Vue中的数据劫持
Vue中响应式系统的核心: {
数据劫持: 使用Object.defineProperty(this, 属性名,{属性值的配置项} );
依赖收集: 因为上一步数据劫持后, 在解析模板时,替换模板中的变量就需要读取变量的数据,此时就会触发数据的get方法,在get方法中收集所有依赖这个数据的dom节点;
观察者模式; 后续数据发生变化, 就会走set方法, 此时读取以前收集所有依赖该数据的dom节点,进行更新(内部有虚拟dom比对的步骤);
}
<body>
<div id="app">
<p>{{msg}}</p>
<div class="test">
<div>
<p>
<span>{{msg}}</span>
</p>
</div>
</div>
</div>
<script type="text/javascript" src="../js/vue.js"></script>
<script type="text/javascript">
function Vue(options) {
const { data } = options //options是一个对象,因此data用对象形式解构
console.log(data)
/*
打印结果:
Object
foo: "bar"
msg: "123"
__proto__: Object
*/
// 1. 数据劫持
// 取得data的所有键名
const keys = Object.keys(data)
console.log(keys)
/*
打印结果:
(2) ["msg", "foo"]
0: "msg"
1: "foo"
length: 2
__proto__: Array(0)
*/
// var a= 1
// console.log(a) //获取数据触发 get函数
// a = 2 // 更新值时触发 set函数
keys.forEach(key => {
let value = data[key]
Object.defineProperty(this, key, {
// 获取this.key的时候会执行get方法
get() {
console.log(`读取数据${key}的值:`, value)
// 收集依赖:
// 收集一下依赖(每个被使用的数据都是一个依赖项);
// 每个依赖项声明一个对象,对象下记录一个属性: 属性的值是所有使用这个数据的dom节点;
// 例如: msg: { watchers: [dom1, dom2, dom3]} ;
// 这里的'msg'是依赖项, 'watchers'是对象下的属性(表示观察者),
// 'dom1,dom2,dom3'是所有使用msg数据的dom节点;
return value
},
// 更新(重新设置)this.key的时候会执行set方法
set(val) { // val 指更新后的新值
console.log(`设置数据${key}的新值:`, val)
value = val
// 为(数据)依赖项更新值时,需要为所有使用这个数据的dom节点(观察者)更新
// 1个数据演示流程: 可以写死使用这个数据的dom节点的更新操作
document.querySelector('p').innerHTML = val
// 多个数据更新时,不能以写死的方式,一个一个去更新
// 数据更新时,去读取该数据的使用者(使用者 即dom节点,在模板编译的步骤中已经收集好这些dom节点)
// 去更新这些dom节点(更新的细节有虚拟dom的参与)
},
})
})
// 2. 解析模板: 简化为直接操作对应的dom
let msgE1 = (document.querySelector('p').innerHTML = this.msg)
// 3. 更新数据
setTimeout(() => {
this.msg = Math.random
}, 2000)
}
const vm = new Vue({
// vue内部的this都指vue实例
el: '#app',
data: {
msg: '123',
foo: 'bar',
},
})
/*
打印结果:
{msg: "123", foo: "bar"}
(2) ["msg", "foo"]
读取数据msg的值: 123
vue.js:8553 You are running Vue in development mode.
Make sure to turn on production mode when deploying for production.
See more tips at https://vuejs.org/guide/deployment.html
设置数据msg的新值: ƒ random() { [native code] }
*/
</Script>
</body>
版权声明:本文为syl19980202原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。