1. 程式人生 > >修改vue的keep-alive實現仿easyui-頁面tab切換

修改vue的keep-alive實現仿easyui-頁面tab切換

後臺管理頁面通常會有tabs切換作為導航

常見實現方式

  1. 通過顯示和隱藏div(缺點:無法看到路由)
  2. 通過iframe,其實和顯示隱藏區別不大

vue實現方式

因為要在vue中實現,用vue-router和vue中一個keep-alive,但是keep-alive有個缺點,他是用物件來快取元件,並且是一個抽象元件,所以就稍微修改下。

效果圖

navigation

功能

  1. 點選左側顯示toolbar nav
  2. 通過toolbar 切換路由,並保持之前快取
  3. 關閉toolbar清除快取,開啟後仍可用快取

專案原始碼

實現方式

監聽路由的變動,當路由改變時將當前路由新增到一個列表裡面。迴圈此列表生成toolbar

tabs,給keep-alive新增兩個方法。第一個是當keep-alive工作的時候,設定儲存keyhook、第二個方法新增通過key刪除快取removeCacheByKey
當點選關閉按鈕的時候,呼叫removeCacheByKey就可以完美解決vue keep-alive無法主動清除快取的問題了。主要的keep-alive程式碼:

import _ from 'lodash'

function isDef (val) {
  return val !== undefined && val !== null
}

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)) { return c } } } } function getComponentName (opts) { return opts && (opts.Ctor.options.name || opts.tag) } 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 (cache, current, filter) { for (const key in cache) { const cachedNode = cache[key] if (cachedNode) { const name = getComponentName(cachedNode.componentOptions) if (name && !filter(name)) { if (cachedNode !== current) { pruneCacheEntry(cachedNode) } cache[key] = null } } } } function pruneCacheEntry (vnode) { if (vnode) { vnode.componentInstance.$destroy() } } export default { name: 'pk-keep-alive', props: { include: [], exclude: [], updateComponentsKey: Function }, created () { // vue的keep-alive儲存物件 this.cache = Object.create(null) }, // 呼叫keep-alive元件銷燬鉤子,元件銷燬的時候同時清除快取 destroyed () { for (const key in this.cache) { pruneCacheEntry(this.cache[key]) } }, watch: { include (val) { pruneCache(this.cache, this._vnode, name => matches(val, name)) }, exclude (val) { pruneCache(this.cache, this._vnode, name => !matches(val, name)) } }, render () { const vnode = getFirstComponentChild(this.$slots.default) const componentOptions = vnode && vnode.componentOptions if (componentOptions) { // check pattern const name = getComponentName(componentOptions) if (name && ( (this.include && !matches(this.include, name)) || (this.exclude && matches(this.exclude, name)) )) { return vnode } const key = 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 // 新增獲取key的外部hook this.updateComponentsKey && this.updateComponentsKey(key) if (this.cache[key]) { vnode.componentInstance = this.cache[key].componentInstance } else { this.cache[key] = vnode } vnode.data.keepAlive = true } return vnode }, methods: { // 通過cache的key刪除對應的快取 removeCacheByKey (key) { pruneCacheEntry(this.cache[key]) this.cache[key] = null } } }