Appearance
一、属性传递(props和attrs)
先明确一下props和attrs区别:
用户在组件中声明的属性为props,用户没有声明的属性为attrs,比如:
ts
const Comp = {
// 用户声明的属性
props: {
msg: String
},
render() {
return h('div', 'hello world')
}
}
createApp(Comp, { msg: 'hello world', count:0, }).mount('#app')上面代码声明了msg属性,count属性是没有声明的属性,所以集体的props和attrs分别是
- props:
{ msg: 'hello world'} - attrs:
{ count: 0 }
二、处理props和attrs的传递
处理传递的props
ts
/**
* 创建组件实例
*/
export function createComponentInstance(vnode) {
const { type } = vnode
const instance = {
// 省略部分代码
// 将props进行标准化,不管是数组还是对象都转化为对象
propsOptions: normalizePropsOptions(type.props)
}
return instance
}packages/runtime-core/src/componentProps.ts 这个文件主要用处理props相关逻辑
ts
// componentProps.ts
export function normalizePropsOptions(props = {}) {
if(isArray(props)) {
return props.reduce((prev, cur) => {
prev[cur] = {}
return prev
}, {})
}
return props
}
/**
* 设置所有的props和attrs
*/
function setFullProps(instance, rawProps, props, attrs) {
// 拿到 propsOptions
const propsOptions = instance.propsOptions
if(rawProps) {
// 如果传递了props
for(const key in rawProps) {
if(hasOwn(propsOptions, key)) {
// 如果 propsOptions 里面有这个 key,应该放到 props 里面
props[key] = value
} else {
// 否则就是 attrs 里面的
attrs[key] = value
}
}
}
}
export function initProps(instance) {
// 初始化 props
const { vnode } = instance
// 拿到用户使用组件时传递的 props
const rawProps = vnode.props
const props = {}
const attrs = {}
setFullProps(instance, rawProps, props, attrs)
// props 是响应式的,所以需要 reactive
instance.props = reactive(props)
// attrs 不是响应式的
instance.attrs = attrs
}在component.ts中的setupComponent函数中初始化props:
ts
/**
* 初始化组件
*/
export function setupComponent(instance) {
/**
* 初始化属性
*/
const { type } = instance
// 初始化prop
initProps(instance)
if(inFunction(type.setup)) {
const setupResult = proxyRefs(type.setup(instance.props))
// 拿到setup返回状态
instance.setupState = setupResult
}
// 将render函数,绑定给instance
instance.render = type.render
}至此,props和attrs的传递就完成了。