您好,登錄后才能下訂單哦!
本文小編為大家詳細介紹“vue中如何使用keep-alive動態刪除已緩存組件”,內容詳細,步驟清晰,細節處理妥當,希望這篇“vue中如何使用keep-alive動態刪除已緩存組件”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學習新知識吧。
在做后臺管理系統的時候,有這樣一個需求:
后臺的界面如下:
點擊左邊的菜單,會在右邊的頂部生成一個個tag導航標簽。當打開多個tag頁時,用戶可以在多個tag之間進行切換。需要在新增,修改頁面切換tag時候,保留之前的信息,不進行頁面的刷新。
經過查詢vue文檔,可以使用keep-alive實現標簽路由緩存,實現方式如下:
在路由配置的meta中添加keepAlive,如下:
{ path: '/actdebt', component: Layout, redirect: '/actdebt/add', children: [ { path: 'add', name: 'XXX新增配置', meta: { keepAlive: true, }, component: () => import (/* webpackChunkName: "page" */'@/views/bankact/actdebt/add') }] },
然后在頁面中使用v-if做判斷,并且加上key
<keep-alive> <router-view :key="$route.fullPath" class="avue-view" v-if="$route.meta.keepAlive" /> </keep-alive> <router-view class="avue-view" v-if="!$route.meta.keepAlive" />
使用上面這種方式解決了修改不同記錄的緩存問題,因為不同記錄的fullPath 不一樣,這樣的話key就會不一樣。
但是對于新增和修改同一條記錄還是有緩存問題。例如新增一條記錄保存成功后,下次在打開新增頁面,還是緩存有之前的記錄。
修改頁面也是的,修改同一條記錄保存成功后,再次打開可能還是會有之前的修改數據。
要解決上面這種問題我想到的解決方案為:在不同的tag導航欄切換的時候,保留緩存數據。當關閉tag導航欄或者關閉頁面的時候,清除緩存。
清除緩存可以在組件里面的deactivated鉤子函數調用this.$destroy();但是發現下次打開這個頁面的時候,新的組件不會被緩存了。
可以利用keep-alive的include,新打開標簽時,把當前組件名加入到include數組里,關閉標簽時從數組中刪除關閉標簽的組件名就可以了。
Include里面的值必須和組件的name屬性保持一致,如下:
但是如果我同一個組件加載了兩次,一個需要緩存,一個不需要緩存。但是他們的name卻是一樣的,還是無法解決問題。
所以是否可以重寫keep-alive源碼,使include可以按照路由地址匹配,而不是按照組件的name匹配。完整的代碼如下:
新建keepAlive.js文件
/** * base-keep-alive 主要解決問題場景:多級路由緩存 * 前提:保證動態路由生成的route name 值都聲明了且唯一 * 基于以上對keep-alive進行以下改造: * 1. 組件名稱獲取更改為路由名稱 * 2. cache緩存key也更改為路由名稱 * 3. pruneCache */ const _toString = Object.prototype.toString function isRegExp(v) { return _toString.call(v) === '[object RegExp]' } export function remove(arr, item) { if (arr.length) { const index = arr.indexOf(item) if (index > -1) { return arr.splice(index, 1) } } } /** * 1. 主要更改了 name 值獲取的規則 * @param {*} opts */ function getComponentName(opts) { // return opts && (opts.Ctor.options.name || opts.tag) return this.$route.path } function isDef(v) { return v !== undefined && v !== null } function isAsyncPlaceholder(node) { return node.isComment && node.asyncFactory } function getFirstComponentChild(children) { if (Array.isArray(children)) { for (let i = 0; i < children.length; i++) { const c = children[i] if (isDef(c) && (isDef(c.componentOptions) || isAsyncPlaceholder(c))) { return c } } } } function matches(pattern, name) { if (Array.isArray(pattern)) { return pattern.indexOf(name) > -1 } else if (typeof pattern === 'string') { return pattern.split(',').indexOf(name) > -1 } else if (isRegExp(pattern)) { return pattern.test(name) } /* istanbul ignore next */ return false } function pruneCache(keepAliveInstance, filter) { const { cache, keys, _vnode } = keepAliveInstance for (const key in cache) { const cachedNode = cache[key] if (cachedNode) { // ------------ 3. 之前默認從router-view取儲存key值, 現在改為路由name, 所以這里得改成當前key // const name = getComponentName.call(keepAliveInstance, cachedNode.componentOptions) const name = key if (name && !filter(name)) { pruneCacheEntry(cache, key, keys, _vnode) } } } } function pruneCacheEntry( cache, key, keys, current ) { const cached = cache[key] if (cached && (!current || cached.tag !== current.tag)) { cached.componentInstance.$destroy() } cache[key] = null remove(keys, key) } const patternTypes = [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, name => matches(val, name)) }) this.$watch('exclude', val => { pruneCache(this, name => !matches(val, name)) }) }, render() { const slot = this.$slots.default const vnode = getFirstComponentChild(slot) const componentOptions = vnode && vnode.componentOptions if (componentOptions) { // check pattern const name = getComponentName.call(this, componentOptions) // ---------- 對于沒有name值得設置為路由得name, 支持vue-devtool組件名稱顯示 if (!componentOptions.Ctor.options.name) { vnode.componentOptions.Ctor.options.name } const { include, exclude } = this if ( // not included (include && (!name || !matches(include, name))) || // excluded (exclude && name && matches(exclude, name)) ) { return vnode } const { cache, keys } = this // ------------------- 儲存的key值, 默認從router-view設置的key中獲取 // const key = vnode.key == null // ? componentOptions.Ctor.cid + (componentOptions.tag ? `::${componentOptions.tag}` : '') // : vnode.key // ------------------- 2. 儲存的key值設置為路由中得name值 const key = name 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]) } }
然后在main.js中引入該組件,使組件可以全局使用
在頁面直接使用BaseKeepAlive:
<BaseKeepAlive :include="cachetags"> <router-view :key="$route.fullPath" class="avue-view" /> </BaseKeepAlive>
cachetags 方法就是新打開標簽時,把當前組件名加入到include數組里,關閉標簽時從數組中刪除關閉標簽,源碼如下:
computed: { ...mapGetters(['isLock', "tagList",'isCollapse', 'website']), cachetags(){ let list=[] for(let item of this.tagList){ if(!validatenull(item.keepalive)&&item.keepalive){ list.push(item.value) } } return list.join(',') } },
方法中的tagList就是導航欄當前打開相應的tag集合如下圖所示
讀到這里,這篇“vue中如何使用keep-alive動態刪除已緩存組件”文章已經介紹完畢,想要掌握這篇文章的知識點還需要大家自己動手實踐使用過才能領會,如果想了解更多相關內容的文章,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。