Vue.js嵌套SFC组件使用$refs调用方法报错的解决方案咨询
Vue嵌套单文件组件中通过$refs调用子组件方法的问题解决
问题概述
控制台报错:TypeError: this.$refs.smile.sayHi is not a function
复现步骤
- 使用
npm create vue@latest创建Vue.js项目; - 创建
src/components/Smile.vue组件; - 创建
src/components/BigSmile.vue组件:在<script setup>中导入Smile组件,同时在常规<script>里定义sayHi方法; - 修改
src/components/TheWelcome.vue:导入BigSmile组件并设置ref为smile,在mounted钩子中调用this.$refs.smile.sayHi();
现象:当BigSmile.vue中导入Smile组件时调用报错,移除该导入则调用正常。
核心结论
嵌套单文件组件(SFC)场景下完全可以通过$refs调用子组件方法,问题出在<script setup>与常规<script>混用时的方法暴露规则上。
原因分析
当组件使用<script setup>时,Vue会默认封装组件内部的属性和方法,常规<script>中定义的methods不会自动暴露给父组件。一旦在BigSmile.vue中启用<script setup>(哪怕只是用来导入Smile组件),组件的上下文就会被<script setup>接管,未显式暴露的sayHi方法无法被父组件的$refs访问。
解决方案
方案1:在<script setup>中显式暴露方法
使用Vue的defineExpose宏,将需要外部访问的方法暴露出去。如果要保留常规<script>的methods,可以通过getCurrentInstance获取组件实例后再暴露:
<!-- src/components/BigSmile.vue --> <script setup> import Smile from './Smile.vue' import { getCurrentInstance } from 'vue' const instance = getCurrentInstance() // 显式暴露常规script中的sayHi方法 defineExpose({ sayHi: instance?.proxy?.sayHi }) </script> <script> export default { methods: { sayHi() { console.log('Hello from BigSmile!') } } } </script>
或者直接将方法定义在<script setup>中再暴露:
<!-- src/components/BigSmile.vue --> <script setup> import Smile from './Smile.vue' const sayHi = () => { console.log('Hello from BigSmile!') } // 显式暴露方法 defineExpose({ sayHi }) </script>
方案2:移除<script setup>,统一使用选项式API
如果不需要<script setup>的语法糖,直接用选项式API编写组件,此时methods会自动暴露给父组件:
<!-- src/components/BigSmile.vue --> <script> import Smile from './Smile.vue' export default { components: { Smile }, methods: { sayHi() { console.log('Hello from BigSmile!') } } } </script>
总结
使用$refs调用嵌套子组件方法的关键是确保子组件的目标方法被正确暴露:
- 若使用
<script setup>,必须通过defineExpose显式声明需要外部访问的方法或属性; - 若使用选项式API,组件的
methods默认对外暴露,无需额外操作。
内容的提问来源于stack exchange,提问作者Fandi Susanto
相关产品推荐
相关产品推荐

