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

Vue中能否不新建文件直接在单文件组件内定义嵌套组件?

引入路径修改生效的核心原理

Vue默认提供两类不同的构建产物,对应不同使用场景:

  • 执行import { createApp } from 'vue'时,默认引入的是纯运行时版本。这个版本剔除了模板编译器代码,体积比全量版本小30%左右,是官方推荐的默认产物。我们平时写的.vue单文件组件里的顶层<template>块,会在构建阶段被vue-loader/@vitejs/plugin-vue提前编译成可直接执行的渲染函数,运行时不需要再做模板解析,所以纯运行时版本完全能满足常规开发需求。
  • 你原来的写法里,Child组件是通过defineComponent的template选项传入字符串模板的,这类写在JS/TS代码里的字符串模板不会被构建工具提前编译,必须在应用运行时动态编译成渲染函数才能渲染,纯运行时版本没有内置编译器,就会直接报错。
  • 改成引入vue/dist/vue.esm-bundler.js后,拿到的是运行时+编译器的全量ESM构建产物,内置了运行时模板编译能力,可以动态把传入的字符串模板转成渲染函数,代码就能正常运行了。

注意:这种修改全局Vue引入路径的方式会让整个应用的包体积增加30%左右,只为了单个小组件带全量编译器性价比很低,非特殊场景不推荐使用。

同文件定义嵌套组件的标准方案

以下方案都不需要新建独立组件文件、不需要导出子组件、不需要全局注册,且兼容默认的纯运行时Vue构建,不会增加额外包体积:

  • 方案1:用h渲染函数定义极简组件
    适合结构非常简单的小组件,不需要额外配置,直接引入Vue提供的h函数编写渲染逻辑即可,构建时无额外开销:
    <!-- Parent.vue -->
    <template>
        <div>
            <span>{{ foo }}</span>
            <Child />
        </div>
    </template>
    
    <script setup>
    import { ref, h } from 'vue'
    const foo = ref('foo')
    
    // 同文件直接定义子组件
    const Child = {
        name: 'Child',
        setup() {
            const bar = ref('bar')
            // 返回渲染函数代替template
            return () => h('span', bar.value)
        }
    }
    </script>
    
  • 方案2:开启JSX支持后用JSX定义组件
    如果项目配置了Vue JSX支持(Vite项目加@vitejs/plugin-vue-jsx、Vue-CLI/Webpack项目默认已支持),可以直接在script里用JSX写组件模板,JSX会在构建阶段被直接编译成渲染函数,不需要运行时编译器,写法比h函数更直观:
    <!-- Parent.vue -->
    <template>
        <div>
            <span>{{ foo }}</span>
            <Child />
        </div>
    </template>
    
    <script setup lang="jsx">
    import { ref } from 'vue'
    const foo = ref('foo')
    
    // 直接用箭头函数+JSX定义子组件
    const Child = () => {
        const bar = ref('bar')
        return <span>{ bar.value }</span>
    }
    </script>
    
  • 方案3:同文件嵌套编写SFC块(原生多组件支持)
    Vue单文件组件规范本身支持在一个.vue文件内定义多个组件,只要给子组件的<script setup>块添加name属性,对应同名的<template>块就会被绑定为该子组件的模板,构建阶段会和普通SFC一样被预编译,完全不需要运行时编译器,适合结构稍复杂的同文件子组件:
    <!-- Parent.vue 父组件部分 -->
    <template>
        <div>
            <span>{{ foo }}</span>
            <Child />
        </div>
    </template>
    <script setup>
    import { ref } from 'vue'
    const foo = ref('foo')
    </script>
    
    <!-- 同文件定义Child子组件 -->
    <template name="Child">
        <span>{{ bar }}</span>
    </template>
    <script setup name="Child">
    import { ref } from 'vue'
    const bar = ref('bar')
    </script>
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 13:15:41