Vue3实现组件二次封装的小技巧分享

 更新时间:2024年09月12日 09:01:21   作者:唐诗  
组件的二次封装:保留组件已有的功能,需要重写组件方法,当组件已有大量功能时候,则需要重写很多重复代码,且组件功能进行修改的时候,封装的组件也需要对应修改,从而造成许多开发和维护成本,本文给大家分享了Vue3实现组件二次封装的小技巧,需要的朋友可以参考下

双向数据绑定

我们以 input 组件作为例子

双向数据绑定的原理及实现想必大家已经烂熟于心了直接看官网吧!

子组件接受一个 modelValue 的 prop, 通过 emit 触发 update:modelValue 事件完成数据的更新

父组件直接 v-model="xxxx"

嫌麻烦官方还提供了 defineModel() 用于简化上边的步骤

向子组件传递插槽

我们以 input 组件作为例子,创建一个 WrapInput.vue 组件

未学习之前

WrapInput.vue 常规的做法,遍历 $slots 来实现

<script setup lang="ts">
const model = defineModel()

</script>

<template>
  <el-input v-model="model" placeholder="Please input" >
    <template v-for="(_, slot) in $slots" :key="solt" v-slot:[slot]="slotProps">
      <slot :name="slot" v-bind="slotProps"></slot>
    </template>
  </el-input>
</template>

<style lang='scss' scoped></style>

在 app.vue 中引入并传递 prepend、append 插槽

<script setup lang="ts">
import { ref } from "vue";
import WrapInput from "./components/WrapInput.vue";

const inputText = ref('')
</script>

<template>
  <WrapInput v-model="inputText">
    <template #prepend>Http://</template>
    <template #append>.com</template>
  </WrapInput>

  <div>
    {{inputText}}
  </div>
</template>

<style scoped>
</style>

正确渲染了插槽

学习之后

让我们来修改下 WrapInput.vue

<script setup lang="ts">
import { h } from "vue";
import { ElInput } from "element-plus";
const model = defineModel()
</script>

<template>
<component :is="h(ElInput, $attrs, $slots)" v-model="model"></component>
</template>

<style lang='scss' scoped></style>

app.vue 的代码不做任何修改

插槽正常传递、数据更新正常,看到这种写法的时候有点震惊的

component 组件为什么可以传入 h 函数

看下 h 函数的文档, h(ElInput, $attrs, $slots) 是创建了一个虚拟 dom 节点

而 component 组件的 is 属性则可以接收

  • 被注册的组件名
  • 导入的组件对象
  • 一个返回上述值之一的函数

component 组件的 is 属性接收到一个函数时,Vue 会调用这个函数并使用其返回值作为要渲染的组件。

在这种情况下,h(ElInput, $attrs, $slots) 会立即执行并返回一个 VNode,这个 VNode 描述了如何渲染 ElInput 组件。

获取子组件的 ref

未学习之前

之前的自己的写法有点蠢的具体的做法是在子组件创建一个 getRef 的函数把 ref 暴露出去,父组件调用 getRef 方法后在执行子组件方法的调用,大概是下边这样

WrapInput1.vue

<script setup lang="ts">
import { h, ref} from "vue";
import { ElInput } from "element-plus";
const model = defineModel()

const inputRef = ref()

function getRef () {
  return inputRef.value
}

defineExpose({
  getRef
})
</script>

<template>
  <component ref="inputRef" :is="h(ElInput, $attrs, $slots)" v-model="model"></component>
</template>

<style lang='scss' scoped></style>

学习之后

WrapInput.vue

<script setup lang="ts">
import { h, ref } from "vue";
import { ElInput } from "element-plus";
const model = defineModel()

const inputRef = ref()

defineExpose(new Proxy({}, {
  get(_target, prop)  {
    return inputRef.value?.[prop]
  },
  has (_target, prop) {
    return prop in inputRef.value
  }
}))

</script>

<template>
  <component :is="h(ElInput, $attrs, $slots)" v-model="model" ref="inputRef"></component>
</template>

<style lang='scss' scoped></style>

使用 Proxy 代理暴露出去的方法,是有点震惊的,还能这么写

App.vue

<script setup lang="ts">
import { ref } from "vue";
import WrapInput from "./components/WrapInput.vue";

const inputText = ref('')

const prependSlotText =  ref('Http://')
const appendSlotText =  ref('.com')

function updateSlotInfo (){
  prependSlotText.value = 'https://'
  appendSlotText.value = `${new Date().getTime()}`
}

const wrapInputRef = ref()
function setWrapInputFocus () {
  wrapInputRef.value?.focus()
}
</script>

<template>
  <WrapInput v-model="inputText" ref="wrapInputRef">
    <template #prepend>{{ prependSlotText }}</template>
    <template #append>{{ appendSlotText }}</template>
  </WrapInput>

  <div style="margin: 20px 0;">
    {{inputText}}
  </div>

  <el-button type="primary" @click="updateSlotInfo">更新插槽内容</el-button>
  <el-button type="primary" @click="setWrapInputFocus">set input focus</el-button>
  
</template>

<style scoped>
</style>

调用组件的 focus 方法让 WrapInput.vue 组件获取焦点

总结

本文实践了在 vue3 中在二次封装组件时如何实现 v-model、插槽传递、子组件 ref 获取

插槽传递通过向 component 组件的 is 属性传递 h 函数创建虚拟 dom 来实现

获取子组件的 ref 则是使用 new Proxy 的方式来实现

以上就是Vue3实现组件二次封装的小技巧分享的详细内容,更多关于Vue3组件二次封装的资料请关注脚本之家其它相关文章!

相关文章

  • vxe-table vue 表格禁用单元格编辑的两种实现方式

    vxe-table vue 表格禁用单元格编辑的两种实现方式

    本文介绍vxe-table禁用单元格编辑的两种方式,本文结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2025-06-06
  • 深入理解Vue3 computed

    深入理解Vue3 computed

    本文主要介绍了Vue3 computed的使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2025-08-08
  • Vue中消息横向滚动时setInterval清不掉的问题及解决方法

    Vue中消息横向滚动时setInterval清不掉的问题及解决方法

    最近在做项目时,需要进行两个组件联动,一个轮询获取到消息,然后将其传递给另外一个组件进行横向滚动展示,结果滚动的速度越来越快。接下来通过本文给大家分享Vue中消息横向滚动时setInterval清不掉的问题及解决方法,感兴趣的朋友一起看看吧
    2019-08-08
  • vue之ele多级联组件的使用方法详解

    vue之ele多级联组件的使用方法详解

    这篇文章为大家详细主要介绍了vue之ele多级联组件的使用方法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-07-07
  • 如何基于uniapp开发android播放webrtc流详解

    如何基于uniapp开发android播放webrtc流详解

    这篇文章主要介绍了在uniapp中播放RTSP和WebRTC协议流的区别,以及如何封装WebrtcVideo组件和音视频实时通讯的实现,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2025-02-02
  • Vue3 封装扩展并简化Vuex在组件中的调用问题

    Vue3 封装扩展并简化Vuex在组件中的调用问题

    这篇文章主要介绍了Vue3 封装扩展并简化Vuex在组件中的调用,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-01-01
  • 详解elementui之el-image-viewer(图片查看器)

    详解elementui之el-image-viewer(图片查看器)

    这篇文章主要介绍了详解elementui之el-image-viewer(图片查看器),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-08-08
  • Vue切换Tab动态渲染组件的操作

    Vue切换Tab动态渲染组件的操作

    这篇文章主要介绍了Vue切换Tab动态渲染组件的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-09-09
  • 用Vue写一个分页器的示例代码

    用Vue写一个分页器的示例代码

    本篇文章主要介绍了用Vue写一个分页器的示例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-04-04
  • vue 实现dot-dropdown的实例代码

    vue 实现dot-dropdown的实例代码

    这篇文章主要介绍了vue实现dot-dropdown的相关操作,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2025-06-06

最新评论