написать впереди
Поскольку я очень интересуюсь Vue.js, а стек технологий, над которым я обычно работаю, тоже Vue.js, за последние несколько месяцев я потратил некоторое время на изучение и изучение исходного кода Vue.js, подвел итоги и сделал вывод.
Оригинальный адрес статьи:GitHub.com/ответы на….
В процессе обучения в Vue были добавлены китайские аннотации.GitHub.com/ответы на…и аннотации VuexGitHub.com/ответы на…, я надеюсь, что это может быть полезно другим друзьям, которые хотят изучить исходный код.
Там могут быть поняты, где происходит отклонение, пожалуйста, укажите вопрос, указал, что общее обучение и общий прогресс.
keep-alive
keep-alive — это встроенный компонент Vue.js. Он может хранить экземпляры неактивных компонентов в памяти, а не уничтожать их напрямую. Это абстрактный компонент, который не будет отображаться в реальном DOM и не появится в цепочке родительских компонентов.
Он предоставляет свойства включения и исключения, которые позволяют условно кэшировать компоненты.
Конкретное содержание может относиться кОфициальный сайт.
использовать
Применение
<keep-alive>
<component></component>
</keep-alive>
Компоненты компонентов здесь будут кэшироваться.
взять каштан
<keep-alive>
<coma v-if="test"></coma>
<comb v-else="test"></comb>
</keep-alive>
<button @click="test=handleClick">请点击</button>
export default {
data () {
return {
test: true
}
},
methods: {
handleClick () {
this.test = !this.test;
}
}
}
При нажатии кнопки два компонента coma и гребенка будут переключаться, но состояние этих двух компонентов в это время будет кэшироваться.Например, в компонентах coma и гребенке есть входной тег, поэтому содержимое на входе тег не исчезнет из-за переключения компонентов.
props
Компонент поддержания активности предоставляет свойства включения и исключения, позволяющие компоненту выполнять условное кэширование, оба из которых могут быть представлены строкой с разделителями-запятыми, регулярным выражением или массивом.
<keep-alive include="a">
<component></component>
</keep-alive>
Компонент с именем a будет кэширован.
<keep-alive exclude="a">
<component></component>
</keep-alive>
Компонент с именем a не будет кэшироваться.
спасательный крючок
keep-alive предоставляет два лайфхука, активированные и деактивированные.
Поскольку keep-alive сохранит компонент в памяти, а не уничтожит и не создаст его заново, он не будет снова вызывать созданный метод компонента.Вам нужно использовать два лайфхука, активированных и деактивированных, чтобы узнать, активен ли текущий компонент.
Углубленная реализация компонента keep-alive
После разговора об использовании компонента поддержки активности давайте посмотрим, как компонент поддержки активности реализует кэширование компонентов с точки зрения исходного кода?
созданные и уничтоженные хуки
Созданный хук создаст объект кеша, который используется в качестве контейнера кеша для хранения узлов vnode.
created () {
/* 缓存对象 */
this.cache = Object.create(null)
},
Хук уничтожения очищает все экземпляры компонента в кеше, когда компонент уничтожается.
/* destroyed钩子中销毁所有cache中的组件实例 */
destroyed () {
for (const key in this.cache) {
pruneCacheEntry(this.cache[key])
}
},
render
Далее идет функция рендеринга.
render () {
/* 得到slot插槽中的第一个组件 */
const vnode: VNode = getFirstComponentChild(this.$slots.default)
const componentOptions: ?VNodeComponentOptions = vnode && vnode.componentOptions
if (componentOptions) {
// check pattern
/* 获取组件名称,优先获取组件的name字段,否则是组件的tag */
const name: ?string = getComponentName(componentOptions)
/* name不在inlcude中或者在exlude中则直接返回vnode(没有取缓存) */
if (name && (
(this.include && !matches(this.include, name)) ||
(this.exclude && matches(this.exclude, name))
)) {
return vnode
}
const key: ?string = vnode.key == null
// same constructor may get registered as different local components
// so cid alone is not enough (#3269)
? componentOptions.Ctor.cid + (componentOptions.tag ? `::${componentOptions.tag}` : '')
: vnode.key
/* 如果已经做过缓存了则直接从缓存中获取组件实例给vnode,还未缓存过则进行缓存 */
if (this.cache[key]) {
vnode.componentInstance = this.cache[key].componentInstance
} else {
this.cache[key] = vnode
}
/* keepAlive标记位 */
vnode.data.keepAlive = true
}
return vnode
}
Во-первых, получить первый подкомпонент через getFirstComponentChild и получить имя компонента (имя компонента используется напрямую, если есть имя компонента, иначе будет использоваться тег). Далее имя будет сопоставляться с атрибутами включения и исключения.Если совпадение не удалось (указывает, что кэширование не требуется), vnode будет возвращен без каких-либо операций.vnode — это объект типа VNode.Студенты, которые не знают VNode можно сослаться на другую статью автора"VNode узел" .
/* 检测name是否匹配 */
function matches (pattern: string | RegExp, name: string): boolean {
if (typeof pattern === 'string') {
/* 字符串情况,如a,b,c */
return pattern.split(',').indexOf(name) > -1
} else if (isRegExp(pattern)) {
/* 正则 */
return pattern.test(name)
}
/* istanbul ignore next */
return false
}
Функция обнаружения соответствия между атрибутами включения и исключения очень проста.Атрибуты включения и исключения поддерживают такие строки, как «a, b, c», где имена компонентов разделены запятыми и регулярными выражениями. Matchs определяет, соответствует ли текущий компонент этим двум способам.
if (this.cache[key]) {
vnode.componentInstance = this.cache[key].componentInstance
} else {
this.cache[key] = vnode
}
Дальше все очень просто, ищем в this.cache по ключу, если он есть, значит он уже был закэширован ранее, и напрямую перезаписываем componentInstance (экземпляр компонента) закешированного vnode на текущий vnode. В противном случае сохраните vnode в кеше.
Наконец, вернитесь к vnode (при наличии кэша componentInstance vnode был заменен на тот, что находится в кэше).
watch
Часы, чтобы слушать и изменять pruneCache pruneCache эти два свойства, изменять кеш кэша данных вовремя для изменения.
watch: {
/* 监视include以及exclude,在被修改的时候对cache进行修正 */
include (val: string | RegExp) {
pruneCache(this.cache, this._vnode, name => matches(val, name))
},
exclude (val: string | RegExp) {
pruneCache(this.cache, this._vnode, name => !matches(val, name))
}
},
Давайте посмотрим на реализацию pruneCache.
/* 修正cache */
function pruneCache (cache: VNodeCache, current: VNode, filter: Function) {
for (const key in cache) {
/* 取出cache中的vnode */
const cachedNode: ?VNode = cache[key]
if (cachedNode) {
const name: ?string = getComponentName(cachedNode.componentOptions)
/* name不符合filter条件的,同时不是目前渲染的vnode时,销毁vnode对应的组件实例(Vue实例),并从cache中移除 */
if (name && !filter(name)) {
if (cachedNode !== current) {
pruneCacheEntry(cachedNode)
}
cache[key] = null
}
}
}
}
/* 销毁vnode对应的组件实例(Vue实例) */
function pruneCacheEntry (vnode: ?VNode) {
if (vnode) {
vnode.componentInstance.$destroy()
}
}
Просмотрите все элементы в кеше, если они не соответствуют правилам, заданным фильтром, будет выполнено pruneCacheEntry. pruneCacheEntry вызовет метод $destroy экземпляра компонента, чтобы уничтожить компонент.
наконец
Vue.js абстрагирует узлы DOM один за другимУзел VNode, кеш компонента поддержания активности также основан на узле VNode вместо непосредственного хранения структуры DOM. Он кэширует компоненты, соответствующие условиям (pruneCache и pruneCache) в объекте кеша, а затем извлекает узел vnode из объекта кеша и визуализирует его, когда требуется повторный рендеринг.
о
Автор: Ран Мо
Электронная почта: answerhuto@gmail.com или answerhuto@126.com
Github: github.com/answershuto
Знаю почти:ууууууу. chi.com/people/grass-…
Пожалуйста, указывайте источник при перепечатке, спасибо.
Добро пожаловать, чтобы обратить внимание на мой общедоступный номер