Измените исходный код vue для реализации кеша динамической маршрутизации.
динамическая маршрутизация
то есть если у вас естьИнвентаризациямаршрутизация, но вы хотите передать разныеIDзагрузитьCheckInputInfoЭтот компонент, если используетсяparamsметод, вам нужно толькоpathзадняя конфигурация/:taskIdможет быть достигнутCheckInputInfo/1а такжеCheckInputInfo/2Такой маршрут также можно пройти черезthis.$route.params.taskIdчтобы получить текущий маршрутtaskId.
{
path: 'CheckInputInfo/:taskId',
meta: {
title: '盘点录入单'
},
name: 'CheckInputInfo',
component: () => import('@/view/Check/CheckInputInfo.vue')
}
Точно так же вы также можете использоватьqueryметод, вам нужно толькоpathзадняя конфигурация:taskIdможет быть достигнутCheckInputInfo?taskId=1а такжеCheckInputInfo?taskId=2Такой маршрут также можно пройти черезthis.$route.query.taskIdчтобы получить текущий маршрутtaskId.
{
path: 'CheckInputInfo:taskId',
meta: {
title: '盘点录入单'
},
name: 'CheckInputInfo',
component: () => import('@/view/Check/CheckInputInfo.vue')
}
vue-routerпо конфигурацииparamsа такжеqueryдля достижения динамической маршрутизации и может бытьэто.$route.xxчтобы получить текущийparamsилиquery, устраняя необходимость прямого манипулирования или обработкиwindow.location, это довольно удобно.
интерпретация: без использованияkeep-aliveВ случае, каждый раз, когда мы загружаем маршрут, он будет перезагружатьсяrenderТекущий маршрут смонтированcomponent, но если два маршрута являются динамическими маршрутами, настроенными одним и тем же компонентом маршрутизации,vueСоздан для производительности и не подлежит переработкеrender.
Это явно не соответствует нашим ожиданиям, так как же обеспечить полный жизненный цикл при динамической маршрутизации? ответkeep-alive.
keep-alive
keep-alive решает самую критическую проблему производительности SPA за счет кэширования Vnodes. Ниже я проанализирую следующие шаги:
1. Проблема, заключающаяся в том, что маршрутизация вызывает повторный рендеринг компонента маршрутизации.
1. Режим без кэша:
<router-view></router-view>
Каждый раз, когда вы переключаетесьrender, выполнять весь жизненный цикл, при каждом переключении перезапускатьrender, повторный запрос, обязательно не соответствует требованию.
2. Режим кэша:
<keep-alive>
<router-view></router-view>
</keep-alive>
Просто ввод текущего маршрута в первый разrender, переключение туда и обратно не приведет к повторному выполнению жизненного цикла, и его можно кэшироватьrouter-viewДанные.
2. Проблема кэширования данных просмотра маршрутизатора
keep-aliveиспользоватьrenderфункция для созданияVnode, разvue v2.5.10изkeep-alive.jsизrender():
render () {
const slot = this.$slots.default
const vnode: VNode = getFirstComponentChild(slot)
const componentOptions: ?VNodeComponentOptions = vnode && vnode.componentOptions
if (componentOptions) {
// check pattern
const name: ?string = getComponentName(componentOptions)
const { include, exclude } = this
if (
// not included
(include && (!name || !matches(include, name))) ||
// excluded
(exclude && name && matches(exclude, name))
) {
return vnode
}
const { cache, keys } = this
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
if (cache[key]) {
vnode.componentInstance = cache[key].componentInstance
// make current key freshest
remove(keys, key)
keys.push(key)
} else {
cache[key] = vnode
keys.push(key)
// prune oldest entry
if (this.max && keys.length > parseInt(this.max)) {
pruneCacheEntry(cache, keys[0], keys, this._vnode)
}
}
vnode.data.keepAlive = true
}
return vnode || (slot && slot[0])
}
}
существуетrenderполучаетсяVnode,подобноcache[key]существует, то:
vnode.componentInstance = cache[key].componentInstance
В противном случае будетVnodeСохранить какcacheвнутри:
cache[key] = vnode
Тогда используйтеkeep-alive, мы можем сохранить каждыйroute-viewДанные.
Проблема кэширования динамического маршрута и как ее реализовать
Во-первых, появление багов
Я не знал этого сначалаbugДа, через феномен тоже реверс, а тут исходный код решает эту проблему, так что начнем с феномена:
Удельная производительность кэша динамической маршрутизации следующая:
- Маршруты, настроенные с помощью динамической маршрутизации, могут кэшировать только одну копию данных.
- keep-aliveТолько первый динамический маршрут будет иметь полный жизненный цикл, а последующие маршруты будут запускать толькоactivedа такжеdeactivatedэти два крючка.
- После изменения определенных данных маршрутизации динамического маршрута все данные динамической маршрутизации этого же маршрута будут обновлены синхронно.
Наше ожидание на самом деле используетkeep-aliveВ случае динамическая маршрутизация может иметь нединамическую производительность, т. е. иметьполный жизненный цикл,соответствующий кэш данных.
2. Найдите ключ к проблеме
Началоkeep-aliveОбнаружение исходного кода, на самом деле проблема возникает на этом этапе:
if (
// not included
(include && (!name || !matches(include, name))) ||
// excluded
(exclude && name && matches(exclude, name))
) {
return vnode
}
Из представленного выше представления можно найти, чтоrouter-viewНа самом деле он уже закеширован, а динамический маршрутrouter-viewвсе прошлоifРешение возвращеноVnode. Тогда посмотри на это сноваnameчто:
function getComponentName (opts: ?VNodeComponentOptions): ?string {
return opts && (opts.Ctor.options.name || opts.tag)
}
const name: ?string = getComponentName(componentOptions)
здесьoptsНа самом деле он соответствуетVueComponentиз$опции,а такжеэто.$options.nameэто не соответствует.vueобъявлено в файлеnameАтрибуты. Потом подумал, не зря это требуется предусмотреть при настройке маршрутизацииnameСвойство должно быть таким же, как и внутри компонента.nameЗначение остается прежним.
Видя это, проблема была решена, потому что компоненты конфигурации динамической маршрутизации одинаковы,getComponentNameвозвращает одно и то же каждый разname,Потомrender()кэшировать то же самоеVnode, и кэшируется только одна копия. В этом случае, пока правильный кешVnodeи вынутьVnode, в случае динамической маршрутизации,keep-aliveДо сих пор нормально работает.
Изменить исходный код Vue
Вышеупомянутое происходит из-за проблемы с именами компонентов динамической маршрутизации, если кешированныйkeyРазве недостаточно сделать его единственным?
Итак, вrouter-viewНастройте ключ, как указано выше, и ключ получит путь деления, который всегда уникален:
<keep-alive :include="cacheList">
<router-view :key="$route.path"></router-view>
</keep-alive>
затем изменитьkeep-alive.jsИсходный код выглядит следующим образом (поскольку отношения между праздниками не детализированы, просто вставьте исходный код напрямую, человек, который его реализовал, это я, и первый, эта ошибка на github все еще открыта):
/*
*@flow
*modify by LK 20190624
*/
import { isRegExp, remove } from 'shared/util'
import { getFirstComponentChild } from 'core/vdom/helpers/index'
type VNodeCache = { [key: string]: ?VNode };
function getComponentName (opts: ?VNodeComponentOptions): ?string {
return opts && (opts.Ctor.options.name || opts.tag)
}
function matches (pattern: string | RegExp | Array<string>, key: string | Number): boolean {
if (Array.isArray(pattern)) {
return pattern.indexOf(key) > -1
} else if (typeof pattern === 'string') {
return pattern.split(',').indexOf(key) > -1
} else if (isRegExp(pattern)) {
return pattern.test(key)
}
/* istanbul ignore next */
return false
}
function pruneCache (keepAliveInstance: any, filter: Function) {
const { cache, keys, _vnode } = keepAliveInstance
for (const key in cache) {
const cachedNode: ?VNode = cache[key]
if (cachedNode) {
// const name: ?string = getComponentName(cachedNode.componentOptions)
if (key && !filter(key)) {
pruneCacheEntry(cache, key, keys, _vnode)
}
}
}
}
function pruneCacheEntry (
cache: VNodeCache,
key: string,
keys: Array<string>,
current?: VNode
) {
const cached = cache[key]
if (cached && (!current || cached.tag !== current.tag)) {
cached.componentInstance.$destroy()
}
cache[key] = null
remove(keys, key)
}
const patternTypes: Array<Function> = [String, RegExp, Array]
export default {
name: 'keep-alive',
abstract: true,
props: {
include: patternTypes,
exclude: patternTypes,
max: [String, Number]
},
created () {
this.cache = Object.create(null)
this.keys = []
},
destroyed () {
for (const key in this.cache) {
pruneCacheEntry(this.cache, key, this.keys)
}
},
mounted () {
this.$watch('include', val => {
pruneCache(this, key => matches(val, key))
})
this.$watch('exclude', val => {
pruneCache(this, key => !matches(val, key))
})
},
render () {
const slot = this.$slots.default
const vnode: VNode = getFirstComponentChild(slot)
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
const componentOptions: ?VNodeComponentOptions = vnode && vnode.componentOptions
if (componentOptions) {
// check pattern
const name: ?string = getComponentName(componentOptions)
const { include, exclude } = this
if (
// not included
(include && (!key || !matches(include, key))) ||
// excluded
(exclude && key && matches(exclude, key))
) {
return vnode
}
const { cache, keys } = this
if (cache[key]) {
vnode.componentInstance = cache[key].componentInstance
// make current key freshest
remove(keys, key)
keys.push(key)
} else {
cache[key] = vnode
keys.push(key)
// prune oldest entry
if (this.max && keys.length > parseInt(this.max)) {
pruneCacheEntry(cache, keys[0], keys, this._vnode)
}
}
vnode.data.keepAlive = true
}
return vnode || (slot && slot[0])
}
}
Как интегрировать
Из-за праздника, чтобы водить машину, позвольте мне кратко рассказать об этом.Если у вас есть какие-либо вопросы, пожалуйста, прокомментируйте прямо ниже:
Сначала измените package.json:
npm installникогда не скачивайтеvue,Исправлятьpackjson.jsизменить на местныйvue: "vue": "файл:./vue2.5.0/"
"dependencies": {
"axios": "^0.18.0",
"clipboard": "^2.0.0",
"codemirror": "^5.38.0",
"countup": "^1.8.2",
"cropperjs": "^1.2.2",
"dayjs": "^1.7.7",
"echarts": "^4.0.4",
"html2canvas": "^1.0.0-alpha.12",
"iview": "^3.2.2",
"iview-area": "^1.5.17",
"js-cookie": "^2.2.0",
"simplemde": "^1.11.2",
"sortablejs": "^1.7.0",
"tree-table-vue": "^1.1.0",
"v-org-tree": "^1.0.6",
"vue": "file:./vue2.5.0/",
"vue-i18n": "^7.8.0",
"vue-router": "^3.0.1",
"vuedraggable": "^2.16.0",
"vuex": "^3.0.1",
"wangeditor": "^3.1.1",
"xlsx": "^0.13.3"
},
2. Измените все локальныеimport vueДля локальных файлов:
// import Vue from 'vue'
import Vue from '../vue-2.5.10/src/core/index'