前言 📝
在Vue3中,我们会通过提供的defineExpose宏,将内部的方法暴露给父组件使用。如果要是基于某个组件进行二次封装的呢?我们改如何优雅的将该组件暴露的方法提供给最外层组件使用呢?
1. DefineExpose
默认情况下,通过模板引用获取到的组件的公开实例,并不会暴露任何在 <script setup> 中声明的绑定。使用 <script setup> 的组件默认关闭了这个功能。
要显式指定在 <script setup> 组件中要暴露出去的属性,可以使用 defineExpose 编译器宏。下面是一个示例:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | <script setup>import { ref, defineExpose } from 'vue'
 
 const a = 1
 const b = ref(2)
 
 defineExpose({
 a,
 b
 })
 </script>
 
 | 
当父组件通过模板引用的方式获取到当前组件的实例时,获取到的实例将包含暴露的属性,例如:{ a: number, b: number }。注意,ref 会像在普通实例中一样被自动解包。
1.1 优雅的将被二次封装组件的内部方法暴露出来
deineExpose接收的是一个对象,我们可以尝试给他一个代理对象试一下:
| 12
 3
 4
 5
 6
 7
 8
 9
 
 | defineExpose(new Proxy(
 {},
 {
 get(target, key) {
 
 }
 })
 )
 
 | 
正如上面所示,我们尝试返回一个代理对象,在我们get拦截的时候,我们返回的是被封装组件暴露的方法。
我们尝试在一个真正的例子中使用一下:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 
 | // 父组件<script setup lang="ts">
 // 框架
 import { ref } from 'vue'
 // 组件
 import Comp from './Comp.vue'
 // 方法/类型
 
 const testVal = ref()
 const compRef = ref()
 
 </script>
 
 <template>
 <div id="container">
 <comp ref="byElInputRef" v-model="testVal" @vue:mounted="(e) => compRef.focus()" />
 </div>
 </template>
 
 | 
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 
 | <script setup lang="ts">// 框架
 import { ElInput } from 'element-plus'
 import { ref, defineExpose } from 'vue'
 // 组件
 // 方法/类型
 
 const inputRef = ref()
 
 defineExpose(
 new Proxy(
 {},
 {
 get(target, key) {
 return inputRef.value?.[key]
 },
 has(target, key) {
 return key in inputRef.value
 }
 })
 )
 </script>
 
 <template>
 <el-input ref="inputRef" v-bind="$attrs" />
 </template>
 
 | 
我们在父组件中,调用了二次封装ElInput组件的focus方法。在元素挂在完之后,让输入框自动进行聚焦。
成果展示:
进入到页面之后,很明显,自动聚焦了。说明我们的方案是行得通的。
