大多數時候模板夠用,但有些場景 render 函式更靈活。
為什麼需要 render 函式
模板有侷限——不能根據 props 動態生成不同的標籤:
javascript
// ❌ 模板裡做不了這個(不能根據 prop 動態指定標籤名)
// <component :is="level"> // 能用,但如果標籤名邏輯複雜就麻煩了
// ✅ render 函式完全用 JS 控制
export default {
props: {
level: { type: Number, required: true },
},
render(h) {
return h("h" + this.level, this.$slots.default);
},
};
// <Heading :level="2">標題</Heading> → <h2>標題</h2>
createElement(h)的引數
javascript
h(
// 1. 標籤名、元件選項物件或非同步函式
"div",
// 2. 資料物件(可選)
{
class: { active: true, disabled: false },
style: { color: "red", fontSize: "14px" },
attrs: { id: "app", "data-id": "123" },
props: { value: "hello" },
on: { click: this.handleClick },
// 原生事件(元件)
nativeOn: { click: this.handleNativeClick },
},
// 3. 子節點(可選)
["text content", h("span", "child")],
);
實戰:動態表單
根據配置生成不同型別的表單項:
javascript
const FormField = {
props: {
type: String, // 'input' | 'select' | 'textarea'
value: [String, Number],
options: Array, // select 選項
},
render(h) {
if (this.type === "select") {
return h(
"select",
{
on: { change: (e) => this.$emit("input", e.target.value) },
},
this.options.map((opt) =>
h("option", { attrs: { value: opt.value } }, opt.label),
),
);
}
if (this.type === "textarea") {
return h("textarea", {
attrs: { value: this.value },
on: { input: (e) => this.$emit("input", e.target.value) },
});
}
return h("input", {
attrs: { type: this.type || "text", value: this.value },
on: { input: (e) => this.$emit("input", e.target.value) },
});
},
};
JSX:更易讀的 render 函式
配置 Babel JSX 外掛後,可以用 JSX 替代 h 呼叫:
bash
npm install --save-dev @vue/babel-preset-jsx @vue/babel-helper-vue-jsx-merge-props
javascript
// 和上面等價的 JSX 寫法
export default {
props: { level: Number },
render() {
const Tag = `h${this.level}`
return <Tag>{this.$slots.default}</Tag>
}
}
// 更復雜的例子
export default {
render() {
return (
<div class="container">
<header>
<h1>{this.title}</h1>
</header>
<ul>
{this.items.map(item => (
<li key={item.id} onClick={() => this.select(item)}>
{item.name}
</li>
))}
</ul>
</div>
)
}
}
模板 vs render 函式的選擇
- 模板:大多數場景,直觀可讀,工具支援好
- render 函式:需要完整 JS 能力的場景(動態標籤、複雜迴圈邏輯)
- JSX:習慣 React 開發模式,或元件主要是邏輯而非展示
小結
render函式接收h(createElement),返回 VNode- 模板最終也編譯為 render 函式
- JSX 是 render 函式的語法糖,需要 Babel 外掛
- 優先用模板,需要動態性時再用 render/JSX