Vue 渲染体系“三件套”(template 模板语法、h 函数和 JSX 语法)

前言

不管你写 template、h() 还是 JSX,最后都会变成 VNode → patch → DOM

一、template 模板语法------ 最常用、最友好

特点:

  • 面向业务开发
  • 声明式
  • 会被编译成 render 函数

1、插值表达式

typescript 复制代码
<div>{{ message }}</div>

数据变化 → 自动更新 DOM

2、指令系统(Vue 模板核心)

指令 作用
v-bind 绑定属性
v-on 绑定事件
v-if / v-else 条件渲染
v-for 列表渲染
v-model 双向绑定
v-slot 插槽
typescript 复制代码
<button @click="add">+1</button>
<img :src="imgUrl" />
<li v-for="item in list" :key="item.id">{{ item.name }}</li>

3、组件 & 插槽

typescript 复制代码
<MyCard title="标题">
  <template #default>
    内容
  </template>
</MyCard>

本质:

  • 模板不会直接操作 DOM,而是被编译成:
typescript 复制代码
render() {
  return h('div', message)
}

4、简单示例

typescript 复制代码
<script setup>
import { ref } from 'vue'

const count = ref(0)
const add = () => count.value++
</script>

<template>
  <div class="box">
    <p>Count: {{ count }}</p>
    <button @click="add">+1</button>
  </div>
</template>

二、h() 函数------ 虚拟 DOM 的直接写法

特点:

  • render 函数的核心
  • 手写虚拟 DOM
  • 所有模板最终都会变成 h()

基本格式:

typescript 复制代码
h(type, props, children)

1、普通元素

typescript 复制代码
h('div', { class: 'box' }, 'Hello')

2、子节点数组

typescript 复制代码
h('ul', null, [
  h('li', null, 'A'),
  h('li', null, 'B')
])

3、事件绑定

typescript 复制代码
h('button', { onClick: this.add }, 'Add')

4、渲染组件

typescript 复制代码
h(MyCard, { title: '标题' }, {
  default: () => h('span', '内容')
})

本质:

  • h() 返回 VNode 对象
typescript 复制代码
{
  type: 'div',
  props: { class: 'box' },
  children: 'Hello'
}

然后进入:

typescript 复制代码
patch(oldVNode, newVNode)

5、简单示例

typescript 复制代码
import { h, ref } from 'vue'

export default {
  setup() {
    const count = ref(0)
    const add = () => count.value++

    return () =>
      h('div', { class: 'box' }, [
        h('p', null, 'Count: ' + count.value),
        h('button', { onClick: add }, '+1')
      ])
  }
}

三、JSX 语法------ 更自由的"类模板语法"

特点:

  • 本质是 h() 的语法糖
  • JS 表达能力更强
  • 适合复杂动态结构

1、JSX 写法

typescript 复制代码
return <div class="box">{msg}</div>

编译后:

typescript 复制代码
h('div', { class: 'box' }, msg)

2、条件渲染

typescript 复制代码
return count > 0
  ? <span>正数</span>
  : <span>负数</span>

3、列表渲染

typescript 复制代码
return (
  <ul>
    {list.map(item => <li key={item.id}>{item.name}</li>)}
  </ul>
)

4、插槽

typescript 复制代码
return <MyCard v-slots={{
  default: () => <span>内容</span>
}} />

5、简单示例

typescript 复制代码
import { ref } from 'vue'

export default {
  setup() {
    const count = ref(0)
    const add = () => count.value++

    return () => (
      <div class="box">
        <p>Count: {count.value}</p>
        <button onClick={add}>+1</button>
      </div>
    )
  }
}

四、三者关系总结

typescript 复制代码
Template  → 编译 → render 函数 → h()
JSX       → 编译 → h()
h()       → 生成 VNode
VNode     → patch → 真实 DOM

它们只是"写法不同",底层渲染机制完全一样。

  • Template 最好写,h() 最底层,JSX 最灵活;
  • 三者最终都会变成 h() 创建的 VNode,再由 Vue 的 patch 机制更新真实 DOM。
相关推荐
SuperEugene3 小时前
表单最佳实践:从 v-model 到自定义表单组件(含校验)
前端·javascript·vue.js
我叫黑大帅8 小时前
Vue3和Uniapp的爱恨情仇:小白也能懂的跨端秘籍
前端·javascript·vue.js
洋洋技术笔记9 小时前
Vue实例与数据绑定
前端·vue.js
牛奶20 小时前
Vue 基础理论 & API 使用
前端·vue.js·面试
牛奶20 小时前
Vue 底层原理 & 新特性
前端·vue.js·面试
pe7er20 小时前
状态提升:前端开发中的状态管理的设计思想
前端·vue.js·react.js
_AaronWong1 天前
Electron 实现仿豆包划词取词功能:从 AI 生成到落地踩坑记
前端·javascript·vue.js
wuhen_n1 天前
双端 Diff 算法详解
前端·javascript·vue.js
爱勇宝1 天前
别再混用了!import.meta.env 与 process.env 的本质差异一次讲透
前端·javascript·vue.js
从文处安2 天前
「九九八十一难」组合式函数到底有什么用?
前端·vue.js