Vue 组件内的模板复用
刀刀
0字
0分钟
2026/8/16
场景
模块多处复用,代码如下:
vue
<template>
<div class="container">
<div class="title">标题</div>
<div class="content">内容</div>
</div>
<div>111</div>
<div class="container">
<div class="title">标题</div>
<div class="content">内容</div>
</div>
<p>2222</p>
<div>333</div>
<div class="container">
<div class="title">标题</div>
<div class="content">内容</div>
</div>
</template>.container 内容重复出现,如何不独立封装为子组件,实现模块内复用?
解决方案
组件即函数
在Vue中,组件即函数,<template></template> 后续会被转化为函数,可通过函数参数实现复用。
创建一个对象,包含 setup 函数,从第二个参数解构出 slots 插槽,通过 slots.default() 获取插槽内容:
js
let render
const DefineTemplate = {
setup(_, { slots }) {
return () => {
render = slots.default
return render()
}
},
}
const UseTemplate = () => render()vue
<template>
<DefineTemplate>
<div class="container">
<div class="title">标题</div>
<div class="content">内容</div>
</div>
</DefineTemplate>
<div>111</div>
<UseTemplate></UseTemplate>
<p>2222</p>
<div>333</div>
<UseTemplate></UseTemplate>
</template>利用插槽特性,从 DefineTemplate 的 setup 中获取相同模块并保存到 render,调用 render() 即可复用。
打印 slot.default() 的内容:

type、内容 children 等信息,通过虚拟组件的 render 函数渲染真实组件。抽离封装复用
抽离为公共函数,每个需要的 .vue 文件都能使用:
js
export const createReusableTemplate() {
let render;
const DefineTemplate = {
setup(_, { slots }) {
return () => {
render = slots.default;
return render();
}
}
}
const UseTemplate = () => render()
return [DefineTemplate, UseTemplate]
} vue
<script setup>
import { createReusableTemplate } from './utils.js'
const [DefineTemplate, UseTemplate] = createReusableTemplate()
</script>
<template>
<DefineTemplate>
<div class="container">
<div class="title">标题</div>
<div class="content">内容</div>
</div>
</DefineTemplate>
<UseTemplate></UseTemplate>
<div>111</div>
<UseTemplate></UseTemplate>
<p>2222</p>
<div>333</div>
<UseTemplate></UseTemplate>
</template>DefineTemplate 负责保存插槽内的组件,UseTemplate 负责渲染。返回数组,外部通过数组解构自定义命名。
注意
DefineTemplate 的 setup 去掉了副作用,不再 return 默认插槽内容,仅保存到 render 变量中。
支持传参数
使用时要传参数,如何解决?例如:
vue
<script setup>
import { createReusableTemplate } from './utils.js'
const [DefineTemplate, UseTemplate] = createReusableTemplate()
</script>
<template>
<DefineTemplate>
<div class="container">
<div class="title">标题</div>
<div class="content">内容</div>
</div>
</DefineTemplate>
<UseTemplate title="header" @foo="console.log"></UseTemplate>
<div>111</div>
<UseTemplate title="main"></UseTemplate>
<p>2222</p>
<div>333</div>
<UseTemplate title="footer"></UseTemplate>
</template>组件 UseTemplate 即 UseTemplate 函数,传的变量和事件可在形参接收:
js
export const createReusableTemplate() {
let render;
const DefineTemplate = {
setup(_, { slots }) {
return () => {
render = slots.default();
}
}
}
const UseTemplate = (props) => {
console.log(props) // { title: 'header', foo: ƒ }
return render()
}
return [DefineTemplate, UseTemplate]
}实现传参的步骤:
UseTemplate接收到参数后,传给renderrender接收参数,相当于默认插槽slots.default接收参数DefineTemplate通过v-slot="data"从默认插槽获取数据- 使用
最终代码:
js
export const createReusableTemplate() {
let render;
const DefineTemplate = {
setup(_, { slots }) {
return () => {
render = slots.default();
}
}
}
const UseTemplate = (props) => render(props)
return [DefineTemplate, UseTemplate]
}vue
<script setup>
import { createReusableTemplate } from './utils.js'
const [DefineTemplate, UseTemplate] = createReusableTemplate()
</script>
<template>
<DefineTemplate>
<div class="container" v-slot="{ title, onFoo }">
<div class="title">{{ title }}</div>
<div class="content" @click="onFoo(111)">内容</div>
</div>
</DefineTemplate>
<UseTemplate title="header" @foo="console.log"></UseTemplate>
<div>111</div>
<UseTemplate title="main"></UseTemplate>
<p>2222</p>
<div>333</div>
<UseTemplate title="footer"></UseTemplate>
</template>注意
方法内部会被转化为 on + 首字母大写的形式。
动手实操
跳转预览:点击跳转