目录
2. createVNode()、render()
2.1 初步使用 createVNode()、render()
2.2 h 函数源码分析
3. 使用 h 函数的几种方法
3.1 h 函数 接收的参数
3.2 h 函数 使用方法
4.1 使用 props 接收传入组件的参数
4.2 使用 emit 向组件外发送事件
4.3 使用 ctx.slots.default() 在组件内定义插槽
5. 参考视频
template 模板
JSX(类似 React)
函数式编程(h 函数)
Vue3 插件当时也涉及到了 createVNode()、render()
h 函数本质上是用了 Vue 内置函数 —— createVNode()、render() 实现的
我在 ElementPlus 实验室里试了一下:
createVNode —— 创建虚拟 DOM:
render —— 渲染虚拟 DOM:
完整测试代码:
结果如下,可以看到,我给 div 添加的 id、innerHTML,在虚拟 DOM 中都体现了
位置:packages\runtime-core\src\h.ts
打开后,可以看到作者贴心的加了一段注释:
// “h” 是 “createVNode” 的用户友好的版本,适用于手动编写的渲染函数
// 编译器生成的代码使用 “createVNode”,因为
// 1.它是单态的,避免了额外的呼叫开销
// 2.它允许为优化指定 patchFlags// 没有 props 的命名槽,需要显式 “null” 以避免歧义
可以看到最后的 h 函数方法中,一直在使用 createVNode()
import {
VNode,
VNodeProps,
createVNode,
VNodeArrayChildren,
Fragment,
Text,
Comment,
isVNode
} from './vnode'
...
...
...
// “h” 是 “createVNode” 的用户友好的版本,适用于手动编写的渲染函数
// 编译器生成的代码使用 “createVNode”,因为
// 1.它是单态的,避免了额外的呼叫开销
// 2.它允许为优化指定 patchFlags
/*
// type only
h('div')
// type + props
h('div', {})
// type + omit props + children
// Omit props does NOT support named slots
h('div', []) // array
h('div', 'foo') // text
h('div', h('br')) // vnode
h(Component, () => {}) // default slot
// type + props + children
h('div', {}, []) // array
h('div', {}, 'foo') // text
h('div', {}, h('br')) // vnode
h(Component, {}, () => {}) // default slot
h(Component, {}, {}) // named slots
// 没有 props 的命名槽,需要显式 “null” 以避免歧义
h(Component, null, {})
**/
...
...
...
// Actual implementation
export function h(type: any, propsOrChildren?: any, children?: any): VNode {
const l = arguments.length
if (l === 2) {
if (isObject(propsOrChildren) && !isArray(propsOrChildren)) {
// single vnode without props
if (isVNode(propsOrChildren)) {
return createVNode(type, null, [propsOrChildren])
}
// props without children
return createVNode(type, propsOrChildren)
} else {
// omit props
return createVNode(type, null, propsOrChildren)
}
} else {
if (l > 3) {
children = Array.prototype.slice.call(arguments, 2)
} else if (l === 3 && isVNode(children)) {
children = [children]
}
return createVNode(type, propsOrChildren, children)
}
}
除类型 type 之外,所有参数都是可选的
// 除类型之外的所有参数都是可选的
h('div')
h('div', { id: 'foo' })
// 属性和内容,都可以在第二个参数中使用
// Vue 会自动选择正确的分配方式
h('div', { class: 'bar', innerHTML: 'hello' })
// 可以添加 .prop 和 .attr 等修饰符
// 分别带有 “.” 和 “^” 前缀
h('div', { '.name': 'some-name', '^width': '100' })
// class、style 可以是对象,也可以是数组
h('div', { class: [foo, { bar }], style: { color: 'red' } })
// 定义事件需要加 on,如 onXxx
h('div', { onClick: () => {} })
// 子集可以是字符串
h('div', { id: 'foo' }, 'hello')
// 如果没有props,可以省略 props
h('div', 'hello')
h('div', [h('span', 'hello')])
// 子数组可以包含混合的 VNode 和 字符串
h('div', ['hello', h('span', 'hello')])
定义一个箭头函数,该函数返回一个 h 函数
箭头函数默认接收两个参数 props、ctx,就跟 setup 接收的两个参数作用一样
再来回忆下:
emit 添加事件的时候,一定要带上 on 前缀
Lyrelion-slots
小满Vue3(第三十八章 函数式编程,h函数)_哔哩哔哩_bilibili小满Vue3(第三十八章 函数式编程,h函数)是Vue3 + vite + Ts + pinia + 实战 + 源码 +electron的第50集视频,该合集共计110集,视频收藏或关注UP主,及时了解更多相关视频内容。https://www.bilibili.com/video/BV1dS4y1y7vd?p=50&vd_source=8bc01635b95dbe8ecd349b2c23b03a10