keep-alive-vue2
Version:
Extend vue2 keep-alive and router-view, add the function of automatically judging whether to use the cache.
245 lines (229 loc) • 6.27 kB
JavaScript
'use strict';
const objectClass = Object;
objectClass.__keepAlive = true;
var defaultCache = false;
const wrapRouter = {
getDefaultCached() {
return defaultCache;
},
setDefaultCached(value) {
defaultCache = value;
},
getKeepAlive() {
return objectClass.__keepAlive;
},
setKeepAlive(useKeepAlive) {
objectClass.__keepAlive = useKeepAlive;
},
wrap(router) {
const { push, go, replace } = router;
function checkSetCache(location) {
return location && (typeof location.cache === 'boolean' || typeof location.keepAlive === 'boolean');
}
function setCache(location) {
if (location && typeof location.cache === 'boolean') {
wrapRouter.setKeepAlive(location.cache);
} else if (location && (typeof location.keepAlive === 'boolean')) {
wrapRouter.setKeepAlive(location.keepAlive);
}
}
router.push = function(...args) {
const location = args[0];
if (checkSetCache(location)) {
setCache(location);
} else {
wrapRouter.setKeepAlive(wrapRouter.getDefaultCached());
}
return push.apply(this, args);
};
router.replace = function(...args) {
const location = args[0];
if (checkSetCache(location)) {
setCache(location);
} else {
wrapRouter.setKeepAlive(wrapRouter.getDefaultCached());
}
return replace.apply(this, args);
};
router.back = function(options = { cache: true }) {
wrapRouter.setKeepAlive(!!options.cache);
return go.apply(this, [-1, { cache: !!options.cache }]);
};
router.forward = function(options = { cache: true }) {
wrapRouter.setKeepAlive(!!options.cache);
return go.apply(this, [1, { cache: !!options.cache }]);
};
router.go = function(num, options = { cache: true }) {
wrapRouter.setKeepAlive(!!options.cache);
return go.apply(this, [num]);
};
}
};
const KeepAliveVue2 = {
name: 'KeepAliveVue2',
props: {
cache: Boolean,
include: RegExp,
exclude: RegExp,
max: Number,
name: String,
defaultCache: Boolean,
},
data() {
wrapRouter.setDefaultCached(this.defaultCache);
return {
hasDestroyed: false,
keepAliveRef: null,
oldCache: {},
pathCache: {},
disabledCachedKeys: {},
};
},
methods: {
before(route, prev, next) {
if (this.hasDestroyed) {
return next();
}
this.setKeepAliveRef();
next();
},
after(route) {
if (this.hasDestroyed) {
return true;
}
setTimeout(() => {
if (!this.cache) {
this.restoreCached();
}
}, 10);
this.afterSyncReset(route);
},
afterSyncReset(route){
setTimeout(() => {
this.setKeepAliveRef();
this.setCacheByPath();
this.setMermoryCache();
wrapRouter.setKeepAlive(true);
}, 10);
},
setCacheByPath() {
if (this.keepAliveRef && this.keepAliveRef.cache) {
const newCache = this.keepAliveRef.cache;
const oldCache = this.oldCache;
const pathCacheJson = JSON.stringify(this.pathCache);
Object.keys(newCache).some(key => {
if(!oldCache[key]){
const path = this.getRoutePath();
if (path && !this.pathCache[path] && !pathCacheJson.match(RegExp(`:"${key}"`))) {
this.pathCache[path] = key;
return true;
}
}
});
}
},
getRoutePath(){
const matched = this.$route.matched || [];
return matched.length ? matched[matched.length - 1].path : null;
},
setKeepAliveRef() {
const cachePage = this.$refs.cachedPage;
if (cachePage && cachePage.$options.parent && cachePage.$options.parent.cacheVNode) {
this.keepAliveRef = cachePage.$options.parent;
}
},
setMermoryCache() {
this.setKeepAliveRef();
if (this.keepAliveRef && this.$refs.cachedPage) {
this.oldCache = {...(this.keepAliveRef.cache || {})};
}
},
restoreCached() {
const cachePage = this.$refs.cachedPage;
if (cachePage) {
this.setKeepAliveRef();
const path = this.getRoutePath();
const key = this.pathCache[path];
if (path && key) {
this.setkeepAliveInValidate(key, path);
}
}
},
setkeepAliveInValidate(key, path){
const cachePage = this.$refs.cachedPage;
const newCache = this.keepAliveRef.cache;
if (newCache[key]) {
const vnode = newCache[key].componentInstance.$vnode;
if(vnode.data){
vnode.data.keepAlive = false;
}
}
if (cachePage) {
const keys = this.keepAliveRef.keys;
if(keys){
this.keepAliveRef.keys = keys.filter(item => item !== key);
delete this.keepAliveRef.cache[key];
}
}
delete this.oldCache[key];
}
},
created () {
wrapRouter.wrap(this.$router.constructor.prototype);
this.$router.beforeEach(this.before);
this.$router.afterEach(this.after);
},
destroyed () {
this.hasDestroyed = true;
},
render () {
const createElement = this._self._c || this.$createElement;
if (!this.cache || !wrapRouter.getKeepAlive()) {
this.restoreCached();
}
if(!this.$refs.cachedPage) {
this.afterSyncReset();
}
return createElement(
'div',
{
attrs: {
class: 'keep-alive-cache'
}
},
[
createElement(
'keep-alive',
{
props: {
include: this.include,
exclude: this.exclude,
max: this.max
},
},
[this.cache ? createElement('router-view', {
ref: "cachedPage",
props: {
name: this.name,
key: this.$route.fullPath
}
}) : this._e()],
1
),
this.cache ? this._e() : createElement('router-view', {
ref: "cachedPage",
props: {
name: this.name
}
})
],
1
)
}
};
var main = {
install(Vue) {
Vue.component(KeepAliveVue2.name, KeepAliveVue2);
}
};
module.exports = main;