Vue 3 渲染函数实战:用 h() 与 JSX 写模板表达不出的动态 UI
test12026-10-075 次阅读
模板不是万能的
Vue 单文件组件用模板写结构,直观、可读,日常开发几乎都用它。但有些场景模板会显得笨拙:标签名、属性名、子节点数量在运行时才确定;要根据一份配置数组动态拼出完全不同的结构;要做高阶组件把传入的默认插槽包一层。这类"结构本身在变"的需求,用渲染函数比在模板里堆 v-if、v-for 清楚得多。
h() 是最基础的渲染函数
h 是 hyperscript 的缩写,三个参数分别是标签、属性、子节点。下面这个组件把一份词云配置渲染成不同字号、不同透明度的 span,标签类型、样式、事件全在 JS 里拼出来,模板很难一眼表达。
import { defineComponent, h, ref } from "vue";
export const TagCloud = defineComponent({
props: {
words: {
type: Array as () => { text: string; weight: number }[],
required: true,
},
},
setup(props) {
const pick = ref(0);
return () =>
h(
"div",
{ class: "cloud" },
props.words.map((w, i) =>
h(
"span",
{
class: "word",
style: {
fontSize: `${12 + w.weight}px`,
opacity: pick.value === i ? 1 : 0.6,
},
onClick: () => (pick.value = i),
},
w.text
)
)
);
},
});
写复杂了就上 JSX
嵌套一多,纯 h() 调用会嵌套得很深,可读性下降。Vue 支持 JSX,配合 @vitejs/plugin-vue-jsx 就能在 .tsx 里直接写类 HTML 结构,同时保留全部 JS 表达能力。
import { defineComponent, ref } from "vue";
export const TagCloud = defineComponent({
props: {
words: {
type: Array as () => { text: string; weight: number }[],
required: true,
},
},
setup(props) {
const pick = ref(0);
return () => (
<div class="cloud">
{props.words.map((w, i) => (
<span
class="word"
style={{
fontSize: `${12 + w.weight}px`,
opacity: pick.value === i ? 1 : 0.6,
}}
onClick={() => (pick.value = i)}
>
{w.text}
</span>
))}
</div>
);
},
});
渲染函数和模板不是二选一
渲染函数的真正价值是处理"逻辑决定结构"的情况。比如一个通用的容器组件,接收 render 函数作为插槽,把默认内容用一层带边框的卡片包起来:
export const Card = defineComponent({
setup(_, { slots }) {
return () =>
h("div", { class: "card" }, slots.default ? slots.default() : []);
},
});
这里 slots.default() 返回的是 VNode 数组,组件不关心里面是按钮还是表格,只负责加外壳。这种"包裹型"组件用渲染函数写几乎零成本,用模板反而要绕。
几个注意点
- 渲染函数里没有 v-model、v-for 这些语法糖,双向绑定要手写 value 加 onInput,列表用 Array.map 替代。
- class 在渲染函数里既可以是字符串,也可以是对象或数组;style 必须是对象,且要用驼峰写法。
- JSX 需要编译插件,工程里要确认 vue-jsx 插件已接入,否则 .tsx 不会被正确转换。
- 能用模板解决的静态结构,优先模板;只有当结构本身依赖运行时逻辑时才切渲染函数,二者按职责分工。
小结
渲染函数和 JSX 是 Vue 表达能力的上限,适合标签、属性、子节点在运行期才确定的动态组件与高阶封装。把它当作模板的补充而不是替代,该用模板时仍用模板,遇到"结构随逻辑变"的场景再切过去,代码才会既灵活又可读。
T
test1
文章作者
模板不是万能的 Vue 单文件组件用模板写结构,直观、可读,日常开发几乎都用它。但有些场景模板会显得笨拙:标签名、属性...
- 分类
- 技术
- 发布时间
- 2026-10-07
- 字数
- 约 2439 字
- 阅读
- 5 次
