一、核心区别对比
特性 | 模板语法 | Render 函数 |
---|---|---|
语法形式 | HTML-like 声明式模板 | JavaScript 函数式编程 |
灵活性 | 有限(受限于模板语法规则) | 极高(可使用完整 JavaScript 能力) |
动态组件 | 需要 v-if /v-for 等指令 | 直接使用 JavaScript 逻辑控制 |
JSX 支持 | 不支持 | 支持(需配置 Babel 插件) |
类型支持 | 有限(TypeScript 支持较弱) | 更好(适合 TypeScript 开发) |
编译优化 | 自动优化(模板预编译) | 需要手动优化(更贴近底层) |
学习曲线 | 低(易上手) | 较高(需理解虚拟 DOM 和函数式编程) |
调试难度 | 容易(可视化结构) | 较难(需要理解虚拟 DOM 结构) |
二、基础示例对比
场景:渲染带条件的列表
模板语法实现:
<template>
<div>
<template v-if="items.length">
<ul class="list">
<li
v-for="(item, index) in items"
:key="index"
:class="{ active: item.selected }"
>
{{ item.name }}
</li>
</ul>
</template>
<p v-else>No items found</p>
</div>
</template>
Render 函数实现:
export default {
render(h) {
if (this.items.length) {
return h('div', [
h('ul', { class: 'list' },
this.items.map((item, index) => {
return h('li', {
class: { active: item.selected },
key: index
}, item.name)
})
)
])
} else {
return h('p', 'No items found')
}
}
}
三、高级场景对比
场景:动态生成表格列
模板语法局限:
<!-- 需要预先知道列结构 -->
<table>
<tr v-for="row in data">
<td v-for="col in columns">{{ row[col.prop] }}</td>
</tr>
</table>
Render 函数优势:
export default {
render(h) {
// 动态生成列(可包含复杂逻辑)
return h('table',
this.data.map(row =>
h('tr',
this.columns.filter(col => col.visible).map(col =>
h('td', {
style: { color: col.color }, // 动态样式
on: {
click: () => this.handleClick(col.prop)
}
}, row[col.prop])
)
)
)
)
}
}
四、JSX 语法示例
export default {
render() {
return (
<div class="container">
{this.showHeader &&
<Header
title={this.title}
onClose={this.handleClose}
/>}
<main class="content">
{this.items.map(item => (
<ItemCard
item={item}
key={item.id}
onClick={this.selectItem}
/>
))}
</main>
</div>
)
}
}
五、选择建议指南
优先使用模板语法:
- 常规 UI 组件开发
- 需要快速原型开发时
- 团队对 HTML 更熟悉时
- 需要直观的结构展示时
优先使用 Render 函数:
- 需要动态生成复杂组件结构时
- 需要实现高阶组件 (HOC) 时
- 需要最大化性能控制时
- 需要与 TypeScript 深度集成时
- 需要跨平台渲染时(如 Weex)
六、性能关键差异
-
编译阶段:
- 模板语法会被编译为优化后的 render 函数
- 手写 render 函数需要自行优化
-
更新机制:
// 模板编译后的优化代码示例 function render() { with(this) { return _c('div', { staticClass: "box" }, [ _c('span', [_v(_s(message))]) ]) } }
-
手动优化示例:
export default { render(h) { // 通过缓存 VNode 提升性能 if (!this.cachedNode) { this.cachedNode = h('div', this.largeDataSet.map(item => h('ComplexNode', { props: { item } }) ) ) } return this.cachedNode } }
七、混合使用技巧
<template>
<div>
<!-- 使用模板处理静态部分 -->
<header class="main-header">
<slot name="header"></slot>
</header>
<!-- 使用 render 处理动态部分 -->
<render-section :items="dynamicItems"/>
</div>
</template>
<script>
export default {
components: {
RenderSection: {
render(h) {
return h('div',
this.items.map(item =>
h('article', { class: 'card' }, [
h('h3', item.title),
h('p', item.content)
])
)
)
}
}
}
}
</script>
通过理解这些差异和适用场景,开发者可以更精准地选择适合项目需求的开发方式。模板语法提供简洁高效的标准开发流程,而 Render 函数则为复杂场景和性能优化提供终极解决方案。