# h 函数
在 Vue 3 的项目开发中,template 是 Vue 3 默认的写法。虽然 template 长得很像 HTML,但 Vue 其实会把 template 解析为 render 函数,之后,组件运行的时候通过 render 函数去返回虚拟 DOM,可以在 Vue Devtools 中看到组件编译之后的结果。
除了 template 之外,在某些场景下,可以直接写 render 函数来实现组件。由于 render 函数可以直接返回虚拟 DOM,因而就不再需要 template。
使用 defineComponent 定义一个组件,组件内部配置了 props 和 setup。这里的 setup 函数返回值是一个函数,就是 render 函数。render 函数返回 h 函数的执行结果,h 函数的第一个参数就是标签名,可以很方便地使用字符串拼接的方式, src/components/Heading.jsx
:
import { defineComponent, h } from 'vue';
export default defineComponent({
props: {
level: {
type: Number,
required: true,
},
},
setup(props, { slots }) {
return () => h(
`h${props.level}`, // 标签名
{}, // prop
slots.default(), // 子节点
);
}
});
在 src/pages/about.vue
中使用:
<template>
<h2>
<Heading :level="2">H2</Heading>
<Heading :level="3">H3</Heading>
</h2>
</template>
<script setup>
import Heading from '../components/Heading.jsx';
</script>
手写的 h 函数,可以处理动态性更高的场景。但是如果是复杂的场景,h 函数写起来就显得非常繁琐,需要自己把所有的属性都转变成对象。并且组件嵌套的时候,对象也会变得非常复杂。
# JSX
为了有更方便的方式去写 h 函数,可以用 JSX。JSX 来源自 React 框架。
代码语言:javascript复制const element = <h1 id="app">Hello, JSX!</h1>
这种在 JavaScript 里面写 HTML 的语法,就叫做 JSX,算是对 JavaScript 语法的一个扩展。上面的代码直接在 JavaScript 环境中运行时,会报错。JSX 的本质就是下面代码的语法糖,h 函数内部也是调用 createVnode 来返回虚拟 DOM。
代码语言:javascript复制const element = createVnode('h1',{id:"app"}, 'hello JSX');
在从 JSX 到 createVNode 函数的转化过程中,需要安装一个 JSX 插件。
代码语言:javascript复制npm install @vitejs/plugin-vue-jsx -D
在 vite.config.js
中配置:
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue(), vueJsx()],
})
改用 JSX 代替 h 函数,就可以写出更加简洁的代码:
代码语言:javascript复制import { defineComponent, h } from 'vue';
export default defineComponent({
props: {
level: {
type: Number,
required: true,
},
},
setup(props, { slots }) {
const HeadTag = `h${props.level}`;
return () => <HeadTag>{slots.default()}</HeadTag>;
}
});
使用 JSX 的本质,还是在写 JavaScript。在 Element3 组件库设计中,有很多组件需要用到 JSX,比如时间轴 Timeline、分页 Pagination、表格 Table 等等。
# JSX 和 Template
template 的语法是固定的,只有 v-if、v-for 等等语法。
JSX 只是 h 函数的一个语法糖,本质就是 JavaScript,想实现条件渲染可以用 if else,也可以用三元表达式,还可以用任意合法的 JavaScript 语法。也就是说,JSX 可以支持更动态的需求。而 template 则因为语法限制原因,不能够像 JSX 那样可以支持更动态的需求。这是 JSX 相比于 template 的一个优势。
JSX 相比于 template 还有一个优势,是可以在一个文件内返回多个组件,类似于返回多个函数一样。
实现业务需求的时候,优先使用 template,动态性要求较高的组件使用 JSX 实现,尽可能地利用 Vue 本身的性能优化。
template 由于语法固定,可以在编译层面做的优化较多,比如静态标记就真正做到了按需更新;而 JSX 由于动态性太强,只能在有限的场景下做优化,虽然性能不如 template 好,但在某些动态性要求较高的场景下,JSX 成了标配,这也是诸多组件库会使用 JSX 的主要原因。