<script> export default { name: 'app-keep-alive', render: function render() { let _this = this; let slot = _this.$slots.default; let vnode = _this.getFirstComponentChild(slot); let componentOptions = vnode && vnode.componentOptions; if (componentOptions) { // check pattern let name = _this.getComponentName(componentOptions); let ref = _this; let include = ref.include; let exclude = ref.exclude; let routerList = ref.routerList; let route = ref.$route; if ( // not included (include && (!name || !_this.matches(include, name))) || // excluded (exclude && name && _this.matches(exclude, name)) || (routerList && (!route.fullPath && !_this.matches(routerList, route.fullPath))) ) { return vnode } let ref$1 = _this; let cache = ref$1.cache; let keys = ref$1.keys; let 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; if (cache[key]) { vnode.componentInstance = cache[key].componentInstance; // make current key freshest _this.remove(keys, key); keys.push(key); } else { cache[key] = vnode; keys.push(key); // prune oldest entry if (_this.max && keys.length > parseInt(_this.max)) { _this.pruneCacheEntry(cache, keys[0], keys, _this._vnode); } } vnode.data.keepAlive = true; vnode.data.curPath = route.fullPath; } return vnode || (slot && slot[0]) }, props: { include: [String, RegExp, Array], exclude: [String, RegExp, Array], max: [String, Number], routerList: [Array] }, data: function(){ return { _toString: Object.prototype.toString } }, created: function () { this.cache = Object.create(null); this.keys = []; }, destroyed: function () { let _this = this; for (let key in _this.cache) { _this.pruneCacheEntry(_this.cache, key, _this.keys); } }, watch: { 'include': function (val) { let _this = this; _this.pruneCache(function (name) { return _this.matches(val, name); }); }, 'exclude': function (val) { let _this = this; _this.pruneCache(function (name) { return !_this.matches(val, name); }); }, 'routerList': function(val) { let _this = this; _this.pruneCache2(function (name) { return !_this.matches(val, name); }); } }, methods: { pruneCacheEntry(cache, key, keys, current) { let cached = cache[key]; if (cached) { cached.componentInstance.$destroy(); } cache[key] = null; this.remove(keys, key); }, pruneCache(filter) { let _this = this; let cache = _this.cache; let keys = _this.keys; let _vnode = _this._vnode; for (let key in cache) { let cachedNode = cache[key]; if (cachedNode) { let name = _this.getComponentName(cachedNode.componentOptions); if (name && !filter(name)) { _this.pruneCacheEntry(cache, key, keys, _vnode); } } } }, pruneCache2(filter) { let _this = this; let cache = _this.cache; let keys = _this.keys; let _vnode = _this._vnode; for (let key in cache) { let cachedNode = cache[key]; if (cachedNode) { let 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 } else if (typeof pattern === 'string') { return pattern.split(',').indexOf(name) > -1 } else 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) { let _this = this; if (Array.isArray(children)) { for (let i = 0; i < children.length; i++) { let 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) { let index = arr.indexOf(item); if (index > -1) { return arr.splice(index, 1) } } } } } </script> <style lang="less"> </style>