原本vue的相应式应当才是重中之重。然则网上的文章许多许多。在看computed的完成之前。一定照样要把vue的相应式怎样完成好好看一下。或者说二者根本就是一样的东西。这边引荐几篇文章关于vue的相应式。
照样看看官网关于相应式的诠释:
总的来说。vue完成相应式的症结有三个:watcher,dep,observe;
observe:遍历data中的属性。在get,set要领中设置中心数据挟制
dep:每一个属性都有一个本身的dep(音讯定阅起)用于订制该属性上的一切视察者
watcher:视察者,经由过程dep完成对相应属性的监听视察。视察获得效果后,主动触发本身的回调
能够去看看vue2.3的这三部份源码。中心照样有许多优美的设想。比方一个全局唯一的Dep.target,在任何时刻都是唯一的值。以确保一致时间只要一个视察者在定阅。再比方,watcher中也会存下相干的定阅器,完成去重和完成一致个视察者的分组(这里是完成computed的症结),再如。watcher中的id也会唯一。用于异步更新的时刻不同时动身雷同的定阅。细致看看会收成不小。改天我把一切的相应式的代码也整顿一下。
在理解了相应式的情况下。我们来看看computed的完成。最简朴的一个demo以下:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
<div id="app">
<div name="test">{{computeA}}</div>
</div>
</body>
<script src="vue.js"></script>
<script type="text/javascript">
new Vue({
el: '#app',
data: function () {
return {
firstName: 111,
lastName: 222
}
},
computed: {
computeA: function () {
return this.firstName + ' ' + this.lastName
}
},
created(){
setTimeout(
() => {
this.firstName = 333;
},1000
)
}
})
</script>
</html>
我们来从源码的角度看看发生了什么:
在初始化实例竖立相应式的时刻。对options中的computed做了特别处置惩罚:
function initComputed (vm, computed) {
var watchers = vm._computedWatchers = Object.create(null);
for (var key in computed) {
var userDef = computed[key];
var getter = typeof userDef === 'function' ? userDef : userDef.get;
{
if (getter === undefined) {
warn(
("No getter function has been defined for computed property \"" + key + "\"."),
vm
);
getter = noop;
}
}
// create internal watcher for the computed property.
watchers[key] = new Watcher(vm, getter, noop, computedWatcherOptions);//为每一个computed项目订制一个watcher
// component-defined computed properties are already defined on the
// component prototype. We only need to define computed properties defined
// at instantiation here.
if (!(key in vm)) {
defineComputed(vm, key, userDef);
} else {
if (key in vm.$data) {
warn(("The computed property \"" + key + "\" is already defined in data."), vm);
} else if (vm.$options.props && key in vm.$options.props) {
warn(("The computed property \"" + key + "\" is already defined as a prop."), vm);
}
}
function defineComputed (target, key, userDef) {
if (typeof userDef === 'function') {
sharedPropertyDefinition.get = createComputedGetter(key);
sharedPropertyDefinition.set = noop;
} else {
sharedPropertyDefinition.get = userDef.get
? userDef.cache !== false
? createComputedGetter(key)
: userDef.get
: noop;
sharedPropertyDefinition.set = userDef.set
? userDef.set
: noop;
}
Object.defineProperty(target, key, sharedPropertyDefinition);
}
function createComputedGetter (key) {//组织该computed的get函数
return function computedGetter () {
var watcher = this._computedWatchers && this._computedWatchers[key];
if (watcher) {
if (watcher.dirty) {
watcher.evaluate();//网络该watcher的定阅
}
if (Dep.target) {
watcher.depend();//一致为这一组定阅再加上组件re-render的定阅(该定阅担任更新组件)
}
return watcher.value
}
}
}
总的来说。理解了相应式的构建以后。再来看computed的完成照样很直观的。组件初始化的时刻。computed项和data中的离别竖立相应式。data中的数据直接对属性的get,set做数据阻拦。而computed则竖立一个新的watcher,在组件衬着的时刻。先touch一下这个computed的getter函数。将这个watcher定阅起来。这里相当于这个computed的watcher定阅了firstname和lastname。touch完后。Dep.target此时又变成之前谁人用于更新组件的。再经由过程watcher.depend()将这个组一致加上这个定阅。如许一旦firstname和lastname变了。同时会触发两个定阅更新。个中一个就是更新组件。从新re-render的函数。觉得看的还不够细啊