最近准备好好看看《Vue的内部运行机制》,学到什么就写什么,先介绍Vue的响应式主要核心API
Object.defineProperty(obj, key, descriptor)
descriptor其中有几个属性:
configurable --》属性可配置性,属性是否可修改或删除,默认false
enumerable --》属性可枚举性,默认false
value --》属性值,默认undefined
writable --》属性可写性,默认false
get --》 get函数set --》set函数
注意:显示声明对象与调用definePropperty函数设置的属性配置不一样
以上两个例子,可以认真看一下
简单实现Observer
首先我们先设定一个更改页面视图的函数
function cb(value) {
document.querySelector('.Test').innerHTML = value;
}
然后我们定义一个 defineReactive ,这个方法通过 Object.defineProperty 来实现对对象的「响应式」化
/**
* 将属性响应式化函数
*
* @param {object} obj 响应式化对象
* @param {} key 响应式对象属性
* @returns {} val 旧属性值
*
*/
function defineReactive(obj, key, val) {
Object.defineProperty(obj, key, {
enumerable: true,
/* 可枚举 */
configurable: true,
/* 可配置修改或删除 */
get: function reactiveGetter() { /* 应该依赖采集 */
return val;
},
set: function reactiveSetter(newVal) {
if (newVal === val) {
return;
}
val = newVal;
cb(val);
}
})
}
我们需要在上面再封装一层 observe 函数 。这个函数传入一个 value(需要「响应式」化的对象),通过遍历所有属性的方式对该对象的每一个属性都通过 defineReactive 处理。
/**
* 将对象所有属性响应式化函数
*
* @param {object} value 响应式化对象
*
*/
function observer(value) {
if (!value || (typeof value !== 'object')) {
return;
}
/* 遍历value中属性定制set和get */
Object.keys(value).forEach(key => defineReactive(value, key, value[key]));
}
然后尝试封装一个简单的 Vue 类
/**
* Vue构造类
*/
class Vue {
constructor(options) {
this._data = options.data;
observer(this._data);
}
}
这样我们只要 new 一个 Vue 对象,就会将 data 中的数据进行「响应式」化。如果我们对 data 的属性进行下面的操作,就会触发 cb 方法更新视图。
var test = new Vue({
data: {
test: 'I am test Vue.'
}
});
页面结构
<body>
<div class="Test">I am test Vue.</div>
</body>
测试结果
在控制台我们尝试修改test对象中的 _data 属性,页面视图也已经被更新
参考文章
本节代码参考《响应式系统的基本原理》