摘要:interface VNode {type: string | Component // 元素类型props: Record // 属性children: VNode | string // 子节点key?: string | num
1.1 模板的局限(Vue2时代)
// 传统模板编译流程{{ message }} ↓ 编译 ↓function render {return _c('div', [_v(_s(message))])}痛点:
动态组件需要 特殊语法无法享受JavaScript完整的编程能力复杂逻辑需要强制拆分到模板和script两个区域1.2 虚拟DOM的革命性
interface VNode {type: string | Component // 元素类型props: Record // 属性children: VNode | string // 子节点key?: string | number // 优化标识// ...其他内部属性}设计哲学:
JavaScript对象描述DOM结构(轻量级"蓝图")通过diff算法最小化DOM操作实现跨平台渲染能力(Web/小程序/Canvas)2.1 官方定义对比
// 源码中的真实定义(vue-next/packages/runtime-core/src/vnode.ts)export const createVNode = (__DEV__ ? createVNodeWithArgsTransform : _createVNode) as typeof _createVNode// h函数是createVNode的类型重载版本export function h(type: any, props?: any, children?: any): VNode {// ...处理不同参数情况return createVNode(type, props, children)}3.1 基础元素创建
// 创建带事件监听的按钮const button = h('button', // 元素类型{class: 'btn-primary', // class绑定onClick: =>console.log('按钮点击'), // 事件监听'data-testid': 'submit-btn'// 自定义属性},'提交表单'// 文本子节点)/* 等效模板:提交表单*/3.2 组件创建模式
// 创建带props的组件import CustomInput from './CustomInput.vue'const inputField = h(CustomInput, {modelValue: '默认值','onUpdate:modelValue': (value) => {console.log('值更新:', value)}})/* 等效模板:*/3.3 动态子节点处理
// 生成列表项const todoList = h('ul', { id: 'todo-list' },todos.value.map((todo, index) => h('li', { key: todo.id, class: { completed: todo.done }}, todo.text)))/* 等效模板:{{ todo.text }}*/4.1 与Vue2的render函数对比
// Vue2的Options API写法exportdefault {render(h) {return h('div', {attrs: { id: 'box' } // 属性要放在attrs对象}, [h('span', 'Hello')])}}// Vue3的Composition API写法import { h } from'vue'exportdefault {setup {return => h('div', { id: 'box'// 属性平铺}, [h('span', 'Hello')])}}4.2 性能优化新特性
// 静态节点提升(Compile-time优化)const staticNode = h('div', { class: 'logo' }, '静态内容')export default {setup {const dynamicData = ref(0)return => [staticNode, // 复用静态VNodeh('p', dynamicData.value) // 动态节点]}}五、最佳实践指南5.1 合理选择使用场景
5.2 性能陷阱规避
// 错误示例:每次渲染都创建新数组function BadExample {return h('div', [1, 2, 3].map(n => h('span', n)) // 每次都会生成新数组)}// 正确优化:缓存静态部分const staticItems = [1, 2, 3].map(n => h('span', n))function GoodExample {return h('div', staticItems) // 复用静态节点}5.3 与JSX的配合
// 配置JSX支持(vite.config.js)import vue from'@vitejs/plugin-vue'exportdefault {plugins: [vue({jsx: true// 开启JSX支持})]}// JSX组件示例exportdefault defineComponent({setup {const count = ref(0)return => ( count.value++}>{count.value})}})来源:不秃头程序员一点号