Vue.js 3 - render函数、h函数、JSX语法使用详解
作者:hangge | 2026-08-25 09:14
在 Vue.js 3 中,除了我们熟悉的模板语法(template),还有一种更底层、更灵活的方式来构建界面:render 函数。配合 h 函数和 JSX 语法,开发者可以像写 JavaScript 一样精确地控制虚拟 DOM 的生成。
(2)运行效果如下:
(2)运行效果如下:
(2)运行在浏览器中的效果和上面的案例一样:
(2)下面是使用这个 HelloWorld.vue 组件的样例代码,同样使用 render 函数进行渲染:
(2)运行效果如下:
(2)接着我们在父组件中导入 HellWorld.vue 组件,然后在 render 函数的 JSX 模板中使用该组件。
(3)运行效果如下:
提示: 实际上,我们在模板中编写的 HTML 最终也会通过渲染函数生成对应的 VNode。如果想充分利用 JavaScript 编程的灵活性,那么可以在 render 函数中使用 createVNode 函数生成对应的 VNode。多个 VNode 组合在一起,就形成了一棵树形结构,即虚拟 DOM。
1,h 函数介绍
(1)在 Vue.js 3 中,我们可以在 render 函数中使用 createVNode 函数生成对应的 VNode。为了简便,Vue.js 3 将 createVNode 函数简化为 h 函数,所以 h 函数是一个用于创建 VNode 的函数。
(2)h 函数包含三个参数:
- 参数一(必需):可以接收一个 HTML 标签名、组件、异步组件或函数式组件。 支持类型:{String|Object|Function}tag。
- 参数二(可选):一个与 attribute、prop 和事件相对应的对象,会在模板中用到。 支持类型:{Object}props。
- 参数三(可选):接收子 VNodes,使用 h 函数构建,也可以使用字符串获取“文本 VNode”或有插槽的对象。支持类型:{String|Array|Object}children。
注意:如果没有参数二(props),那么通常可以将 children 作为参数二传入。为了避免产生歧义,可以将 null 作为参数二传入,将 children 作为参数三传入。
2,h 函数基本用法
(1)h 函数可以在 render 函数和 setup 函数中使用。下面先演示在 render 函数中使用:
<script>
import { h } from 'vue'; // 导入h函数
export default {
render() { // render函数
return h("h4", { class: "title" }, "欢迎访问hangge.com")
}
}
</script>
<style scoped>
.title {
text-decoration: underline;
}
</style>
- 上面代码等价于下面使用模板的方式:
<template>
<h4 class="title">欢迎访问hangge.com</h4>
</template>
<script>
export default {
}
</script>
<style scoped>
.title {
text-decoration: underline;
}
</style>
(2)运行效果如下:

3,render 函数实现计数器
(1)下面使用 render 函数实现一个复杂一些计数器样例:
- 首先在 data 中定义 counter 变量。
- 接着在 render 函数中使用 h 函数构建一个 <div> 元素,其中包含一个 <h4> 元素和两个 <button> 元素的计数器案例页面,在 render 函数中也可以直接通过 this 访问到组件的实例。
<script>
import { h } from 'vue'; // 导入h函数
export default {
data() {
return { counter: 0 }
},
render() {
// div标签中包含:一个h4元素和2个button元素
return h("div", { class: "render-counter" }, [
h("h4", null, `当前计数: ${this.counter}`),
h("button", {
onClick: () => this.counter++
}, "+1"),
h("button", {
onClick: () => this.counter--
}, "-1"),
])
}
}
</script>
(2)运行效果如下:

4,setup 函数实现计数器
(1)上面样例使用 render 函数实现的计数器用的是 OptionsAPI 语法,如果想要使用 Composition API 语法实现计数器,那么可以在 setup 函数中编写代码。 代码如下:
- 首先使用 ref 定义响应式变量。
- 接着在 setup 函数中返回 render 函数。
<script>
import { ref, h } from 'vue';
export default {
setup() {
const counter = ref(0); // 定义变量
// setup函数返回一个render函数, 该函数可以直接使用在同一作用域中声明的响应式状态
return () => {
return h("div", { class: "app" }, [
h("h2", null, `当前计数: ${counter.value}`),
h("button", {
onClick: () => counter.value++
}, "+1"),
h("button", {
onClick: () => counter.value--
}, "-1"),
])
}
}
}
</script>
(2)运行在浏览器中的效果和上面的案例一样:

5,在 render 函数中实现插槽
(1)在使用 render 函数构建页面时,如果组件中需要添加插槽,那么可以使用 this.$slots 来实现。首先我们创建一个 HelloWorld.vue 组件代码如下,可以看到,在 render 函数中使用 this.$slots.default 判断父组件是否传递了 default 默认插函数:
- 如果有传递,那么调用 default 默认插槽函数,并传递一个对象给该函数作为参数。
- 如果父组件没有传递 default 默认插槽函数,那么使用插槽的默认值,即显示一个 <span> 元素。
<script>
import { h } from "vue";
export default {
render() {
// 等价于:
// <div>
// <h4>HelloWorld组件</h4>
// <slot name="default">
// <span>插槽默认值</span>
// </slot>
// </div>
return h("div", { class: "hello-world" }, [
h("h4", null, "HelloWorld组件"),
// 定了一个默认的插槽
this.$slots.default ? this.$slots.default({ name: "hangge" }) : h("span", null, "插槽默认值")
])
}
}
</script>
<style scoped>
.hello-world {
border: 1px solid #ddd;
margin: 8px;
}
</style>
(2)下面是使用这个 HelloWorld.vue 组件的样例代码,同样使用 render 函数进行渲染:
- 首先,在该组件中导入 HelloWorld.vue 组件。
- 接着,在 render 函数中的 h 函数里使用该组件。
- 最后,为该组件传递 default 默认插槽函数,该函数返回的内容会替换掉 HelloWorld.vue 组件中定义的默认插槽,该函数的 props 参数中可以接收 HelloWorld.vue 组件中的插槽传递过来的参数。
<script>
import { h } from 'vue';
import HelloWorld from './HelloWorld.vue'; // 1.导入HelloWorld组件
export default {
// 等价于:
// <div class="render-slot">
// RenderSlot组件
// <HelloWorld>
// <template v-slot:default="slotProps">
// <span>传入HelloWorld插槽中的内容。插槽props的name: {{slotProps.name}}</span>
// </template>
// </HelloWorld>
// </div>
render() {
return h("div", { class: "render-slot" }, [
'RenderSlot组件',
// 2.使用HelloWorld组件
h(HelloWorld, null, {
// 3.使用HelloWorld组件定义的默认插槽。props是:插槽props
default: props => h("span", null,
`传入HelloWorld插槽中的内容。插槽props的name:${props.name}`)
})
])
}
}
</script>
<style scoped>
.render-slot {
border: 1px solid #ddd;
margin: 8px;
}
</style>
附:组件的 JSX 语法
1,基本介绍
(1)在 Vue.js 3 中,虽然可以使用 h 函数构建组件的布局,但是其编写效率非常低,并且不利于阅读和后期维护。
(2)为了解决这个问题,Vue.js 3 支持使用 JSX 语法编写组件,该语法更接近于模板语法。JSX 语法实际上是一种允许在 JavaScript 中编写 HTML 元素的语法糖。
提示:为了将 JSX 语法编写的模板转换成 h 函数的写法,Vue.js 3 底层需要借助 Babel 插件(@yue/babel-plugin-jsx)。该插件已经被集成并安装在 Vue CLI 脚手架中,因此可以在 Vue.js3 的单文件组件中直接编写 JSX 语法。
2,计数器样例
(1)下面样例在 render 函数中使用 JSX 语法编写计数器案例的模板。可以看到,相比于 h 函数编写的计数器案例,JSX 语法更接近于模板的语法,也便于阅读和后期维护。
提示:在编写 JSX 语法时, 一般使用一个括号来包裹 JSX 编写的模板,这样既可以提高代码的可读性,也能使代码更美观。
<script lang="jsx">
export default {
data() {
return { counter: 0 }
},
render() {
// 下面的方法也可以写到 methods 选项中
const increment = () => this.counter++;
const decrement = () => this.counter--;
return (
<div class="app" style="border:1px solid #ddd;padding:4px">
<h4>当前计数: {this.counter}</h4>
<button onClick={increment}>+1</button>
<button onClick={decrement}>-1</button>
</div>
)
}
}
</script>
(2)运行效果如下:

3,插槽样例
(1)JSX 语法不仅支持编写 HTML 元素,还支持编写 Vue.js 组件。首先我们新建一个名为 HelloWorld.vue 的组件,代码如下:
- 首先在该组件的 render 函数中使用 JSX 语法编写模板。
- 然后在该组件中定义个默认的插槽。
<script lang="jsx">
export default {
render() {
return (
<div style="border:1px solid #ddd;margin:8px">
<div>HelloWorld组件</div>
{/**这里编写的是注释:定义default插槽*/}
{this.$slots.default ? this.$slots.default() : <span>插槽默认内容</span>}
</div>
)
}
}
</script>
(2)接着我们在父组件中导入 HellWorld.vue 组件,然后在 render 函数的 JSX 模板中使用该组件。
<script lang="jsx">
import HelloWorld from './HelloWorld.vue';
export default {
render() {
return (
<HelloWorld />
)
}
}
</script>
(3)运行效果如下:

全部评论(0)