实现组件 props 功能
- 功能
- 通过 setup 函数传递 props 属性
- 在模板中通过 this 访问 props 属性
- 不可以修改 props 属性
- 思路
- 在 mountElement 函数中拦截 props 属性
- 将 props 属性通过 el.setAttribute 设置到元素上
- 代码实现
- 页面上要实现的功能,创建完 Foo,引入就可以把 子组件不涉及 props 的文本渲染过来
js
复制代码
// exmaple/Foo.js // ✅
import {h} from '../lib/guide-mini-vue.esm.js'
export const Foo = {
render() {
return h("div", {},"foo:" + this.count)
},
setup (props) {
console.log(props.count,'count');
return {
}
}
}
js
复制代码
// example/App.js
import { h } from '../lib/guide-mini-vue.esm.js'
import { Foo } from './Foo.js'
window.self = null
export const App = {
name: 'App',
render() {
window.self = this
return h("div",{
id: 'root',
class: ['red', 'hard'],
},
[h("p",{class:"red"}, "hi"),h(Foo,{count: 1})] // ✅
)
},
setup() {
return {
msg: "mini-vue-haha",
}
}
}
js
复制代码
// runtime-core/component.ts
import { shallowReadonly } from "../reactivity/reactive"
import { initProps } from "./componentProps"
export function setupComponent(instance) {
initProps(instance, instance.vnode.props) // ✅ 将props挂载到实例上
setupStatefulComponents(instance)
}
function setupStatefulComponents(instance: any) {
const Component = instance.vnode.type
const { setup } = Component
instance.proxy = new Proxy({_: instance}, PublicInstanceProxyHandlers)
if(setup) {
// ✅ 将props传递到 setup 函数, 此时控制台已经能够打印出 props的值 在 Foo.js 中
// ✅ 这里的 shallowReadonly 做了容错处理,具体在下面
const setupResult = setup(shallowReadonly(instance.props))
handleSetupResult(instance, setupResult)
}
}
js
复制代码
// runtime-core/componentProps.ts
export function initProps(instance, rawProps) {
instance.props = rawProps || {} // ✅ 这里是做了兼容性处理,如果不做,在获取 value 时,会因为 props 为空而报错,要知道不是每个组件都有给子组件传递 props 属性
}
js
复制代码
// runtime-core/ componentPublicInstance.ts
import { hasOwn } from "../shared/index" // ✅
const publicPropertiesMap = {
$el:(i)=>i.vnode.el
}
export const PublicInstanceProxyHandlers = {
get({_: instance}, key) {
let { setupState, props } = instance
if(hasOwn(setupState,key)) {
return setupState[key]
} else if(hasOwn(props, key)) { // ✅ 判断访问的 key 是否在 props 上,如果在就返回属性值,此时页面已经可以渲染到 props
return props[key] // ✅
}
const publicGetter = publicPropertiesMap[key]
if(publicGetter) {
return publicGetter(instance)
}
}
}
js
复制代码
// reactive/reactive.ts
function createReactiveObject(target, baseHandlers) {
if(!isObject(target)) { // ✅ 这是 shallowReadonly 做的容错处理
console.warn(`target ${target} 必须是一个对象`)
return target
}
return new Proxy(target, baseHandlers)
}
js
复制代码
export const hasOwn = (val, key) => { // ✅
if(!val) {
return false
}
return Object.prototype.hasOwnProperty.call(val, key)
}