Vue의 캐시 페이지 관리 방법
<keep-alive>
<router-view />
</keep-alive>
Vue에 내장된 본문 기본 모든 페이지는keep-alive
문제 해결
업무 논리가 복잡해지면서 루트 창고도 점점 높아지고 이론적으로 사용자는 무한한 루트를 진행할 수 있다. 불가피하게 우리는 메모리에 캐시된 페이지 데이터를 관리해야 한다. 페이지 데이터는 두 부분, Vue 실례와 대응하는 Vnode를 포함한다.Vue 원본 코드의 src/core/components/keep-alive를 보십시오.js 캐시에 대한 정의
this.cache = Object.create(null) // vnode cache[key] => Vnode
this.keys = [] // vnode key
캐시 후에 Vnode를 다시 사용하지 않고 위에 마운트된 Vue 인스턴스만 사용합니다.
if (cache[key]) {
vnode.componentInstance = cache[key].componentInstance // vnode vue vnode
// make current key freshest
remove(keys, key)
keys.push(key)
}
왜 안 써요? 버그가 있기 때문에 최초의 버전에서는 캐시를 직접 사용하는 Vnode가 확실합니다.src/core/components/keep-alive에서 나왔습니다.js init version
export default {
created () {
this.cache = Object.create(null)
},
render () {
const childNode = this.$slots.default[0]
const cid = childNode.componentOptions.Ctor.cid
if (this.cache[cid]) {
const child = childNode.child = this.cache[cid].child // vnode
childNode.elm = this.$el = child.$el
} else {
this.cache[cid] = childNode
}
childNode.data.keepAlive = true
return childNode
},
beforeDestroy () {
for (const key in this.cache) {
this.cache[key].child.$destroy()
}
}
}
우리가 관리해야 할 것은 사실은cache와keys입니다.keep-alive는 세 가지 파라미터를 제공하여 캐시를 동적으로 관리합니다.
include - 。
exclude - 。
max - 。
그것들의 역할은 매우 간단하고 원본 코드도 간단하고 읽기 쉽다.따라서 우리가 이 캐시를 관리하고자 할 때, 간단한 방안은 이 세 가지 파라미터를 조작하고, include와 exclude를 수정해서 캐시를 하거나 일부 캐시를 제거하는 것입니다. 그러나 주의해야 할 것은 이 세 가지 파라미터가 일치하는 구성 요소의name입니다.
src/core/components/keep-alive에서 나왔습니다.js
const name: ?string = getComponentName(componentOptions)
따라서 캐시를 지우는 것은 어떤 구성 요소의 모든 실례를 무차별적으로 지우는 것이다. 이것은 분명히 우리의 요구를 만족시키지 못한다.max의 논리는 최대치를 초과할 때 창고 밑의 캐시를 지우고,
src/core/components/keep-alive에서 나왔습니다.js:
if (this.max && keys.length > parseInt(this.max)) {
pruneCacheEntry(cache, keys[0], keys, this._vnode)
}
우리는 문제를 해결해야 한다. 첫째, 정부가 제공한 API가 통하지 않는다. 우리는 스스로 올 수밖에 없다. 우리가 필요로 하는 것은 두 개의 하위 문제를 해결하는 것이다.1. 폐기 방법
먼저 어떻게 없애는지 보십시오. 실례를 없애려면 직접this.$로destroy (), 이렇게 하면 됩니까, 안 됩니다. 이렇게 캐시 캐시와 keys에 원래의 vnode와 key가 보존되어 있습니다. 다시 방문할 때 문제가 발생합니다. vnode는 계속 저장되어 있습니다. 그러나 이 캐시의 실례는 삭제되었습니다. 이때 vue의 업데이트 과정에서 vue 실례를 다시 만듭니다. 즉, 어떤keep-alive 페이지가this를 한 번 호출한 적이 있다면. $destroy (), 하지만 캐시 그룹을 정리하지 않았습니다. 이 페이지가 다시 렌더링되면 반드시 실례를 다시 만들 것입니다. 물론 모든 생명주기를 다시 걸을 것입니다.현상은 결국 이 페이지가 캐시되지 않은 것과 같다.
this.$destroy(); // keep-alive
따라서 캐시를 제거하려면 캐시 캐시와 keys를 동시에 제거해야 합니다. 다음은 캐시를 동시에 제거하는 $keepaliveDestroy 방법을 정의합니다.
const dtmp = Vue.prototype.$destroy;
const f = function() {
if (this.$vnode && this.$vnode.data.keepAlive) {
if (this.$vnode.parent && this.$vnode.parent.componentInstance && this.$vnode.parent.componentInstance.cache) {
if (this.$vnode.componentOptions) {
var key = !isDef(this.$vnode.key)
? this.$vnode.componentOptions.Ctor.cid + (this.$vnode.componentOptions.tag ? `::${this.$vnode.componentOptions.tag}` : '')
: this.$vnode.key;
var cache = this.$vnode.parent.componentInstance.cache;
var keys = this.$vnode.parent.componentInstance.keys;
if (cache[key]) {
if (keys.length) {
var index = keys.indexOf(key);
if (index > -1) {
keys.splice(index, 1);
}
}
delete cache[key];
}
}
}
}
dtmp.apply(this, arguments);
}
Vue.prototype.$keepAliveDestroy = f;
2. 언제 폐기
그럼 언제 없애나요? 두 가지 촉발 시기가 있습니다.
루트백의 상황을 구체적으로 살펴보자. 만약에 우리 페이지에 되돌아오는 키가 있다면 캐시를 제거하는 것은 매우 정확한 시기이다. 그러나 브라우저가 가지고 있는 되돌아오는 키와 안드로이드의 물리적 되돌아오는 키를 무시할 수 없다. 이런 상황을 고려한 후에 되돌아오는 키만 사용하는 방안은 만족할 수 없다.
2.1 방안은 루트를 사용한다.query 현재 페이지 스택 깊이 기록
매번push나replace는query의 이전 인자를 추가하여 현재 깊이를 기록합니다
this.$router.push({
path:"/targer",
query:{
stackLevel:Number(this.$route.query.stackLevel) + 1
}
})
이 방안은 뚜렷한 폐단이 있다. 외부에 하나의 매개 변수가 노출되는 것은 매우 추악하고 위험하다. 사용자가 마음대로 수정할 수 있다. 웹 홍보를 할 때 업무가 생산 환경에 가서 자신이 복사한 홍보 링크도 이상한 것을 가지고 있을 수 있다.https://xxx.com/foo?bar=123&stackLevel=13접미사활용단어참조2.2 프로젝트 2는 Vue 인스턴스를 사용하여 현재 스택 깊이를 자체 기록합니다.
hackrouter의push와replace 방법을 떨어뜨린 후, 매번 점프할 때마다 목표 페이지의 vm에 마운트할 수 있습니다_Stack Level, 이렇게 하면 방안 1의 문제를 해결할 수 있습니다. 사용자에게 노출되지 않고 URL에 보이지 않고 수정할 수 없습니다. 그러나 브라우저의 또 다른 악마인 리셋 키를 무시할 수 없습니다. 리셋할 때 URL은 변하지 않지만 vm 실례는 다시 만들어야 합니다. 그러면 우리의 창고 깊이 표시도 잃어버리게 됩니다.활용단어참조
2.3 방안 3 사용 역사.state 레코드 스택 깊이
그러면 결국 사용자에게 보이지 않을 수도 있고 새로 고칠 때 저장할 수도 있다.그게 역사야.state입니다. 그래서 우리가 해야 할 일은 stack 깊이를history에 저장하는 것입니다.state에서 전체 루트 체인을 완전하게 저장할 수 있습니다.
목표 페이지 창고의 깊이가 현재 페이지보다 작을 때 현재 페이지를 삭제할 수 있습니다.
if(target.stack < current.stack){
current.$keepAliveDestroy();
}
문제 2 페이지와 다른 캐시 여러 개의 실례
원본 코드에서 src/core/components/keep-alive를 볼 수 있습니다.js
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는 키가 없으면 구성 요소 이름을 사용합니다. 따라서 기본 캐시에 있는 키는 구성 요소 이름입니다. 만약에 구성 요소가 같다면 우리는 모든 페이지에 자신의 키가 있으면 이 문제를 해결할 수 있습니다. 어떻게 모든 페이지에 자신의 키를 가지게 할 수 있습니까?두 가지 문제가 있습니다.1. 어떻게 유일하게 할 것인가
1.1 타임 스탬프, 초대형 랜덤 수
key = Date.now()
1.2 라우팅 스택 높이 + 경로 이름
key = vm._stack + router.currentRoute.path 이 방안은 현재의 창고 높이 + 경로 이름을 이용합니다. 왜 경로 이름이 필요합니까? 리플레이스할 때 창고 높이는 변하지 않고 경로 이름만 바뀌기 때문입니다.
2. 키의 값을 페이지의 vnode에 어떻게 부여합니까
현재 두 가지 방안이 vue-router의 현재 Vnode 키에 값을 부여합니다.
2.1 경로를 통과합니다.query 동적 바인딩 키
이 방안은 실현이 비교적 간단하다
// key
...
<router-view :key='$route.query.routerKey' />
...
//push
this.$router.push({
path:"/foo",
query:{
routerKey: Date.now() // key
}
})
이런 방식은 사용하기에 매우 간단하고 효과적이지만 단점 역시 이상한 매개 변수가 URL에 노출될 수 있다2.2 Vnode에 직접 할당된 값 가져오기
어느 단계에서 Vnode의 키에 값을 부여합니까? 정답은 명백히 알 수 있습니다.keep-alive 구성 요소render 함수가 들어가기 전에 src/core/components/keep-alive.js
...
render () {
const slot = this.$slots.default
const vnode: VNode = getFirstComponentChild(slot)
...
우리는keep-alive의render 함수를 해킹하고 그 전에 슬롯의 첫 번째 하위 노드를 가져온 후에 키에 값을 부여한 다음keep-alive의render를 호출할 수 있습니다.
const tmp = vm.$options.render //vm is keep-alive component instance
vm.$options.render = function() {
const slot = this.$slots.default;
const vnode = getFirstComponentChild(slot) // vnode is a keep-alive-component-vnode
if (historyShouldChange) {
if (!isDef(vnode.key)) {
if (isReplace) {
vnode.key = genKey(router._stack)
} else if (isPush()) {
vnode.key = genKey(Number(router._stack) + 1)
} else {
vnode.key = genKey(Number(router._stack) - 1)
}
}
} else {
// when historyShouldChange is false should rerender only, should not create new vm ,use the same vnode.key issue#7
vnode.key = genKey(router._stack)
}
return tmp.apply(this, arguments)
}
총결산
위의 문제에 대한 분석을 통해 우리는 캐시를 자동으로 관리하는 핵심 난제를 해결했다.본고는 개원 라이브러리vue-router-keep-alive-helper에 대한 요약이다. 이 라이브러리는 간단하고 사용하기 쉬운keep-alive 캐시 자동화 관리 도구로 Vue 캐시 관리의 난제와 작별한다.만약 당신에게 유용하다면, 아낌없는 스타에게 감사 드립니다.
데모 시연Sample Code
Bilibili 프레젠테이션 비디오삼련에게 감사 드립니다.
다음은 Vue의 캐시 페이지를 어떻게 관리하는지에 대한 상세한 내용입니다. 더 많은 vue 캐시 페이지에 대한 자료는 저희 다른 관련 글을 참고하세요!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
OCI Database Management로 OracleDB 성능 모니터링2020년 2월에 Oracle Cloud Infrastructure Database Management가 새로운 Database 운영 모니터링 서비스로 출시되었습니다. 온 프레미스 및 OCI의 Oracle Datab...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.