在日常 Vue 项目中,你可能已经非常熟悉 template 写法:结构清晰、语义明确、直观易读。但当业务进入更复杂的阶段,你会发现:
- 模板语法存在一定限制
- 某些 UI 渲染逻辑十分动态
- 条件/循环/组件嵌套变得越来越难写
- h 函数(
createVNode)看得懂,但自己写非常痛苦
这时,你可能会想:有没有一种方式既能保持 DOM 结构的直观性,又能充分利用 JavaScript 的灵活表达?
答案是:JSX。
你可能会问:JSX 不是 React 的东西吗?
是,但 Vue 同样支持 JSX,并且在组件库、动态 UI 控件、高度抽象组件中大量使用。
本文将从三个核心问题带你理解 Vue 中的 JSX:
- JSX 的本质是什么?
- 为什么需要 JSX,它能解决什么问题?
- 在 Vue 中如何优雅地使用 JSX?
h 函数:理解 JSX 的前置知识
Vue 组件的 template 最终会被编译为一个 render 函数 ,render 函数会返回 虚拟 DOM(VNode) 。
也就是说,下面这段模板:
css
<h3>你好</h3>
最终会变成类似这样的 JavaScript:
csharp
h('h3', null, '你好')
也就是说:
h 函数 = 手写虚拟 DOM 的入口
JSX = h 函数的语法糖
为什么需要 JSX?来看一个真实例子
假设我们做一个动态标题组件 <Heading />,它根据 level 动态渲染 <h1> ~ <h6>:
如果使用 template,你可能写成这样:
xml
<h1 v-if="level === 1"><slot /></h1>
<h2 v-else-if="level === 2"><slot /></h2>
...
<h6 v-else-if="level === 6"><slot /></h6>
非常冗余、难拓展、维护成本高。
使用 h 函数可以简化为:
javascript
import { h, defineComponent } from 'vue'
export default defineComponent({
props: { level: Number },
setup(props, { slots }) {
return () => h('h' + props.level, {}, slots.default())
}
})
但写 h 函数并不优雅,标签、属性、事件都要自己构造。
这时 JSX 就来了。
在 Vue 中使用 JSX
① 安装 JSX 插件(Vite 项目)
bash
npm install @vitejs/plugin-vue-jsx -D
② 在 vite.config.js 中启用
javascript
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'
export default {
plugins: [vue(), vueJsx()]
}
③ 使用 JSX 改写 Heading 组件
javascript
import { defineComponent } from 'vue'
export default defineComponent({
props: { level: Number },
setup(props, { slots }) {
const Tag = 'h' + props.level
return () => <Tag>{slots.default()}</Tag>
}
})
是不是比手写 h 爽太多了?
结构依然直观,但不受 template 语法局限。
JSX 的核心能力:灵活、动态、纯 JavaScript
举个再明显的例子:Todo 列表
javascript
import { defineComponent, ref } from 'vue'
export default defineComponent({
setup() {
const title = ref('')
const todos = ref([])
const addTodo = () => {
if (title.value.trim()) {
todos.value.push({ title: title.value })
title.value = ''
}
}
return () => (
<div>
<input vModel={title.value} />
<button onClick={addTodo}>添加</button>
<ul>
{todos.value.length
? todos.value.map(t => <li>{t.title}</li>)
: <li>暂无数据</li>}
</ul>
</div>
)
}
})
可以看到:
| 模板语法 | JSX 对应写法 |
|---|---|
v-model |
vModel={value} |
@click |
onClick={fn} |
v-for |
array.map() |
v-if |
三元 / if 表达式 |
本质是 JavaScript,可以随意写逻辑。
JSX vs Template:应该如何选择?
| 对比点 | template | JSX |
|---|---|---|
| 可读性 | 强,结构清晰 | 视业务复杂度而定 |
| 动态表达能力 | 较弱(语法受限) | 非常强(JS 语法全支持) |
| 编译优化 | 优秀,可静态提升 | 不如 template 友好 |
| 适用场景 | 普通业务 UI | 高动态逻辑、组件库、渲染函数场景 |
一句话总结选择策略:
业务组件优先 template ,
高动态组件或组件库优先 JSX。
JSX 并不是来替代 template 的,而是:
当 template 无法优雅表达渲染逻辑时,JSX 给你打开了一扇窗。
- 它让组件变得更灵活
- 它让写 render 函数变得不再痛苦
- 它让 Vue 在复杂组件抽象层面更加强大
掌握 JSX,是从"会写 Vue"向"会设计 Vue 组件"的关键一步。