Эта статья представляет собой заметку об изучении исходного кода vue.js, подходящую для студентов, которые имеют определенное представление о реализации vue data response.Я надеюсь, что в тексте есть неточные выражения. затем начните
Совет: Вы увидите в тексте пометку типа (точка знаний: xxx), указывающую на то, что соответствующая позиция исходного кода помечена для удобства чтения всеми
Во-первых, посмотрите на исходный код реализации вычисляемого
// initState会在new Vue()时执行
export function initState (vm: Component) {
/*
other
*/
// 如果我们定义了comouted属性则执行initComputed
if (opts.computed) initComputed(vm, opts.computed)
/*
other
*/
}
Найдите определение initComputed в том же файле.
function initComputed (vm, computed) {
// 往组件实例上添加一个_computedWatchers属性,保存所有的computed watcher
const watchers = vm._computedWatchers = Object.create(null)
// 对所有的computed属性遍历处理
for (const key in computed) {
// 将我们定义的computed属性值用userDef保存
const userDef = computed[key]
// 我们在定义computed时可以是一个函数,也可以是一个对象{get:function(){}, set:function(){}}
const getter = typeof userDef === 'function' ? userDef : userDef.get
// 数据响应过程中的watcher(注意第二个参数是我们刚才拿到的getter,记住了)
watchers[key] = new Watcher(
vm,
getter || noop, // 注意这里,注意这里,注意这里,(****知识点getter)
noop,
computedWatcherOptions
)
if (!(key in vm)) {
defineComputed(vm, key, userDef)
}
}
}
Далее мы еще находим реализацию defineComputed в этом файле
export function defineComputed (target, key, userDef) {
/* other */
// 这里我对源码进行了简化
// sharedPropertyDefinition是一个全局对象
// 拿到一个get函数
sharedPropertyDefinition.get = createComputedGetter(key)
/* other */
// 这个函数的主要功能是computed属性的get进行了重写
Object.defineProperty(target, key, sharedPropertyDefinition)
}
Или продолжайте видеть createComputedGetterочень важно, очень важно, очень важно
function createComputedGetter (key) {
// 返回一个函数,也就是我们在上一个函数中那个get函数
return function computedGetter () {
// 拿到我们在initComputed函数中添加到vm上面的_computedWatchers
const watcher = this._computedWatchers && this._computedWatchers[key]
// 如果我们有定义computed属性,watcher必定存在
if (watcher) {
// 注意,注意,注意,只要在模板中使用了这个computed属性,之后每次页面更新就是循环知识点1到知识点5这个过程
// 第二节主要就是在讲这一块,在理解下面的步骤时可以对照的看一下
if (watcher.dirty) { // ****标记:知识点1
watcher.evaluate() // ****标记:知识点2
}
if (Dep.target) { // ****标记:知识点3
watcher.depend() // ****标记:知识点4
}
return watcher.value // ****标记:知识点5
}
}
}
Во-вторых, вычисленный ответ свойства
1. Происхождение всего
или в этом файле мы можем найти этот объект
const computedWatcherOptions = { lazy: true }
При возврате к новому Watcher в функции initComputed
watchers[key] = new Watcher(
vm,
getter || noop,
noop,
computedWatcherOptions // 看这里,看这里,看这里(传入{lazy: true})
)
2. Начало всего
Наблюдательисходный код
constructor (vm, expOrFn, cb, options, isRenderWatcher) {
this.vm = vm
if (isRenderWatcher) {
vm._watcher = this
}
vm._watchers.push(this)
/* ... */
if (options) {
this.lazy = !!options.lazy // this.lazy = true
}
this.getter = expOrFn
this.dirty = this.lazy // 初始化this.dirty = true
/* ... */
// 注意了,注意了,注意了
// new时this.lazy为true所以this.value = 'undefined'
this.value = this.lazy ? undefined : this.get()
}
Основной процесс находится в функции createComputedGetter
- существует
new Watcher
Времяthis.dirty = this.lazy
такПункт знаний 1: watcher.dirty = true - тогдаПункт знаний 2:
watcher.evaluate()
будуthis.dirty = false
Тогда он будет выполнять наблюдательthis.get()
В конце концов, это реализацияПолучатель очков знаний:this.getter()
- ПродолжатьПункт знаний 3:
Dep.target
всегда правда - СмотретьПункт знаний 4Собрать зависимости
- наконецЗнания пункт 5получить вычисленное значение
Вот и все, что касается реализации Watcher.Эта статья основана на общем понимании класса Wathcer. Если у вас есть какие-либо потребности, вы можете оставить сообщение, и я подробно разберу процесс реализации ответа данных позже.В Интернете, кажется, много статей по теме.
3. Начать шоу
new Vue({
data(){
return {
dataA: 'a',
dataB: 'b'
}
},
template: '<div>{{computedA}}-{{dataB}}</div>',
computed: {
computedA() {
return 'computed ' + this.dataA
}
},
method: {
changeA(){
this.dataA = 'change dataA'
},
changeB(){
this.dataA = 'change dataB'
}
}
})
Посмотрите на функцию createComputedGetter
- 1, в шаблоне при первом отображении страницы
{{computedA}}
воплощать в жизньcomputedA.get()
Перейти к функции createComputedGetter - 2,Пункт знаний 1:
this.dirty = true
- 3,Пункт знаний 2:
watcher.evaluate()
выполнить, будетthis.dirty = false
, наблюдатель внутренне выполняетПолучатель очков знаний:this.getter()
this.getter = computedA = function(){
return 'computed' + this.dataA // 看这里,看这里,看这里,知识点update
}
Естьwacher.valueравныйcomputed a
- 4,
watcher.depend()
Повторный сбор зависимостей - 5. Верните wacher.value и отобразите его на странице
<div>computed a-b</div>
- 6, мы звоним
this.changA()
Изменить dataA, вызвать dataA вdep.notify()
, выполнит все объекты-наблюдатели dataAwathcer.update()
,потому чтоЛенивый наблюдателя, которому принадлежит вычисление, всегда истинен,Пункт знаний 1: this.dirty = true - 7, поскольку dataA изменился, инициируйте повторную визуализацию страницы, повторную визуализацию шаблона, шаблона в
{{computedA}}
позвони сноваcomputedA.get()
, петля шаг 1
Три, вычисляемый кэш атрибутов
Благодаря процессу вычисляемого ответа в Разделе 3, Разделе 3 мы знаем, что вычисленный A будет отслеживать изменения в dataA, чтобы изменитьПункт знаний 1: this.dirty = trueнаконец казненПолучатель очков знаний
Предположения:
- мы сейчас выполняем
this.changeB()
, изменил значение dataB, - Все объекты-наблюдатели dataB будут выполнены
wathcer.update()
, - Поскольку dataB изменился, запустите повторную визуализацию страницы, повторную визуализацию шаблона, шаблона в
{{computedA}}
позвони сноваcomputedA.get()
Перейти к функции createComputedGetter. - потому чтоcomputedAОн не отслеживает изменения dataB, поэтому не будет выполняться.computedAиз
watcher.update()
Пункт знаний 1: this.dirty = false,не будет выполняться в концеТочка знаний: геттер - Вернитесь прямо к последнему разуТочка знаний: геттеррезультат
return watcher.value
Суммировать
Поскольку в этой статье в основном говорится о знании вычисляемых данных, в ней нет подробного описания знания ответа данных, что может показаться немного запутанным, а процесс реализации ответа данных vue будет подробно проанализирован позже.