0%

setup原理

setup只会在被挂载时执行一次,返回值由两种情况:

1 返回一个函数,该函数将作为组件的render函数

2 返回一个对象,该对象包含的数据将暴露给模板使用

setup函数第一个参数为外部为组件传递的props数据对象,第二个参数为setupContext对象,其中保存着组件接口相关的数据和方法:slots,emit,attrs,expose

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
function mountComponent(vnode,container,anchor) {
const componentOptions = vnode.type
//从组件选项中取出setup函数
let {render,data,setup} = componentOptions
beforeCreate && beforeCreate()
const state = data ? reactive(data()) : null
const [props,attrs] = resolveProps(propsOption,vnode,props)
const instance = {
state,
props:shallowReactive(props),
isMounted: false,
subTree: null
}
//setupContext包含slots,emit,attrs,expose
const setupContext = {attrs}
//setupContext作为第二个参数传入
const setupResult = setup(shallowReadOnly(instance.props),setupContext)
//如果setupResult为函数,则作为渲染函数
if(typeof setupResult === 'function'){
//冲突
if(render)console.error('setup函数返回渲染函数,render选项被忽略')
render = setupResult
}else{
//如果setup返回值不是函数,则作为数据状态赋值给setupState
setupState = setupContext
}
//渲染函数上下文对象,本质上是组件实例的代理,使得渲染函数能够通过this访问props数据和组件自身状态
const renderContext = new Proxy(instance,{
get(t,k,t){
const {state,props,slots} = t
//先尝试读取自身状态数据
if(state && k in state) {
return state[k]
}else if(k in props){
return props[k]//如果组件自身没有该数据,尝试从props上读取
}else {
console.error('不存在')
}
//当k的值为$slots,直接返回组件实例上的slots
if(k === '$slots')return slots
//...
},
set(t,k,v,r){
const [state,props] = t
if(state && k in state){
state[k]=t
}else if(k in props){
props[k]=t
}else{
console.error('不存在')
}
}
})

}
//用于解析组件props和attrs数据
function resolveProps(options,propsData) {
const props = {}
const attrs = {}
//遍历为组件传递的props数据
for(const key in propsData) {
if(key in options){
//如果为组件传递的props数据在组件自身的props选项中有定义,则将其视为合法的props
props[key] = propsData[key]
}else{
attrs[key] = propsData[key]
}
}
return [props,attrs]
}