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
相关产品推荐
相关产品推荐

