告别繁琐template!Vue3 JSX让动态组件开发更丝滑
在Vue开发的日常中,你是否也曾被template的固定语法束缚?想实现动态标签渲染却要写一堆v-if?想做高度动态的组件逻辑却被template的语法限制住?
其实Vue3早就为我们准备了更灵活的方案——JSX。它不是React的专属,在Vue3中,JSX能完美弥补template的灵活性短板,让我们在复杂场景下写组件更丝滑。这篇文章就带你从底层原理到实战落地,彻底搞懂Vue3的JSX!
一、先搞懂:为什么需要JSX?(h函数铺垫)
在聊JSX之前,必须先提h函数——因为JSX的本质就是h函数的语法糖。
1. template的局限性
先看一个简单需求:根据传入的数字(1-6),动态渲染h1~h6标签。如果用template实现,只能写一堆冗余的v-if:
<template>
<h1 v-if="level===1">{{ title }}</h1>
<h2 v-if="level===2">{{ title }}</h2>
<h3 v-if="level===3">{{ title }}</h3>
<!– … 还要写h4/h5/h6 –>
</template>
这种写法不仅冗余,而且动态性极差——如果后续要扩展更多动态逻辑,template会变得难以维护。
2. h函数:手写虚拟DOM
Vue3中,template最终会被编译成render函数,而render函数的核心是通过h函数创建虚拟DOM(VNode)。我们可以直接手写h函数,摆脱template的束缚:
新建Heading.jsx(注意后缀是jsx):
import { defineComponent, h } from 'vue'
export default defineComponent({
props: {
level: {
type: Number,
required: true
}
},
setup(props, { slots }) {
// render函数返回h函数的执行结果
return () => h(
'h' + props.level, // 动态拼接标签名
{}, // 属性/Props
slots.default() // 子节点(插槽)
)
}
})
使用时只需要传一个level参数:
<template>
<Heading :level="3">Hello Vue3 JSX</Heading>
</template>
<script setup>
import Heading from './components/Heading.jsx'
</script>
h函数完美解决了动态标签的问题,但问题来了:复杂场景下h函数写起来太繁琐——嵌套组件时要层层嵌套对象,属性也要手动组装,可读性和开发效率都很低。
这时候,JSX就该登场了!
二、JSX核心:h函数的“语法糖”
1. 什么是JSX?
JSX是“在JavaScript中写HTML”的语法扩展,比如:
const element = <h1 id="app">Hello, Geekbang!</h1>
这段代码看起来像HTML,但本质是下面这段代码的语法糖:
const element = createVnode('h1',{id:"app"}, 'Hello, Geekbang!')
而createVnode正是h函数的核心逻辑——所以JSX最终还是会被解析成h函数执行,既保留了JavaScript的动态性,又拥有HTML的直观写法。
2. Vue3中配置JSX(Vite环境)
要在Vue3中用JSX,需要先安装插件并配置:
步骤1:安装依赖
npm install @vitejs/plugin-vue-jsx -D
步骤2:修改vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx';
export default defineConfig({
plugins: [vue(), vueJsx()] // 注册JSX插件
})
3. 用JSX改写h函数示例
回到前面的Heading组件,用JSX改写后,代码更简洁直观:
import { defineComponent } from 'vue'
export default defineComponent({
props: {
level: {
type: Number,
required: true
}
},
setup(props, { slots }) {
const tag = 'h' + props.level
// 直接写JSX,替代繁琐的h函数调用
return () => <tag>{slots.default()}</tag>
}
})
是不是瞬间清爽了?这就是JSX的核心价值——用更直观的语法,实现h函数的动态能力。
三、Vue3 JSX实战语法要点
JSX的本质是JavaScript,所以能兼容所有JS语法,同时也有一些和template的语法差异,这里整理了核心实战要点:
1. 基础语法对比(template → JSX)
| 双向绑定 | v-model="title" | vModel={title.value} |
| 事件绑定 | @click="handleClick" | onClick={handleClick} |
| 条件渲染 | v-if/v-else | 三元表达式/if-else |
| 列表渲染 | v-for="item in list" | list.map(item => {}) |
2. 实战示例:用JSX实现待办清单
新建Todo.jsx,实现一个简单的待办清单,感受JSX的灵活性:
import { defineComponent, ref } from 'vue'
export default defineComponent({
setup(props) {
// 响应式数据
let title = ref('')
let todos = ref([
{ title: "学习 Vue3 JSX", done: true },
{ title: "手写h函数", done: false }
]);
// 新增待办
function addTodo() {
if (!title.value) return
todos.value.push({ title: title.value })
title.value = ''
}
// 返回JSX结构
return () => (
<div class="todo-container">
<input
type="text"
vModel={title.value}
placeholder="请输入待办事项"
/>
<button onClick={addTodo}>添加</button>
<ul class="todo-list">
{
// 列表渲染 + 条件判断
todos.value.length
? todos.value.map((todo, index) => (
<li key={index}>{todo.title}</li>
))
: <li>暂无待办事项</li>
}
</ul>
</div>
)
}
})
在Vue文件中引入使用:
<template>
<Todo />
</template>
<script setup>
import Todo from './components/Todo.jsx'
</script>
3. 高级场景:组件库级别的动态逻辑
在组件库开发中(比如Element3),JSX的动态性优势更明显。比如时间轴(Timeline)组件的“倒序渲染”需求:
export const Timeline = (props) => {
const timeline = [
<div class="timeline-item">8.21 开始学习Vue3</div>,
<div class="timeline-item">10.18 掌握JSX用法</div>
]
// 根据props动态反转数组,实现倒序
if (props.reverse) {
timeline.reverse()
}
return <div class="timeline">{timeline}</div>
}
这种“直接操作JS数组实现DOM逻辑”的场景,用template很难优雅实现,而JSX可以轻松搞定。
四、JSX vs Template:该怎么选?
很多同学会纠结:到底该用JSX还是template?核心原则是**“按场景选型”**:
1. Template的优势
- 编译优化更强:Vue对template做了大量编译期优化(比如静态节点提升、动态节点标记),静态内容会被缓存,Diff算法会跳过静态节点,性能更高;
- 语法更规范:固定的v-if/v-for等语法,团队协作成本低;
- 更贴近HTML:适合大部分常规业务场景(比如表单、列表展示)。
2. JSX的优势
- 动态性极强:支持所有JavaScript语法,适合“标签动态、逻辑复杂”的场景(比如动态标签、组件库开发);
- 灵活性更高:一个文件可以导出多个组件,无需拆分多个.vue文件;
- 逻辑内聚:JS逻辑和DOM结构写在一起,适合复杂交互的组件。
3. 选型建议
- 优先用template:常规业务页面(比如列表、表单、详情页)用template,享受Vue的编译优化;
- 按需用JSX:动态标签、复杂逻辑组件(比如自定义表单、组件库组件)用JSX,解决template的灵活性不足问题。
五、总结
Vue3的JSX不是“替代template”,而是“补充template”——它让Vue的组件开发能力更完整:
最后留一个思考题:你在实际项目中,遇到过哪些template难以实现、但用JSX能轻松搞定的场景?欢迎在评论区交流~
拓展资料
- Vue3官方文档:渲染函数 & JSX
- Vue JSX插件文档:@vue/babel-plugin-jsx





