keep-alive保持组件状态的方法

本文详细介绍了Vue.js内置组件keep-alive的作用和设计初衷,它用于保持组件状态,避免重复渲染。通过缓存机制,keep-alive在组件切换时能有效地复用组件实例,提高性能。文章还解析了keep-alive的实现原理,包括如何检查include和exclude属性、如何管理缓存以及如何保持组件状态。并提供了一个实际示例来帮助理解。
摘要由CSDN通过智能技术生成

keep-alive的设计初衷

有些业务场景需要根据不同的判断条件,动态地在多个组件之间切换。频繁的组件切换会导致组件反复渲染,如果组件包含有大量的逻辑和dom节点,极易造成性能问题。其次,切换后组件的状态也会完全丢失。keep-alive的设计初衷就是为了保持组件的状态,避免组件的重复渲染。

为什么keep-alive可以直接使用

开发者无需注册和引入,直接可以在模板中使用。 跟开发者使用Vue.component自定义的组件不同,keep-alive无需注册,在模板中直接可以使用,如下所示:

1
2
3



这是因为keep-alive是vue的内置组件,已经在vue中提前定义。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
// core/components/keep-alive.js

export default {
name: ‘keep-alive’,
abstract: true,

props: {
include: patternTypes,
exclude: patternTypes,
max: [String, Number]
},

created () {
this.cache = Object.create(null)
this.keys = []
},

destroyed () {
// keep-alive的销毁,将所有缓存的组件清除
for (const key in this.cache) {
pruneCacheEntry(this.cache, key, this.keys)
}
},

mounted () {
// 如果指定了include和exclude属性,需要实时观察当前这两个属性的变化,以及时的更新缓存
this. w a t c h ( ′ i n c l u d e ′ , v a l = > p r u n e C a c h e ( t h i s , n a m e = > m a t c h e s ( v a l , n a m e ) ) ) t h i s . watch('include', val => { pruneCache(this, name => matches(val, name)) }) this. watch(include,val=>pruneCache(this,name=>matches(val,name)))this.watch(‘exclude’, val => {
pruneCache(this, name => !matches(val, name))
})
},

render () {
// keepAlive组件本身不会被渲染成dom节点,其render方法的处理逻辑的是将其包裹的组件的vnode返回
const slot = this.$slots.default
// 获取第一个组件子节点
const vnode: VNode = getFirstComponentChild(slot)
const componentOptions: ?VNodeComponentOptions = vnode && vnode.componentOptions
if (componentOptions) {
// check pattern
const name: ?string = getComponentName(componentOptions)
const { include, exclude } = this
if (
// not included
(include && (!name || !matches(include, name))) ||
// excluded
(exclude && name && matches(exclude, name))
) {
return vnode
}

const { cache, keys } = this
const key: ?string = 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

// 1、如果缓存中存在该vnode,从缓存中取得该组件的实例(一个组件对应一颗vnode树,同时一个组件对应一个vue子类的实例),不再重新创建
if (cache[key]) {
vnode.componentInstance = cache[key].componentInstance
// make current key freshest
// 将当前的组件的key作为最新的缓存(更新其在keys数组中的顺序)
remove(keys, key)
keys.push(key)
} else {
// 2、如果未命中缓存,添加到缓存
cache[key] = vnode
keys.push(key)
// 如果缓存超过限制,淘汰最旧的缓存
if (this.max && keys.length > parseInt(this.max)) {
pruneCacheEntry(cache, keys[0], keys, this._vnode)
}
}

// 标记为keepAlive组件
vnode.data.keepAlive = true
}
return vnode || (slot && slot[0])
}
}
这是因为keep-alive是vue的内置组件,已经在vue中提前定义。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
// core/components/keep-alive.js

export default {
name: ‘keep-alive’,
abstract: true,

props: {
include: patternTypes,
exclude: patternTypes,
max: [String, Number]
},

created () {
this.cache = Object.create(null)
this.keys = []
},

destroyed () {
// keep-alive的销毁,将所有缓存的组件清除
for (const key in this.cache) {
pruneCacheEntry(this.cache, key, this.keys)
}
},

mounted () {
// 如果指定了include和exclude属性,需要实时观察当前这两个属性的变化,以及时的更新缓存
this. w a t c h ( ′ i n c l u d e ′ , v a l = > p r u n e C a c h e ( t h i s , n a m e = > m a t c h e s ( v a l , n a m e ) ) ) t h i s . watch('include', val => { pruneCache(this, name => matches(val, name)) }) this. watch(include,val=>pruneCache(this,name=>matches(val,name)))this.watch(‘exclude’, val => {
pruneCache(this, name => !matches(val, name))
})
},

render () {
// keepAlive组件本身不会被渲染成dom节点,其render方法的处理逻辑的是将其包裹的组件的vnode返回
const slot = this.$slots.default
// 获取第一个组件子节点
const vnode: VNode = getFirstComponentChild(slot)
const componentOptions: ?VNodeComponentOptions = vnode && vnode.componentOptions
if (componentOptions) {
// check pattern
const name: ?string = getComponentName(componentOptions)
const { include, exclude } = this
if (
// not included
(include && (!name || !matches(include, name))) ||
// excluded
(exclude && name && matches(exclude, name))
) {
return vnode
}

const { cache, keys } = this
const key: ?string = vnode.key == null
// same constructor may get registered as different local components
// so cid alone is no

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值