跳到主要内容

认识

2024年03月15日
柏拉文
越努力,越幸运

一、认识


setupVue.js 3.0 新增的组件选项, 主要用于配合 组合式 API, 为用户提供一个地方, 用于建立组合逻辑、创建响应式数据、创建通用函数、注册生命周期钩子等能力。在组件的整个生命周期中, setup 函数只有在被挂载时执行一次。

mountComponent 中创建组件实例, 调用 setupComponent 进行组件实例安装, 过程中会初始化 propsslots, 然后开始调用 setup 函数, 传入两个参数, 一个参数为已经初始化完成的 props, 另一个参数为 setupContext, 有 slotsemitattrsexpose 等方法。可以返回一个函数或者对象, 返回函数作为组件的 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 的返回值有两种情况:

  1. 返回一个函数: 该函数作为组件的 render 函数。这种方式常用于组件不是以模版来表达其渲染内容的情况。如果组件以模版来表达其渲染的內容,那么 setup 函数不可以再返回函数,否则会与模版编译生成的渲染函数产生冲突。

    const Component = {
    setup(){
    return ()=>{
    return {
    type: 'div',
    children: 'hello div'
    }
    }
    }
    }
  2. 返回一个对象: 该对象中包含的数据将暴露给模版使用

    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)
}
}
});
}

四、组件更新细节