1.数据双向绑定及响应式
(1).Object.defineProperty
该方法是Object对象定义属性的方法,可以修改属性默认的特性
/*参数解释:
obj表示目标对象,即属性所在的对像;
key表示属性名;
最后一个参数表示属性的描述符对象
*/
Object.defineProperty(obj, key, {
configurable: false, //属性是否可以被删除或修改,默认为false
enumerable: false, //属性是否可枚举,默认为false
writeable: true, //属性的值能否修改,默认为true
value: 'yayaya', //包含该属性的数据值
get: function() {}, //获取属性的方法
set: function() {} //设置属性的方法
})
(2).观察者模式(发布-订阅)
(3).举例解析双向绑定
<1>.响应式基本原理
例1:
基本思路:渲染视图 <=监听每个data的数据变化 <=遍历data中的每一项 <=获取数据
html中代码:
<!DOCTYPE html>
<html>
<head>
<title>demo</title>
</head>
<body>
<div id="demo">
</body>
</html>
<script type="text/javascript" src="vue2.js"></script>
<script>
//new 一个 Vue 对象,就会将 data 中的数据进行「 响应式」化
var v = new Vue({
el: '#demo',
data: {
name: '123'
},
})
v._data.name = '456';
</script>
vue2.js中代码:
function Vue(options) { //获取数据
this._data = options.data;
observe(this._data);
}
function observe(value) { //遍历data中的每一项
//先不考虑value为数组的复杂情况
if (!value || typeof value !== 'object') return;
Object.keys(value).forEach(function(propertyName) {
defineReactive(value, propertyName, value[propertyName])
})
}
function defineReactive(obj, key, val) { //监听每个data的数据变化
console.log('defineReactive==parameter', obj, key, val)
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
set: function(newVal) {
console.log('newVal', newVal);
if (val == newVal) return;
update(); //如果新修改的值和原来的值不同就重新渲染页面
},
get: function() {
return val;
}
})
}
function update() {
console.log("update view===")
}
输出结果:
小结:从data到视图view的响应式原理主要用到的是Object.definePorperty对数据进行劫持,再更新视图
<2>.依赖收集
1>为什么要有依赖收集
例1:
var globalData = {
name: 'yayaya',
age: '26'
}
var vue1 = new Vue({
data: {
name: globalData.name
}
})
var vue2 = new Vue({
data: {
name: globalData.name
}
})
假如我们修改了globalData中name的值,那么vue1和vue2实例中用到全局name的地方都需要更新,这个时候就需要依赖收集,告诉观察者哪些实例下的数据需要更新.
2>.依赖收集的实现过程
1.订阅者Dep:Dep的主要作用是存放Watcher观察者对象
function Dep() {
//添加观察者watcher
this.subs = [];
this.addSub = function(sub) {
this.subs.push(sub);
console.log("sub==", sub);
}
//通知Watcher更新视图
this.notify = function() {
this.subs.forEach(function(s) {
s.update()
});
}
}
Dep.target = null;
2.观察者Watcher:主要作用是监听数据变化更新视图
function Watcher() {
Dep.target = this; //在new 一个Watcher 对象时将该对象赋值给Dep.target,在get 中会用到
this.update = function() {
console.log('updata view===')
}
}
3.在defineReactivez和Vue中实现依赖收集
function defineReactive(obj, key, val) { //监听data中的数据变化
var dep = new Dep();//实例化一个订阅者
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
set: function(newVal) {
//在set时发送通知给Watcher,重新渲染视图
console.log("set start===");
if (val == newVal) return;
dep.notify(); //如果新修改的值和原来的值不同就重新渲染页面
},
get: function() {
//get时添加依赖
console.log("get start===");
dep.addSub(Dep.target); //把watcher实例添加到依赖中
return val;
}
})
}
function Vue(options) { //获取数据
this._data = options.data;
observe(this._data);
new Watcher();
console.log("this._data.name", this._data.name)
}
function observe(value) { //遍历data中的每一项
//先不考虑value为数组的复杂情况
if (!value || typeof value !== 'object') return;
Object.keys(value).forEach(function(propertyName) {
defineReactive(value, propertyName, value[propertyName])
})
}
4.组件中的代码
var v = new Vue({
el: '#demo',
data: {
name: '123'
},
})
console.log("name is changing")
v._data.name = '456';
输出结果:
小结:
首先vue在observe中注册并调用get,在get中,将Watcher实例通过addSub方法添加到dep的subs数组中,这完成了依赖添加的过程; 当数据变化时,调用Object.defineProperty中的set方法,判断数据是否发生改变,如果改变了,就调用dep中的notify方法通知Watcher,Watcher知道数据变化更新数据.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。