认识
一、认识
setup
是 Vue.js 3.0
新增的组件选项, 主要用于配合 组合式 API
, 为用户提供一个地方, 用于建立组合逻辑、创建响应式数据、创建通用函数、注册生命周期钩子等能力。在组件的整个生命周期中, setup
函数只有在被挂载时执行一次。
在 mountComponent
中创建组件实例, 调用 setupComponent
进行组件实例安装, 过程中会初始化 props
、slots
, 然后开始调用 setup
函数, 传入两个参数, 一个参数为已经初始化完成的 props
, 另一个参数为 setupContext
, 有 slots
、emit
、attrs
、expose
等方法。可以返回一个函数或者对象, 返回函数作为组件的 render
函数。这种方式常用于组件不是以模版来表达其渲染内容的情况。如果组件以模版来表达其渲染的內容,那么 setup
函数不可以再返回函数,否则会与模版编译生成的渲染函数产生冲突; 返回对象中包含的数据将暴露给模版使用
二、语法
const Component = {
props: {
a: String,
b: Number,
}
setup(props,setupContext){
const { a,b } = props;
const { slots, emit, attrs, expose } = setupContext;
return 函数/对象
}
}
2.1 props
setup
的第一个参数 props
可以取得外部为组件传递的 props
数据对象
2.2 setupContext
setup
的第二个参数 setupContext
保存着与组件接口相关的数据和方法
-
slots
: 组件接收到的插槽 -
emit
: 一个函数, 用来发射自定义事件 -
attrs
: 当为组件传递props
时, 没有显示地声明为props
的属性会存储到attrs
对象中 -
expose
: 一个函数, 用来显示地对外暴露组件数据,
2.3 setup return
setup
的返回值有两种情况:
-
返回一个函数: 该函数作为组件的
render
函数。这种方式常用于组件不是以模版来表达其渲染内容的情况。如果组件以模版来表达其渲染的內容,那么setup
函数不可以再返回函数,否则会与模版编译生成的渲染函数产生冲突。const Component = {
setup(){
return ()=>{
return {
type: 'div',
children: 'hello div'
}
}
}
} -
返回一个对象: 该对象中包含的数据将暴露给模版使用
const Component = {
setup(){
return {
a: 1,
b: 2
}
},
render(){
return {
type: 'div',
children: `a 为: ${this.a}; b 为: ${this.b}`
}
}
}
三、组件挂载细节
组件挂载时, 相关 setup
的逻辑大体如下所示:
function mountComponent(vnode,container,anchor){
const componentOptions = vnoe.type;
let { data,setup,render,props: propsOptions } = componentOptions;
const state = data? reactive(data()) : null;
const [props,attrs] = resolveProps(propsOptions,vnode.props);
const instance = {
state,
subTree: null,
isMounted: false,
props: shallowReactive(props),
}
const setupContext = { attrs }; // attrs emit ……
const setupResult = setup(shallowReactive(instance.props), setupContext);
let setupState = null;
if(typeof setupResult === 'function'){
if (render) {
console.log('setup 返回值为函数,将作为渲染函数, render 选项将被忽略');
}
render = setupResult;
}else{
setupState = setupResult;
}
……
const renderContext = new Proxy(instance, {
get(target,key,receiver){
……
else if(setupState && key in setupState){
return Relfect.get(setupState,key,receiver)
}
},
set(target,key,value,receiver){
……
else if(setupState && key in setupState){
return Reflect.set(setupState,key,value,receiver)
}
}
});
}