<script> export const patternTypes = [String, RegExp, Array]; export default { name: 'AppKeepAlive', props: { // 根据组件 name 进行匹配。如果 name 选项不可用,则匹配它的局部注册名称 (父组件 components 选项的键值)。匿名组件不能被匹配。 include: patternTypes, exclude: patternTypes, max: [String, Number], keyList: [Array], }, data() { return { // eslint-disable-next-line vue/no-reserved-keys _toString: Object.prototype.toString, }; }, watch: { include(val) { const _this = this; _this.pruneCache(function (name) { return _this.matches(val, name); }); }, exclude(val) { const _this = this; _this.pruneCache(function (name) { return !_this.matches(val, name); }); }, keyList(val) { const _this = this; // 配置了keyList但是下方插件key _this.pruneCache2(function (name) { return !_this.matches(val, name); }); }, }, created() { // 保存缓存的组件 this.cache = Object.create(null); // 保存缓存的组件的key this.keys = []; }, destroyed() { const _this = this; // eslint-disable-next-line no-restricted-syntax, guard-for-in for (const key in _this.cache) { _this.pruneCacheEntry(_this.cache, key, _this.keys); } }, methods: { pruneCacheEntry(cache, key, keys, _current) { const cached = cache[key]; if (cached) { cached.componentInstance.$destroy(); } // eslint-disable-next-line no-param-reassign cache[key] = null; this.remove(keys, key); }, pruneCache(filter) { const _this = this; const cache = _this.cache; const keys = _this.keys; const _vnode = _this._vnode; // eslint-disable-next-line no-restricted-syntax, guard-for-in for (const key in cache) { const cachedNode = cache[key]; if (cachedNode) { const name = _this.getComponentName(cachedNode.componentOptions); if (name && !filter(name)) { _this.pruneCacheEntry(cache, key, keys, _vnode); } } } }, pruneCache2(filter) { const _this = this; const cache = _this.cache; const keys = _this.keys; const _vnode = _this._vnode; // eslint-disable-next-line no-restricted-syntax, guard-for-in for (const key in cache) { const cachedNode = cache[key]; if (cachedNode) { const name = cachedNode.data.curPath; if (name && filter(name)) { _this.pruneCacheEntry(cache, key, keys, _vnode); } } } }, matches(pattern, name) { if (Array.isArray(pattern)) { return pattern.indexOf(name) > -1; } if (typeof pattern === 'string') { return pattern.split(',').indexOf(name) > -1; } if (this.isRegExp(pattern)) { return pattern.test(name); } /* istanbul ignore next */ return false; }, getComponentName(opts) { return opts && (opts.Ctor.options.name || opts.tag); }, getFirstComponentChild(children) { const _this = this; if (Array.isArray(children)) { for (let i = 0; i < children.length; i++) { const c = children[i]; if ( _this.isDef(c) && (_this.isDef(c.componentOptions) || _this.isAsyncPlaceholder(c)) ) { return c; } } } }, isAsyncPlaceholder(node) { return node.isComment && node.asyncFactory; }, isDef(v) { return v !== undefined && v !== null; }, isRegExp(v) { return this._toString.call(v) === '[object RegExp]'; }, remove(arr, item) { if (arr.length) { const index = arr.indexOf(item); if (index > -1) { return arr.splice(index, 1); } } }, }, render: function render() { // this.$slots.default 包含了所有没有被包含在具名插槽中的节点 // 这里取得第一个子组件 const _this = this; const slot = _this.$slots.default; const vnode = _this.getFirstComponentChild(slot); const componentOptions = vnode && vnode.componentOptions; if (componentOptions) { // check pattern const name = _this.getComponentName(componentOptions); const ref = _this; const include = ref.include; const exclude = ref.exclude; const keyList = ref.keyList; // 获取第一个子组件上面的key const slotKey = vnode.key; // 如果 componentName 没有作为keep-alive被包含进来,直接返回 if ( // 包括并且不匹配的 (include && (!name || !_this.matches(include, name))) || // 排除并且匹配的 (exclude && name && _this.matches(exclude, name)) || // keyList中存在并且不匹配的 (keyList && !slotKey && !_this.matches(keyList, slotKey)) ) { return vnode; } const ref$1 = _this; const cache = ref$1.cache; const keys = ref$1.keys; const key = vnode.key == null ? // 相同的构造器(constructor)可能会注册为不同的本地组件,所以仅有一个 cid 是不够的 componentOptions.Ctor.cid + (componentOptions.tag ? `::${componentOptions.tag}` : '') : vnode.key; if (cache[key]) { // 如果已经缓存了,需要保持当前的key 是最新的 vnode.componentInstance = cache[key].componentInstance; // make current key freshest _this.remove(keys, key); keys.push(key); } else { // 否则,进行缓存并更新keys数组。 cache[key] = vnode; keys.push(key); // 缓存组件超出最大值,将队首的组件销毁(先进先出) if (_this.max && keys.length > parseInt(_this.max, 10)) { _this.pruneCacheEntry(cache, keys[0], keys, _this._vnode); } } vnode.data.keepAlive = true; vnode.data.curPath = slotKey; } return vnode || (slot && slot[0]); }, }; </script>