10.1 Render函数核心原理
10.1.1 虚拟节点创建过程
// 手动编写Render函数示例
new Vue({
render(h) {
return h('div',
{ attrs: { id: 'app' } },
[
h('span', { class: 'text' }, this.message),
h('button', {
on: { click: this.handleClick }
}, 'Click me')
]
)
}
})
// 对应的虚拟DOM结构
{
tag: 'div',
data: { attrs: { id: 'app' } },
children: [
{
tag: 'span',
data: { class: 'text' },
text: 'Hello'
},
{
tag: 'button',
data: { on: { click: handleClick } },
text: 'Click me'
}
]
}
核心参数解析:
h
函数:createElement的别名- 参数结构:
h(tag, data, children)
- 数据对象规范:
{ class: { active: isActive }, style: { color: 'red' }, attrs: { id: 'foo' }, domProps: { innerHTML: '...' }, on: { click: handler }, key: 'uniqueKey' }
10.1.2 与模板编译的关系
// 模板代码
<template>
<div :class="{ active: isActive }">
<span>{{ message }}</span>
</div>
</template>
// 编译后的Render函数
function render() {
return _c('div', {
class: { active: this.isActive }
}, [
_c('span', [_v(_s(this.message))])
])
}
编译转换规则:
- 标签 →
_c(tag)
- 插值 →
_v(_s(value))
- 指令 → 转换为数据对象属性
- 事件 →
on: { eventName: handler }
10.2 JSX在Vue中的应用
10.2.1 Babel转换原理
// JSX代码
const list = items.map(item =>
<li key={item.id}>{item.text}</li>
)
// 转换后的代码
const list = items.map(item =>
h('li', { key: item.id }, [item.text])
)
// Babel配置示例
{
"plugins": [
["@vue/babel-plugin-transform-vue-jsx", {
"injectH": false // 是否自动注入h函数
}]
]
}
10.2.2 与React JSX的差异
特性 | Vue JSX | React JSX |
---|---|---|
事件处理 | onClick → on: { click } | 原生事件名 |
样式处理 | style 自动前缀 | 需要手动处理 |
插值语法 | 单括号{} | 同左 |
组件引用 | 需注册后使用 | 直接引用 |
指令支持 | 需转换为JSX语法 | 无指令系统 |
10.3 动态组件实现模式
10.3.1 组件工厂模式
components: {
TextComponent: { /*...*/ },
ImageComponent: { /*...*/ }
},
render(h) {
const componentType = this.type + 'Component'
return h(this.$options.components[componentType], {
props: this.$props
})
}
10.3.2 动态插槽处理
render(h) {
// 动态生成具名插槽
const slots = Object.keys(this.$slots)
.map(name => h('template', { slot: name }, this.$slots[name]))
return h('dynamic-component', {
scopedSlots: {
default: props => h('span', props.text)
}
}, slots)
}
10.4 性能优化技巧
10.4.1 静态节点提升
// 手动优化前
render(h) {
return h('div', [
h('header', [/* 复杂结构 */]),
h('main', this.dynamicContent)
])
}
// 优化后:缓存静态部分
const staticHeader = h('header', [/* 复杂结构 */])
render(h) {
return h('div', [
staticHeader, // 复用静态VNode
h('main', this.dynamicContent)
])
}
10.4.2 避免重复渲染
// 通过shouldUpdate钩子优化
export default {
data() {
return { updateFlag: false }
},
methods: {
forceUpdate() {
this.updateFlag = !this.updateFlag
}
},
render(h) {
return h(HeavyComponent, {
key: this.updateFlag // 强制重新渲染
})
}
}
10.5 高级模式实践
10.5.1 递归组件实现
// 树形组件示例
const TreeNode = {
name: 'TreeNode',
props: ['data'],
render(h) {
const children = this.data.children || []
return h('div', [
h('span', this.data.name),
children.length > 0 &&
h('div', children.map(child =>
h(TreeNode, { props: { data: child } })
)
])
}
}
10.5.2 高阶组件封装
function withLoading(WrappedComponent) {
return {
data() {
return { loading: false }
},
render(h) {
return h('div', [
this.loading
? h('div', 'Loading...')
: h(WrappedComponent, {
props: this.$props,
on: this.$listeners
})
])
}
}
}
本章重点总结:
- 灵活渲染:掌握手动控制虚拟DOM生成的能力
- JSX集成:理解Vue的JSX转换机制
- 性能模式:优化动态组件渲染性能
- 高级实践:实现复杂组件模式
深度实践建议:
- 将现有模板组件改写成Render函数形式
- 使用Chrome Performance对比不同实现方式的性能
- 实现包含条件分支和循环的复杂Render函数
// 调试建议:观察VNode结构
const vnode = vm.$options.render.call(vm, vm.$createElement)
console.log('生成的VNode:', vnode)