Skip to content

Commit ab4bfd4

Browse files
committed
perf(router-alive): 组件销毁有清理缓存和组件数据
1 parent 5835308 commit ab4bfd4

File tree

5 files changed

+77
-41
lines changed

5 files changed

+77
-41
lines changed

demo/components/frames/I18n.vue

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ export default {
5050
}
5151
},
5252
53+
destroyed () {
54+
Vue.prototype.$lang = null
55+
},
56+
5357
methods: {
5458
i18n (key, params) {
5559
let lang = this.lang[key]

src/components/RouterAlive.js

Lines changed: 40 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -14,32 +14,42 @@ export default {
1414
})
1515
},
1616

17+
// 销毁后清理缓存
18+
destroyed () {
19+
this.removeAll()
20+
this.cache = null
21+
this.lastRoute = null
22+
},
23+
1724
render () {
1825
const slot = this.$slots.default
1926
const vnode = getFirstComponentChild(slot)
2027
const vmOpts = vnode && vnode.componentOptions
2128

2229
if (vmOpts) {
23-
const { cache, $route, lastRoute } = this
30+
const { $route, lastRoute } = this
2431

2532
// 如果是transition组件,页面组件则为子元素
2633
const pageNode = vmOpts.tag === 'transition' ? vmOpts.children[0] : vnode
2734

2835
if (pageNode && pageNode.componentOptions) {
2936
// 获取缓存
3037
const key = this.getAliveId()
31-
const cacheItem = cache[key]
32-
const { vm: cacheVm, route: cacheRoute } = cacheItem || emptyObj
38+
let cacheItem = this.get(key)
39+
let { vm: cacheVm, route: cacheRoute } = cacheItem || emptyObj
3340

3441
// 是否需要重载路由强制刷新页面组件
3542
let needReloadView = false
3643

3744
// 路由是否改变
3845
let isRouteChange = lastRoute !== $route
3946

40-
// 是否跟上次路由共用组件
47+
// 是否与上次路由相似
48+
let likeLastRoute = this.isAlikeRoute($route, lastRoute)
49+
50+
// 是否跟上次路由不同单共用组件
4151
let isShareComp = isRouteChange &&
42-
!this.isAlikeRoute($route, lastRoute) &&
52+
!likeLastRoute &&
4353
this.getPageComp($route) === this.getPageComp(lastRoute)
4454

4555
if (isRouteChange) {
@@ -51,15 +61,24 @@ export default {
5161
}
5262

5363
if (cacheVm) {
54-
// 缓存组件的路由地址匹配则取缓存的组件
55-
if (this.isAlikeRoute(cacheRoute, $route)) {
64+
let ctorId = this.getCtorIdByNode(pageNode)
65+
let lastCtorId = cacheVm._ctorId
66+
67+
// 页面实例组件构造函数改变则清理旧缓存,解决 webpack 热加载后组件缓存不更新
68+
if (lastCtorId && lastCtorId !== ctorId) {
69+
// 清理缓存组件
70+
this.remove(key)
71+
} else if (this.isAlikeRoute(cacheRoute, $route)) {
72+
// 缓存组件的路由地址匹配则取缓存的组件
5673
pageNode.componentInstance = cacheVm
5774
} else {
5875
// 缓存组件路由地址不匹配则销毁缓存并重载路由
59-
cacheVm.$destroy()
60-
cacheItem.vm = null
76+
this.remove(key)
6177
needReloadView = true
6278
}
79+
80+
// 更新构造 id
81+
cacheVm._ctorId = ctorId
6382
}
6483

6584
// 共用组件的路由切换需重载路由
@@ -93,28 +112,29 @@ export default {
93112
return (cache[key] = item)
94113
},
95114

115+
// 获取缓存项
116+
get (key) {
117+
return this.cache[key]
118+
},
119+
96120
// 删除缓存项
97121
remove (key) {
98122
const { cache } = this
99-
const item = cache[key]
123+
let item = this.get(key)
100124

101125
// 销毁组件实例
102126
if (item) {
103127
item.vm && item.vm.$destroy()
104-
item.vm = null
105128
delete cache[key]
106129
}
107-
108-
this.$emit('remove', [ key ])
109130
},
110131

111-
// 清理缓存
112-
clear (key) {
113-
const item = this.cache[key]
114-
const vm = item && item.vm
115-
if (vm) {
116-
vm.$destroy()
117-
item.vm = null
132+
// 清理所有缓存
133+
removeAll () {
134+
const { cache } = this
135+
136+
for (let i in cache) {
137+
this.remove(i)
118138
}
119139
}
120140
}

src/components/RouterTab/index.js

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,13 @@ export default {
6868
this.updateActivedTab()
6969
},
7070

71+
destroyed () {
72+
// 取消原型挂载
73+
if (Vue.prototype.$routerTab === this) {
74+
Vue.prototype.$routerTab = null
75+
}
76+
},
77+
7178
methods: {
7279
// 根据初始页签数据生成页签列表
7380
getTabItems () {
@@ -210,7 +217,7 @@ export default {
210217
async refreshTab (id = this.activedTab) {
211218
try {
212219
await this.pageLeavePromise(id, 'refresh')
213-
this.$refs.routerAlive.clear(id)
220+
this.$refs.routerAlive.remove(id)
214221
if (id === this.activedTab) this.reloadView()
215222
} catch (e) {}
216223
},
@@ -226,10 +233,10 @@ export default {
226233
if (!force) {
227234
try {
228235
await this.pageLeavePromise(id, 'refresh')
229-
$alive.clear(id)
236+
$alive.remove(id)
230237
} catch (e) {}
231238
} else {
232-
$alive.clear(id)
239+
$alive.remove(id)
233240
}
234241
}
235242
this.reloadView()

src/components/RouterTab/matched.js

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,10 @@ export default {
1616
warn(pageRouteIdx > -1, '未能匹配到路由信息')
1717

1818
return {
19-
baseRoute: matched[pageRouteIdx - 1],
20-
pageRoute: matched[pageRouteIdx],
21-
pageRouteIdx
19+
baseRoute: matched[pageRouteIdx - 1], // 跟路由
20+
pageRoute: matched[pageRouteIdx], // 页面路由
21+
pageRouteIdx,
22+
isNest: pageRouteIdx !== matched.length - 1 // 是否嵌套路由
2223
}
2324
},
2425

@@ -31,6 +32,12 @@ export default {
3132
return path
3233
},
3334

35+
// 获取 vnode 构造 id
36+
getCtorIdByNode (node) {
37+
let { componentOptions: opts } = node
38+
return opts ? opts.Ctor.cid : null
39+
},
40+
3441
// 获取跟路径
3542
getBasePath () {
3643
let { path } = this.matchRoutes().baseRoute
@@ -41,17 +48,18 @@ export default {
4148

4249
// 获取嵌套路由的页面路径
4350
getPagePath (route = this.$route, matchRoutes = this.matchRoutes(route)) {
44-
let { pageRoute, pageRouteIdx } = matchRoutes
51+
let { pageRoute, isNest } = matchRoutes
4552

4653
// 页面嵌套路由
47-
if (pageRouteIdx !== route.matched.length - 1) {
54+
if (isNest) {
4855
return this.parsePath(pageRoute.path, route.params)
4956
}
5057
},
5158

5259
// 获取嵌套路由的页面组件
5360
getPageComp (route = this.$route) {
54-
return this.matchRoutes(route).pageRoute.components.default
61+
let { pageRoute } = this.matchRoutes(route)
62+
return pageRoute ? pageRoute.components.default : null
5563
},
5664

5765
// 获取路由不带hash的路径
@@ -68,6 +76,11 @@ export default {
6876

6977
return this.getPathWithoutHash(route1) === this.getPathWithoutHash(route2) ||
7078
(route1Path && route2Path && route1Path === route2Path)
79+
},
80+
81+
// 是否嵌套路由
82+
isNestRoute (route, matchRoutes = this.matchRoutes(route)) {
83+
return matchRoutes.isNest
7184
}
7285
}
7386
}

src/mixins/routerPage.js

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,18 +28,10 @@ export default {
2828
})
2929
},
3030

31-
// 解决webpack热加载后组件缓存不更新
32-
activated () {
33-
if (!this._isRouterPage) return false
34-
35-
let ctorId = this.$vnode.componentOptions.Ctor.cid
36-
37-
// 热加载后Ctor.cid改变
38-
if (this._ctorId && this._ctorId !== ctorId) {
39-
this.$destroy()
40-
this.$routerTab.refreshTab()
31+
// 销毁后清理数据
32+
destroyed () {
33+
if (this._isRouterPage) {
34+
this.$vnode.data.routerAlive = null
4135
}
42-
43-
this._ctorId = ctorId
4436
}
4537
}

0 commit comments

Comments
 (0)