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组件二次封装的资料请关注脚本之家其它相关文章!

相关文章

  • 一文详解Vue.js生产环境文件及优化策略

    一文详解Vue.js生产环境文件及优化策略

    随着 Vue.js 在前端开发中的普及,如何高效地将 Vue 项目部署到生产环境成为了开发者关注的重点,本文将详细解析 Vue.js 生产环境文件的使用方法、优缺点以及优化策略,需要的朋友可以参考下
    2024-12-12
  • vue + electron应用文件读写操作

    vue + electron应用文件读写操作

    这篇文章主要介绍了vue + electron应用文件读写操作,如果要制作的应用并不复杂,完全可以将数据存储在本地文件当中,然后应用就可以通过这些文件进行数据的读写,需要的朋友参考下吧
    2022-06-06
  • vue 点击删除常用方式小结

    vue 点击删除常用方式小结

    这篇文章主要介绍了vue 点击删除常用方式小结,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-04-04
  • 解决VantUI popup 弹窗不弹出或无蒙层的问题

    解决VantUI popup 弹窗不弹出或无蒙层的问题

    这篇文章主要介绍了解决VantUI popup 弹窗不弹出或无蒙层的问题。具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-11-11
  • vue使用canvas手写输入识别中文

    vue使用canvas手写输入识别中文

    这篇文章主要介绍了vue使用canvas手写输入识别中文,工作时遇到一些项目如:系统上的输入法使用不方便,客户要求做一个嵌入web网页的手写输入法。下面我们来看看文章得具体描述吧
    2021-11-11
  • vue前端重构computed及watch组件通信等实用技巧整理

    vue前端重构computed及watch组件通信等实用技巧整理

    这篇文章主要为大家介绍了vue前端重构computed及watch组件通信等实用技巧整理,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-05-05
  • vue2+element-ui新增编辑表格+删除行功能

    vue2+element-ui新增编辑表格+删除行功能

    这篇文章主要介绍了vue2+element-ui新增编辑表格+删除行功能,本文通过示例代码给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧
    2024-07-07
  • vue3 腾讯地图设置签到范围并获取经纬度的实现代码

    vue3 腾讯地图设置签到范围并获取经纬度的实现代码

    本文给大家介绍vue3 腾讯地图设置签到范围并获取经纬度的实现代码,本文通过示例代码给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧
    2022-05-05
  • 快速掌握Vue3.0中如何上手Vuex状态管理

    快速掌握Vue3.0中如何上手Vuex状态管理

    Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式,本文给大家分享Vue3.0中快速上手Vuex状态管理的方式,本文通过实例代码讲解的很详细,对大家学习Vuex状态管理相关知识有很大的帮助,感兴趣的朋友一起学习吧
    2021-05-05
  • vue3.0 setup中使用vue-router问题

    vue3.0 setup中使用vue-router问题

    这篇文章主要介绍了vue3.0 setup中使用vue-router问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-10-10

最新评论