前言 📝
在Vue3中,我们会通过提供的defineExpose
宏,将内部的方法暴露给父组件使用。如果要是基于某个组件进行二次封装的呢?我们改如何优雅的将该组件暴露的方法提供给最外层组件使用呢?
1. DefineExpose
默认情况下,通过模板引用获取到的组件的公开实例,并不会暴露任何在 <script setup>
中声明的绑定。使用 <script setup>
的组件默认关闭了这个功能。
要显式指定在 <script setup>
组件中要暴露出去的属性,可以使用 defineExpose
编译器宏。下面是一个示例:
1 2 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接收的是一个对象,我们可以尝试给他一个代理对象试一下:
1 2 3 4 5 6 7 8 9
| defineExpose( new Proxy( {}, { get(target, key) { } }) )
|
正如上面所示,我们尝试返回一个代理对象,在我们get
拦截的时候,我们返回的是被封装组件暴露的方法。
我们尝试在一个真正的例子中使用一下:
1 2 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>
|
1 2 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
方法。在元素挂在完之后,让输入框自动进行聚焦。
成果展示:
进入到页面之后,很明显,自动聚焦了。说明我们的方案是行得通的。
