双向绑定实现($on $emit)

关于父子之间数据更新同步, 如果单向绑定, 子修改了,父却没有修改, 这种一般不符合规范

正常更新数据的套路是:
1. 子通知父更新数据
2. 子自动刷新获取最新数据
- 为实现这个,就会有发布订阅模式
1.特点: 一对多, 一个动作产生,引发一连串行为. 对应到数据结构是:
{失恋:[cry,eat,shopping]}
2.如果失恋产生, 则会触发cry,eat shopping一系列动作执行. 这个思路就是发布订阅模式. 对应到vue,就是子去通知父亲刷新数据后子同步数据. // 发布 emit 订阅 on {}
function Girl() {
this._events = {}
}
Girl.prototype.on = function (eventName,callback) { if(this._events[eventName]){ // 不是第一次
this._events[eventName].push(callback); // {失恋:[cry,eat,shopping]}
}else{
this._events[eventName] = [callback] //{失恋:[cry]}
}
};
Girl.prototype.emit = function (eventName,...args) { //[我,你,他]
// [].slice.call(arguments,1);
// Array.from(arguments).slice(1);
if(this._events[eventName]){
this._events[eventName].forEach(cb=>cb(...args));
}
};
let girl = new Girl();
let girl1 = new Girl();
let cry = (who) =>{console.log(who+'哭');};
let shopping = (who) =>{console.log(who+'购物');};
let eat = (who) =>{console.log(who+'吃');};
girl.on('失恋',cry); // {失恋:[cry]}
girl.on('失恋',eat); // {失恋:[cry,eat]}
girl.on('失恋',shopping); // {失恋:[cry,eat,shopping]}
girl1.emit('失恋');
本文思路:

- 先实现子获取父数据(单向绑定)
- 然后实现双向数据更新($on $emit)
1.给父亲写改money的方法(但不要注册到父上)
2.将父改money方法传给子,$on
3.子一旦想改数据,即会发射信息$emit给父,提示父该执行动作了. - 双向更新简化: sync
1.直接实现
2.语法糖简化

<div id="app">
money:{{money}} <br>
<awsome :childmoney="money"></awsome>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
let vm = new Vue({
el: "#app",
data: {
money: 700,
},
components: {
awsome: {
data: function () {
return {count: 0}
},
props:['childmoney'],
template: "<button @click='childmoney++'>childmoney: {{childmoney}}</button>"
}
}
})
</script>
- 双向绑定3步走
// 1. 父亲定义更改自己money事件
methods: {getMoney() {this.$emit('childthings', 1400);}
// 2. 父将事件传给子,
childthings.$on('childthings',things)
// 3, 子在这里(相当于)触发父方法在父上执行
awsome.$emit('childthings', 1400);
<div id="app">
money:{{money}} <br>
<!--2,父将事件传给子,
childthings.$on('childthings',things)-->
<awsome :childmoney="money" @childthings="things"></awsome>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script> //1. 单向数据更新不应该发生
//2. 子想改变数据,应该通知父先改变, 父改变后,子自动刷新
let vm = new Vue({
el: "#app",
data: {
money: 700,
},
methods: {
things(val) { // 1.父亲定义更改自己money事件
alert(val);
this.money = val;
}
},
components: {
awsome: {
data: function () {
return {count: 0}
},
props: ['childmoney'],
methods: {
getMoney() {
this.$emit('childthings', 1400); // 3, 子在这里(相当于)触发父方法在父上执行(函数名+参数)
}
},
template: "<button @click='getMoney'>childmoney: {{childmoney}}</button>"
}
}
})
</script>
- 双向绑定的简写: sync

<div id="app">
money:{{money}} <br>
<h1>sync双向绑定1-1:</h1>
<awsome :childmoney="money" @update:childmoeny="val=>this.money=val"></awsome>
<h1>sync双向绑定1-2:</h1>
<awsome :childmoney="money" @update:childmoeny="things"></awsome>
<h1>sync双向绑定1-3: 简化写法</h1>
<awsome :childmoney.sync="money"></awsome>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
let vm = new Vue({
el: "#app",
data: {
money: 700,
},
methods: {
things(val) {
alert(val);
this.money = val;
}
},
components: {
awsome: {
data: function () {
return {count: 0}
},
props: ['childmoney'],
methods: {
getMoney() {
this.$emit('update:childmoney', 1400); // 这里需要改成和上面父给子注册方法时相同的名字
}
},
template: "<button @click='getMoney'>childmoney: {{childmoney}}</button>"
}
}
})
</script>
- 最简单的写法

<div id="app">
{{money}}
<awsome :childmoney.sync="money"></awsome>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
let vm = new Vue({
el: "#app",
data: {
money: 700,
},
components: {
awsome: {
props:['childmoney'],
/* methods:{
getMoney(){
this.$emit('update:childmoney',1400);
}
},*/
template: `<button @click="()=>this.$emit('update:childmoney',1400)">{{childmoney}}</button>`
}
}
})
</script>

模态框案例

参考

  • 1.父传数据给子, 父将flag=true传给子,实现点按钮弹出
  • 2.子远程替父调用方法,修改flag=false,实现点关闭按钮关闭.
<div id="app">
<button @click="flag=true">模态框</button>
<!--<motal :childflag="flag" @close="()=>flag=false"></motal>-->
<motal :childflag="flag" @childthings="things"></motal>
</div> <script src="node_modules/vue/dist/vue.js"></script>
<script>
let vm = new Vue({
el: "#app",
data: {
flag: false,
},
methods: {
things(val) {
this.flag = val;
}
},
components: {
motal: {
props: ['childflag'],
methods: {
shutdown() {
this.$emit('childthings');
}
},
template: `
<div class="mask" v-show="childflag">
<div class="dialog">
<button @click="shutdown">关闭</button>
</div>
</div>`,
},
}
})
</script>

较为抽象的代码

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.mask {
width: 100%;
height: 100%;
position: fixed;
background: rgba(0, 0, 0, .35);
top: 0;
left: 0
} .dialog {
width: 400px;
height: 150px;
background: #fff;
position: fixed;
top: 50%;
left: 50%;
transform: translate3d(-50%, -50%, 0)
}
</style>
</head>
<body>
<div id="app">
<button @click="flag=true">弹</button>
<!--如果show的值是true则显示 如果是false则隐藏 @close对应的函数是点击关闭按钮时触发的函数-->
<modal :childflag="flag" @childthings="()=>flag=false"></modal>
</div> <template id="dialog">
<div class="mask" v-show="childflag">
<div class="dialog">
<button @click="shutdown">关闭</button>
</div>
</div>
</template>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
let modal = { //接收了父组件的属性
props: ['childflag'],
template: '#dialog',
methods: {
shutdown() {
this.$emit('childthings');
}
}
}; let vm = new Vue({
el: '#app',
data: {flag: false},
components: {
modal // 名字不能叫dialog 原生中已经占用了这个名字
}
})
</script>
</body>
</html>

mounted里refs实现父类触发子类的方法.

加载中...页在加载完成后会被销毁, 谁来触发他销毁? 一般是父类. 映射到vue就是父类触发子类的方法.

1.给要获取子组件添加ref标识
2.mounted阶段调用,如this.$refs.load.hide() 注: ref放在组件上获取的是vue实例(VueComponent), 而非dom元素, 但可以通过实例在全局调用子元素的方法. <div id="app">
<loading ref="load"></loading>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
let vm = new Vue({
el: "#app",
data: {
msg: 'hi'
},
mounted() {
console.log(this.$refs.load);
this.$refs.load.hide(); //获取到的是vm实例,但可以操控里面的方法.
},
components: {
loading: {
methods: {
hide() {
console.log('hide func被触发');
}
},
template: "<h1>sucess!</h1>",
}
}
})
</script>
- 学习知识一贯的做法是,先理解骨干使用套路, 然后结合栗子来揣摩知识点的设计理念(用来解决啥问题)

下面是ref一个栗子页面loading.

<div id="app">
<loading ref="load"></loading>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
// 父组件调用子组件的方法
let loading = {
data(){
return {flag:true}
},
template:'<div v-show="flag">疯狂加载中。。。</div>',
methods:{
hide(){
this.flag = false;
}
}
};
let vm = new Vue({
el:'#app',
mounted(){ // ref 如果放在组件上 获取的是组件的实例 并不是组件的dom元素
// this.$refs.load.hide()
// this.$refs.load.$el.style.background = 'red'
},
data:{},
components:{
loading
}
})
</script>

[vue]vue双向绑定$on $emit sync-模态框的更多相关文章

  1. 揭密 Vue 的双向绑定

    Vue 中需要输入什么内容的时候,自然会想到使用 <input v-model="xxx" /> 的方式来实现双向绑定.下面是一个最简单的示例 剖析Vue原理& ...

  2. 撸一个vue的双向绑定

    1.前言 说起双向绑定可能大家都会说:Vue内部通过Object.defineProperty方法属性拦截的方式,把data对象里每个数据的读写转化成getter/setter,当数据变化时通知视图更 ...

  3. 浅谈Vue之双向绑定

    VUE实现双向数据绑定的原理就是利用了 Object.defineProperty() 这个方法重新定义了对象获取属性值(get)和设置属性值(set)的操作来实现的.那么Object.defineP ...

  4. vue数据双向绑定

    Vue的双向绑定是通过数据劫持结合发布-订阅者模式实现的,即通过Object.defineProperty监听各个属性的setter,然后通知订阅者属性发生变化,触发相应的回调. 整个过程分为以下几步 ...

  5. 【学习笔记】剖析MVVM框架,简单实现Vue数据双向绑定

    前言: 学习前端也有半年多了,个人的学习欲望还比较强烈,很喜欢那种新知识在自己的演练下一点点实现的过程.最近一直在学vue框架,像网上大佬说的,入门容易深究难.不管是跟着开发文档学还是视频教程,按步骤 ...

  6. MVVM以及vue的双向绑定

    原文:https://www.cnblogs.com/onepixel/p/6034307.html MVVM 是Model-View-ViewModel 的缩写,它是一种基于前端开发的架构模式,其核 ...

  7. 深入理解Proxy 及 使用Proxy实现vue数据双向绑定

    阅读目录 1.什么是Proxy?它的作用是? 2.get(target, propKey, receiver) 3.set(target, propKey, value, receiver) 4.ha ...

  8. vue事件双向绑定

    事件 案例: vue的事件绑定原理:改变图片的背景颜色问题来实现这个框架的使用方法, new Vue({ el:"", data:{}, methord:{}, computed: ...

  9. vue之双向绑定

    Vue的一大核心是双向绑定,在2.0中采用数据劫持,用Object.defineProperty实现,但作者已声明在3.0中会采用proxy实现   Object.defineProperty是什么? ...

随机推荐

  1. LESS CSS 框架简介与使用

    简介 CSS(层叠样式表)是一门历史悠久的标记性语言,同 HTML 一道,被广泛应用于万维网(World Wide Web)中.HTML 主要负责文档结构的定义,CSS 负责文档表现形式或样式的定义. ...

  2. spring mvc 跨域请求处理——spring 4.2 以上

    Controller method CORS configuration You can add to your @RequestMapping annotated handler method a  ...

  3. 五、K3 WISE 开发插件《K3 Wise 群发短信配置开发(一)之短信平台配置》

    开发环境:K/3 Wise 13.0 目录 一.创建短信数据库 二.配置短信接口 三.设置帐套关键字 四.查询短信余额 一.创建短信数据库 打开帐套管理: 账号默认为Admin,密码不填: 菜单“系统 ...

  4. Intellij 部署项目java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderListener

    报错信息: org.apache.catalina.core.StandardContext.listenerStart Error configuring application listener ...

  5. C#串口介绍以及简单串口通信程序设计实现

    C#串口介绍以及简单串口通信程序设计实现 周末,没事干,写个简单的串口通信工具,也算是本周末曾来过,废话不多,直接到主题 串口介绍 串行接口简称串口,也称串行通信接口或串行通讯接口(通常指COM接口) ...

  6. android 线程间的通信

    (转自:http://www.cnblogs.com/allin/archive/2010/05/19/1738800.html) andriod提供了 Handler 和 Looper 来满足线程间 ...

  7. 整理一系列优秀的Android开发源码

    转:http://www.cnblogs.com/feifei1010/archive/2012/09/12/2681527.html 游戏类: 一.15个Android游戏源码(是以andengin ...

  8. Word 2010 插入其他文件的方法

    1. 2.

  9. 题目1454:Piggy-Bank(完全背包问题)

    题目链接:http://ac.jobdu.com/problem.php?pid=1454 详解链接:https://github.com/zpfbuaa/JobduInCPlusPlus 参考代码: ...

  10. Dockerfile创建镜像

    Dockerfile是一个文本格式的配置文件,用户可以使用Dockerfile来快速创建自定义的镜像. Dockerfile由一行行命令语句组成,并且支持易#开头的注释行. 一般而言Dockerfil ...