You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue.js如何在组件内复用模板而无需导出为新组件?

当然有啦!Vue 提供了几种不用单独导出组件就能复用模板片段的方案,完美匹配你的需求~下面针对不同Vue版本给你具体的实现方式:


Vue 2 实现方式(类似React渲染函数)

你可以在组件的methods里定义一个返回VNode的渲染函数,就像React里的函数式渲染片段一样:

<template>
  <div>
    <!-- 直接调用渲染函数生成内容 -->
    {{ renderIncrease(yearly) }}
    <YearlyChart/>
    {{ renderIncrease(monthly) }}
    <MonthlyTable/>
    {{ renderIncrease(weekly) }}
  </div>
</template>

<script>
export default {
  data() {
    return {
      yearly: { text: "Yearly Sales", increase: 5 },
      monthly: { text: "Monthly Sales Dropping", increase: -7.2 },
      weekly: { text: "Awesome Weekly Sales!", increase: 0.2 }
    }
  },
  methods: {
    spanClassName(increase) {
      return increase >= 0 ? 'text-success' : 'text-danger'
    },
    iconClassName(increase) {
      return increase >= 0 ? 'fa fa-arrow-up' : 'fa fa-arrow-down'
    },
    // 自定义渲染函数,返回VNode数组
    renderIncrease(stat) {
      return [
        this.$createElement('span', stat.text),
        this.$createElement('span', {
          class: this.spanClassName(stat.increase)
        }, [
          this.$createElement('i', {
            class: this.iconClassName(stat.increase)
          }),
          `${stat.increase}%`
        ])
      ]
    }
  }
}
</script>

Vue 3 实现方式(更简洁灵活)

在Vue 3中,你可以直接用h函数(Vue的虚拟DOM创建函数)结合<script setup>来实现,写法更接近React的风格:

<template>
  <div>
    <!-- 通过<component>渲染生成的VNode -->
    <component :is="renderIncrease(yearly)" />
    <YearlyChart/>
    <component :is="renderIncrease(monthly)" />
    <MonthlyTable/>
    <component :is="renderIncrease(weekly)" />
  </div>
</template>

<script setup>
import { h } from 'vue'
import YearlyChart from './YearlyChart.vue'
import MonthlyTable from './MonthlyTable.vue'

// 定义数据
const yearly = { text: "Yearly Sales", increase: 5 }
const monthly = { text: "Monthly Sales Dropping", increase: -7.2 }
const weekly = { text: "Awesome Weekly Sales!", increase: 0.2 }

// 工具函数
const spanClassName = (increase) => increase >= 0 ? 'text-success' : 'text-danger'
const iconClassName = (increase) => increase >= 0 ? 'fa fa-arrow-up' : 'fa fa-arrow-down'

// 渲染函数:返回单个根节点的VNode(Vue 3要求组件必须有单根)
const renderIncrease = (stat) => {
  return h('div', [
    h('span', stat.text),
    h('span', {
      class: spanClassName(stat.increase)
    }, [
      h('i', { class: iconClassName(stat.increase) }),
      `${stat.increase}%`
    ])
  ])
}
</script>

备选方案:局部小型组件(开销极低)

如果你觉得渲染函数写起来有点繁琐,也可以在当前组件内部注册一个极小的局部组件,完全不需要单独导出文件,开销其实非常小:

<template>
  <div>
    <increase-display :stat="yearly" />
    <YearlyChart/>
    <increase-display :stat="monthly" />
    <MonthlyTable/>
    <increase-display :stat="weekly" />
  </div>
</template>

<script setup>
import YearlyChart from './YearlyChart.vue'
import MonthlyTable from './MonthlyTable.vue'

const yearly = { text: "Yearly Sales", increase: 5 }
const monthly = { text: "Monthly Sales Dropping", increase: -7.2 }
const weekly = { text: "Awesome Weekly Sales!", increase: 0.2 }

// 局部注册小型组件
const IncreaseDisplay = {
  props: ['stat'],
  template: `
    <span>{{ stat.text }}</span>
    <span :class="spanClassName(stat.increase)">
      <i :class="iconClassName(stat.increase)"></i>
      {{ stat.increase }}%
    </span>
  `,
  methods: {
    spanClassName(increase) {
      return increase >= 0 ? 'text-success' : 'text-danger'
    },
    iconClassName(increase) {
      return increase >= 0 ? 'fa fa-arrow-up' : 'fa fa-arrow-down'
    }
  }
}
</script>

这种方式的可读性其实比渲染函数更好,而且Vue对小型组件的优化已经做得非常到位,完全不用担心性能问题~

内容的提问来源于stack exchange,提问作者glinda93

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 19:07:50