为何Vue组件名仅会被非默认导出遮蔽?导入差异解析
我有一个仅渲染TestComp组件的简单Vue应用,在App.vue的setup上下文中存在一个名为testComp的ref。尽管未使用推荐的<TestComp />模板表达式,而是采用<test-comp />,组件仍能正常渲染。
App.vue 代码:
<script setup> import { ref } from 'vue' import TestComp from './TestComp.vue' const testComp = ref(null) </script> <template> <div> <test-comp /> <!-- 推荐写法是<TestComp />, 可以避免问题,但这不是重点 --> </div> </template>
TestComp.vue 代码:
<script setup> </script> <template> <div> I am a test component. </div> </template>
components.ts 代码:
import TestComp from './TestComp.vue' // 用于统一导出多个组件 export { TestComp }
此时模板表达式<test-comp />会被解析为导入的TestComp组件,而非testComp变量。但如果将导入方式从import TestComp from './TestComp.vue'改为import { TestComp } from './components.ts',<test-comp />会被解析为ref变量testComp,出现警告[Vue warn]: Invalid vnode type when creating vnode: null且组件无法渲染。
请问为何直接导入与通过非默认导出导入TestComp会存在此差异?
这是Vue的<script setup>语法糖中组件自动注册规则和变量解析优先级共同作用的结果:
直接默认导入的情况
当你直接从.vue文件默认导入组件时(import TestComp from './TestComp.vue'),Vue会自动识别这是一个组件,并将其注册到当前组件的模板可用范围内。此时模板中的<test-comp />会按照Vue的组件命名转换规则(大驼峰转短横线分隔),匹配到注册的TestComp组件,优先级高于同名的ref变量testComp。通过非默认导出导入的情况
当你从components.ts通过命名导出导入组件时(import { TestComp } from './components.ts'),Vue的自动组件注册机制会失效——它默认只对直接从.vue文件导入的默认导出做自动注册,无法识别从非.vue文件导入的变量是组件。此时TestComp只是setup上下文中的一个普通变量,而模板解析时,<test-comp />会优先匹配到setup中同名的短横线转驼峰形式的变量testComp(也就是那个初始值为null的ref),自然会抛出无效vnode的警告。
简单总结:
直接从.vue默认导入的组件会被Vue自动注册,模板优先匹配组件;从其他文件命名导入的组件不会自动注册,模板会优先匹配setup中同名的响应式变量。
内容的提问来源于stack exchange,提问作者Tobias Braun

