Jiang's Tech Journal

Jiang's Tech Journal

首页
分类
关于
Login →
Jiang's Tech Journal

Jiang's Tech Journal

首页 分类 关于
Login
  1. Home
  2. 前端
  3. 【Vue】 组件内模板复用技巧:createReusableTemplate

【Vue】 组件内模板复用技巧:createReusableTemplate

0
  • 前端
  • Published at 2025-12-29
  • Read 42 times
Jiang
Jiang
Table of Contents
No Table of Contents

在 Vue 组件开发中,我们经常遇到部分模板内容需要在同一组件内多次复用的场景。传统的解决方案如提取子组件、v-for 循环或直接复制粘贴,在某些简单场景下可能显得过于繁琐或冗余。

本文介绍一种利用 Vue 3 组合式 API 和渲染函数特性实现的“局部模板复用”技巧,类似于模板引擎中的“宏(Macro)”概念。

核心思路

该方案的核心在于利用 闭包 和 渲染函数:

  1. DefineTemplate:一个“插槽捕获器”。它不直接渲染内容,而是通过 setup 函数获取默认插槽(slots.default)的渲染函数,并将其存储在一个局部变量中。
  2. UseTemplate:一个“渲染器”。它是一个简单的函数式组件,负责调用并渲染上述存储的渲染函数。

基础实现

以下是该模式的最简实现。

1. 定义工具组件

我们通过一个局部变量 render 来在两个组件之间共享渲染逻辑。

<script lang="ts" setup>
import { type Slot } from 'vue'

// 用于存储插槽渲染函数的变量
let render: Slot | undefined

// 1. 定义模板的组件
const DefineTemplate = {
  setup(_: unknown, { slots }: { slots: { default: Slot } }) {
    // 将插槽函数赋值给外部变量,注意:这里返回一个渲染函数
    return () => {
      render = slots.default
    }
  }
}

// 2. 使用模板的组件
const UseTemplate = () => {
  // 调用存储的渲染函数
  return render ? render() : null
}
</script>

2. 在模板中使用

<template>
  <div>
    <!-- 定义区:这部分内容不会直接渲染,而是被“捕获” -->
    <DefineTemplate>
      <div class="reused-box">
        <span>这是复用的内容</span>
      </div>
    </DefineTemplate>

    <!-- 使用区 -->
    <header>
      <h1>Page Header</h1>
      <UseTemplate />
    </header>

    <main>
      <p>Main Content</p>
      <UseTemplate />
    </main>
  </div>
</template>

进阶封装:支持参数传递

为了让复用模板更灵活,我们需要支持通过 作用域插槽(Scoped Slots)传递数据。我们可以将其封装为一个通用的工具函数 createReusableTemplate。

优化后的工具函数

import { type Slot, type VNode } from 'vue'

/**
 * 创建一对可复用的模板组件
 * @returns [DefineTemplate, UseTemplate]
 */
export function createReusableTemplate<T extends object = any>() {
  // 使用闭包保存渲染函数,确保每个实例独立
  let render: Slot | undefined

  // 定义组件:接收插槽并保存
  const DefineTemplate = {
    setup(_: unknown, { slots }: { slots: { default: Slot } }) {
      return () => {
        render = slots.default
      }
    }
  }

  // 使用组件:接收 props 并传递给渲染函数
  const UseTemplate = (props: T): VNode[] | null => {
    return render ? render(props) : null
  }

  return [DefineTemplate, UseTemplate] as const
}

使用示例

通过 v-slot 接收参数,实现动态内容渲染。

<template>
  <div class="layout">
    <!-- 定义模板:接收 title 参数 -->
    <DefineTemplate v-slot="{ title }">
      <div class="card">
        <h3>当前区域:{{ title }}</h3>
        <p>这是通用的卡片样式</p>
      </div>
    </DefineTemplate>

    <div class="section">
      <UseTemplate title="头部区域" />
    </div>

    <div class="section">
      <UseTemplate title="侧边栏" />
    </div>
  </div>
</template>

<script lang="ts" setup>
// 假设上面的函数保存在 utils 中
// import { createReusableTemplate } from '@/utils'

// 实例化一对模板组件
const [DefineTemplate, UseTemplate] = createReusableTemplate<{ title: string }>()
</script>

最佳实践

虽然手写这个功能很有趣,但在生产环境中,建议直接使用 VueUse 库提供的 createReusableTemplate。它处理了更多的边界情况(如 Fragment、多个根节点、TS 类型推断等),更加健壮。

安装 VueUse:

npm i @vueuse/core

使用方式:

<script lang="ts" setup>
import { createReusableTemplate } from '@vueuse/core'

const [DefineTemplate, UseTemplate] = createReusableTemplate<{ msg: string }>()
</script>

<template>
  <DefineTemplate v-slot="{ msg }">
    <div>Message: {{ msg }}</div>
  </DefineTemplate>

  <UseTemplate msg="Hello" />
  <UseTemplate msg="World" />
</template>

总结

这种模式利用了 Vue 的底层能力,提供了一种轻量级的组件内代码复用方式:

  • 隔离性:模板仅在当前组件内有效,不污染全局注册。
  • 简洁性:避免了为了一小段 HTML 专门创建一个 .vue 文件的麻烦。
  • 灵活性:结合作用域插槽,可以像函数一样传递参数。

推荐在组件内部存在重复结构,且该结构尚未复杂到需要拆分为独立组件时使用。

Related Posts

OpenCode 接入 Figma MCP:无需安装 fork 的 OAuth 解决办法

在 OpenCode 中接入 Figma 的远程 MCP 服务时,如果 OAuth 授权流程无法正常完成,可以通过手动注册一个 Figma MCP OAuth 客户端来绕过问题。这个方法不需要安装第三方 fork,核心思路是: 向 Figma 的 MCP OAuth 注册接口申请客户端凭据。 把返回

【Vue】VueUse 中 createReusableTemplate 的妙用

在 Vue 3 开发中,虽然推荐使用模板语法,但在封装高阶组件或使用特定 UI 库(如 Naive UI、Element Plus、Ant Design Vue)的表格组件时,我们往往需要编写 Render 函数(h 函数)或使用 JSX/TSX 来处理复杂的自定义列渲染。 对于不熟悉渲染函数 AP

【Vue】 组件内模板复用技巧:createReusableTemplate

在 Vue 组件开发中,我们经常遇到部分模板内容需要在同一组件内多次复用的场景。传统的解决方案如提取子组件、v-for 循环或直接复制粘贴,在某些简单场景下可能显得过于繁琐或冗余。 本文介绍一种利用 Vue 3 组合式 API 和渲染函数特性实现的“局部模板复用”技巧,类似于模板引擎中的“宏(Mac

【Vue】组件二次封装技巧

日常任务开发过程中避免不了进行 UI 组件库部分组件的二次封装使用,记录下长期开发过程中积累的一些经验和网络学习的新技巧,组件二次封装需要解决的无非就是属性 props 如何透传出去,如何复用原有组件的插槽,以及如何调用原组件暴露的方法,这里以比较热门的 UI 框架 Element Plus 为例。

【vue-admin-kit】配置驱动的 Vue 3 后台管理组件工具套件

📖 在线文档:https://vue-admin-kit.jiang.in/ 前言 在企业级后台管理系统开发中,CRUD 页面占据了大量的开发工作。搜索表单、数据表格、新增/编辑弹窗、详情展示……这些重复性的工作不仅耗时,还容易产生不一致的代码风格。 vue-admin-kit 正是为解决这一痛点

[CSS] 移除元素焦点状态

padding: '0' - 移除内边距 border: 'none' - 移除边框 outline: 'none' - 移除焦点时的轮廓线(这是关键!) boxShadow: 'none' - 移除可能的阴影效果

Table of Contents
No Table of Contents
Copyright © 2024 your company All Rights Reserved. Powered by Halo.