Vue3 Composition API怎么优雅封装第三方组件
时间:2023-05-12 04:48
对于第三方组件,如何在保持第三方组件原有功能(属性props、事件events、插槽slots、方法methods)的基础上,优雅地进行功能的扩展了? 以Element Plus的el-input为例: 很有可能你以前是这样玩的,封装一个MyInput组件,把要使用的属性props、事件events和插槽slots、方法methods根据自己的需要再写一遍: 可过一段时间后,需求变更,又要在MyInput组件上添加el-input组件的其它功能,可el-input组件总共有20个多属性,5个事件,4个插槽,那该怎么办呢,难道一个个传进去,这样不仅繁琐而且可读性差。 在Vue2中,我们可以这样处理,点击此处查看 封装Vue第三方组件 此文诣在帮助大家做一个知识的迁移,探究如何使用Vue3 CompositionAPI优雅地封装第三方组件~ 在Vue2中 $attrs: 包含了父作用域中不作为 prop 被识别 (且获取) 的 attribute 绑定 (class 和 style 除外)。当一个组件没有声明任何prop 时,这里会包含所有父作用域的绑定 (class 和 style 除外),并且可以通过 v-bind="$attrs" 传入内部组件 $listeners:包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on="$listeners" 传入内部组件 而在Vue3中 $attrs:包含了父作用域中不作为组件 props 或自定义事件的 attribute 绑定和事件(包括 class 和 style和自定义事件),同时可以通过 v-bind="$attrs" 传入内部组件。 $listeners 对象在 Vue 3 中已被移除。事件监听器现在是 $attrs 的一部分。 在 <script setup>中辅助函数useAttrs可以获取到$attrs。 当然,这样还不够。光这样写,我们绑定的属性(包括 class 和 style)同时会在根元素(上面的例子是class="my-input"的Dom节点)上起作用。要阻止这个默认行为,我们需要设置inheritAttrs为false。 下面我们来看看Vue3文档对inheritAttrs的解释 默认情况下父作用域的不被认作 props 的 attribute 绑定 (attribute bindings) 将会“回退”且作为普通的 HTML attribute 应用在子组件的根元素上。当撰写包裹一个目标元素或另一个组件的组件时,这可能不会总是符合预期行为。通过设置 inheritAttrs 到 false,这些默认行为将会被去掉。而通过实例 property $attrs 可以让这些 attribute 生效,且可以通过 v-bind 显性的绑定到非根元素上。 于是,我们对于第三方组件的属性props、事件events处理,可以写成如下代码: Vue3中 $slots:我们可以通过其拿到父组件传入的插槽 Vue3中移除了$scopedSlots,所有插槽都通过 $slots 作为函数暴露 在 <script setup>中辅助函数useSlots可以获取到$slots。 基于以上几点,如果我们对于第三方组件的封装没有增加额外的插槽,且第三方组件的插槽处于同一个dom节点之中,我们也有一种取巧的封装方式????, 通过遍历$slots拿到插槽的name,动态添加子组件的插槽: 如果不满足以上条件的话,咱还得老老实实在子组件中手动添加需要的第三方组件的插槽~ 对于第三方组件的方法,我们通过ref来实现。首先在MyInput组件中的el-input组件上添加一个ref="elInputRef"属性,然后通过defineExpose把elInputRef暴露出去给父组件调用。 子组件:MyInput.vue 父页面:Index.vue的调用代码如下: 以上就是Vue3 Composition API怎么优雅封装第三方组件的详细内容,更多请关注Gxl网其它相关文章!前言
// MyInput.vue<template> <div class="my-input"> <el-input v-model="inputVal" :clearable="clearable" @clear="clear"> <template #prefix> <slot name="prefix"></slot> </template> <template #suffix> <slot name="suffix"></slot> </template> </el-input> </div></template><script setup>import { computed } from 'vue'const props = defineProps({ modelValue: { type: String, default: '' }, clearable: { type: Boolean, default: false }})const emits = defineEmits(['update:modelValue', 'clear'])const inputVal = computed({ get: () => props.modelValue, set: (val) => { emits('update:modelValue', val) }})const clear = () => { emits('clear')}</script>
一、对于第三方组件的属性props、事件events
//MyInput.vue <template> <div class="my-input"> <el-input v-bind="attrs"></el-input> </div></template><script setup>import { useAttrs } from 'vue'const attrs = useAttrs()</script>
// MyInput.vue <template> <div class="my-input"> <el-input v-bind="attrs"></el-input> </div></template><script>export default { name: 'MyInput', inheritAttrs: false}</script><script setup>import { useAttrs } from 'vue'const attrs = useAttrs()</script>
二、对于第三方组件的插槽slots
//MyInput.vue <template> <div class="my-input"> <el-input v-bind="attrs"> <template v-for="k in Object.keys(slots)" #[k] :key="k"> <slot :name="k"></slot> </template> </el-input> </div></template><script>export default { name: 'MyInput', inheritAttrs: false}</script><script setup>import { useAttrs, useSlots } from 'vue'const attrs = useAttrs()const slots = useSlots()</script>
三、对于第三方组件的方法methods
// MyInput.vue <template> <div class="my-input"> <el-input v-bind="attrs" ref="elInputRef"> <template v-for="k in Object.keys(slots)" #[k] :key="k"> <slot :name="k"></slot> </template> </el-input> </div></template><script>export default { name: 'MyInput', inheritAttrs: false}</script><script setup>import { useAttrs, useSlots } from 'vue'const attrs = useAttrs()const slots = useSlots()const elInputRef = ref(null)defineExpose({ elInputRef // <script setup>的组件里的属性默认是关闭的,需通过defineExpose暴露出去才能被调用})</script>
// Index.vue <template> <my-input v-model='input' ref="myInput"> <template #prefix>姓名</template> </my-input></template><script setup>import MyInput from './components/MyInput.vue'import { ref, onMounted } from 'vue'const input = ref('')const myInput = ref(null) // 组件实例onMounted(()=> { myInput.value.elInputRef.focus() // 初始化时调用elInputRef实例的focus方法})</script>