您的位置:首页 > Web前端 > Vue.js

Vue系列二十四:源码解析-数据绑定

2019-05-19 12:54 369 查看

数据劫持与数据绑定
1、数据绑定(model==>View):
(1)、一旦更新了data中的某个属性数据, 所有界面上直接使用或间接使用了此属性的节点都会更新(更新)。
2、数据劫持
(1)、数据劫持是vue中用来实现数据绑定的一种技术。
(2)、基本思想: 通过defineProperty()来监视data中所有属性(任意层次)数据的变化, 一旦变化就去更新界面。
3、四个重要对象
(1)、Observer
  用来对data所有属性数据进行劫持的构造函数。
  给data中所有属性重新定义属性描述(get/set)。
  为data中的每个属性创建对应的dep对象。
(2)、Dep(Depend)
  data中的每个属性(所有层次)都对应一个dep对象。
  创建的时机:
    在初始化define data中各个属性时创建对应的dep对象。
    在data中的某个属性值被设置为新的对象时。
  对象的结构:

{
id, // 每个dep都有一个唯一的id
subs //包含n个对应watcher的数组(subscribes的简写)
}

  subs属性说明:
    当一个watcher被创建时, 内部会将当前watcher对象添加到对应的dep对象的subs中。
    当此data属性的值发生改变时, 所有subs中的watcher都会收到更新的通知, 从而最终更新对应的界面。
(3)、Compile
  用来解析模板页面的对象的构造函数(一个实例)。
  利用compile对象解析模板页面。
  每解析一个表达式(非事件指令)都会创建一个对应的watcher对象, 并建立watcher与dep的关系。
  complie与watcher关系: 一对多的关系。
(4)、Watcher
  模板中每个非事件指令或表达式都对应一个watcher对象。
  监视当前表达式数据的变化。
  创建的时机: 在初始化编译模板时。
  对象的组成:

{
vm,  //vm对象
exp, //对应指令的表达式
cb, //当表达式所对应的数据发生改变的回调函数
value, //表达式当前的值
depIds //表达式中各级属性所对应的dep对象的集合对象
//属性名为dep的id, 属性值为dep
}

(5)、 总结: dep与watcher的关系: 多对多
  一个data中的属性对应对应一个dep, 一个dep中可能包含多个watcher(模板中有几个表达式使用到了属性)。
  模板中一个非事件表达式对应一个watcher, 一个watcher中可能包含多个dep(表达式中包含了几个data属性)。
  数据绑定使用到2个核心技术:
     defineProperty()
    消息订阅与发布
4、双向数据绑定
(1)、双向数据绑定是建立在单向数据绑定(model==>View)的基础之上的。
(2)、双向数据绑定的实现流程:
  在解析v-model指令时, 给当前元素添加input监听
  当input的value发生改变时, 将最新的值赋值给当前表达式所对应的data属性

<body>
<!--
1. 数据绑定
* 初始化显示: 页面(表达式/指令)能从data读取数据显示 (编译/解析)
* 更新显示: 更新data中的属性数据==>页面更新
-->
<div id="test">
<p>{{name}}</p>
<p v-text="name"></p>
<p v-text="wife.name"></p>
<button v-on:click="update">更新</button>
</div>

<!--
Dep
创建时间:初始化的给data的属性进行数据劫持时创建的
个数:与data中的属性一一对应
Dep的结构:
id: 标识
subs:[] n个相关的watcher对象的容器
Watcher
创建时间:初始化的解析大括号表达式与一般指令时创建
个数:与模板中表达式(不包含事件指令)一一对应
Watcher的结构:
this.cb = cb;  // 用于更新界面的回调
this.vm = vm;  // vm
this.exp = exp;  // 对应表达式
this.depIds = {};  // 相关的n个dep的容器对象
this.value = this.get(); // 当前表达式对应的value
Dep与Watcher之间的关系:多对多关系
一个dep中对应多个watcher:同一个属性在模板中多次使用  {{name}} v-text="name"
一个watcher中对应多个dep:多层表达式   {{a.b.c}}
建立关系的方法:data中属性的get()方法
建立时间:初始化的解析模块中的表达式创建watcher对象时
vm.name = 'xxx' 执行流程:
1、data中的name属性值变化
2、调用name的set()方法
3、通知dep
4、通知所有相关的watcher
5、调用cb()回调函数
6、调用updater方法更新界面
-->

<script type="text/javascript" src="js/mvvm/compile.js"></script>
<script type="text/javascript" src="js/mvvm/mvvm.js"></script>
<script type="text/javascript" src="js/mvvm/observer.js"></script>
<script type="text/javascript" src="js/mvvm/watcher.js"></script>
<script type="text/javascript">
new MVVM({
el: '#test',
data: {
name: 'feifei',
wife: {
name: 'feifei2',
age: 28
}
},
methods: {
//更新数据
update () {
this.name = 'xinxin'
}
}
})
</script>
</body>
<body>
<div id="test">
<input type="text" v-model="msg">
<p>{{msg}}</p>
</div>

<script type="text/javascript" src="js/mvvm/compile.js"></script>
<script type="text/javascript" src="js/mvvm/mvvm.js"></script>
<script type="text/javascript" src="js/mvvm/observer.js"></script>
<script type="text/javascript" src="js/mvvm/watcher.js"></script>
<script type="text/javascript">
new MVVM({
el: '#test',
data: {
msg: 'hello'
}
})
</script>
</body>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: