Vue3二次封装UI组件3板斧

作为一个前端开发,精通Vue、React、Node.js等单词书写,职业Ctrl+CCtrl+V使用者,怎么能不会UI组件的二次封装!下面我将详细的介绍二次组件开发,请各位准备好键盘的 Ctrl+CCtrl+V

vite创建vue3项目

这里我是使用vite创建的vue3项目,组件库是使用的element-plus,我们自定义的组件为 MyInput,在App.vue中使用

属性

二次封装UI组件的三板斧,分别是属性、事件、插槽,我们在封装组件的时候,无非是往这个方向,我们就先从属性开始:

可以看出,可传的属性还是很多的,这里我们可以借助$attrs,接收用户往自定义组件传入的所有属性,$attrs继承所有的父组件属性(除了 prop 传递的属性、class 和 style )

Vue3中,$attrs改为useAttrs,功能都是一样的

vue 复制代码
<!-- App.vue -->
<script setup>
import { ref } from 'vue';
import MyInput from "./components/MyInput.vue";

const name = ref('')

</script>

<template>
  <MyInput  v-model="name"  placeholder="自定义组件" clearable    size="large" />
</template>
vue 复制代码
<!-- MyInput.vue -->
<template>
  <div>
    <el-input   v-bind="$attrs"></el-input>
  </div>
</template>


<script setup>
import { useAttrs } from "vue";

defineOptions({
  name: "MyInput",
});

const $attrs = useAttrs()

</script>

属性透传已经完成,我们在MyInput组件上绑定的属性,通过attrs,全部绑定到el-input上

事件

在我们二次封装UI组件时,还需要使用UI库原本的事件,在Vue2时,我们是通过$listeners接收父组件传过来的全部事件,然后通过v-on="$listeners"绑定到el-input上,Vue3中,事件也整合到了useAttrs上了,我们在绑定过属性后,同时的也绑定了事件,实在是太方便了

vue 复制代码
<!--App.vue  -->
<script setup>
import { ref } from 'vue';
import MyInput from "./components/MyInput.vue";

const name = ref('')


const handleInput = ()=>{
  console.log('在 Input 值改变时触发')
}

const handleBlur=()=>{
  console.log('当选择器的输入框失去焦点时触发')
}

</script>

<template>
  <MyInput  v-model="name"  placeholder="自定义组件" clearable    size="large"  @input="handleInput"  @blur="handleBlur" />
</template>
vue 复制代码
<!--MyInput.vue  -->
<template>
  <div>
    <el-input   v-bind="$attrs"></el-input>
  </div>
</template>


<script setup>
import { useAttrs } from "vue";

defineOptions({
  name: "MyInput",
});

const $attrs = useAttrs()

console.log($attrs)
</script>

方法透传已经完成,我们在MyInput组件上绑定的事件,通过useAttrs,全部绑定到el-input上

插槽

在我们二次封装UI组件时,还需要使用UI库原本的插槽,在Vue2时,我们是通过$slots接收所有的插槽,在Vue3中,通过useSlots,获取父组件传过来的所有插槽

vue 复制代码
<!--App.vue  -->
<script setup>
import { ref } from 'vue';
import MyInput from "./components/MyInput.vue";

const name = ref('')


const handleInput = ()=>{
  console.log('在 Input 值改变时触发')
}

const handleBlur=()=>{
  console.log('当选择器的输入框失去焦点时触发')
}

</script>

<template>
  <MyInput  v-model="name"  placeholder="自定义组件" clearable    size="large"  @input="handleInput"  @blur="handleBlur" >
    <template #prepend>Http://</template>
    <template #append>.com//</template>
  </MyInput>
</template>
vue 复制代码
<!--MyInput.vue  -->
<template>
  <div>
    <el-input v-bind="$attrs">
      <template #[slotName]="slotProps" v-for="(slot, slotName) in $slots">
        <slot :name="slotName" v-bind="slotProps"></slot>
      </template>
    </el-input>
  </div>
</template>


<script setup>
import { useAttrs, useSlots } from "vue";

defineOptions({
  name: "MyInput",
});

// 属性和方法
const $attrs = useAttrs();

// 插槽
const $slots = useSlots();
console.log($slots);
</script>

插槽已经完成,我们在MyInput组件上绑定的插槽,通过useSlots,全部传递到el-input上

方法

这是进阶的第四板斧,vue中,我们可以使用ref获取到组件,并且调用组件上的方法,所有UI组件在进行二次封装时,我们也需要获取组件上的方法。我们需要先获取el-iput组件上所有的方法,然后循环挂载到一个对象上,然后将对象暴露出去,父组件就可以直接使用子组件暴露的方法!

vue 复制代码
<!--App.vue  -->
<script setup>
import { ref } from "vue";
import MyInput from "./components/MyInput.vue";

const name = ref("");

const handleInput = () => {
  console.log("在 Input 值改变时触发");
};

const handleBlur = () => {
  console.log("当选择器的输入框失去焦点时触发");
};



const inputRef = ref()
const clearInput = ()=>{
    // console.log(inputRef.value)
    inputRef.value.clear()
}
</script>

<template>
  <div>
    <MyInput
      v-model="name"
      placeholder="自定义组件"
      clearable
      size="large"
      @input="handleInput"
      @blur="handleBlur"
      ref="inputRef"
    >
      <template #prepend>Http://</template>
      <template #append>.com//</template>
    </MyInput>

    <el-button @click="clearInput">清空组件</el-button>
  </div>
</template>
vue 复制代码
<!-- MyInput.vue  -->
<template>
  <div>
    <el-input v-bind="$attrs" ref="inputRef">
      <template #[slotName]="slotProps" v-for="(slot, slotName) in $slots">
        <slot :name="slotName" v-bind="slotProps"></slot>
      </template>
    </el-input>
  </div>
</template>


<script setup>
import { useAttrs, useSlots, ref, onMounted } from "vue";

defineOptions({
  name: "MyInput",
});

// 属性和事件
const $attrs = useAttrs();

// 插槽
const $slots = useSlots();
// console.log($slots);

// 方法  注意这里哦,挂载完才能获取到组件
const inputRef = ref();
const expose = {};
onMounted(() => {
  //  console.log(inputRef.value)
  const entries = Object.entries(inputRef.value);
  // 遍历,将方法全部都放在expose上
  for (const [method, fn] of entries) {
    expose[method] = fn;
  }
});
// 暴露expose上的方法
defineExpose(expose);
</script>

3+1板斧已会,赶紧自己在项目上秀几手吧!

相关推荐
叁两20 小时前
用opencode打造全自动公众号写作流水线,AI 代笔太香了!
前端·人工智能·agent
golang学习记20 小时前
GitLens 十大神技:彻底改变你在 VS Code 中的 Git 工作流
前端·后端·visual studio code
SuperEugene20 小时前
后台权限与菜单渲染:基于路由和后端返回的几种实现方式
前端·javascript·vue.js
兆子龙20 小时前
WebSocket 入门:是什么、有什么用、脚本能帮你做什么
前端·架构
是一碗螺丝粉20 小时前
LangChain 链(Chains)完全指南:从线性流程到智能路由
前端·langchain·aigc
月弦笙音21 小时前
【浏览器】这几点必须懂
前端
青青家的小灰灰21 小时前
迈向全栈新时代:SSR/SSG 原理、Next.js 架构与 React Server Components (RSC) 实战
前端·javascript·react.js
SuperEugene21 小时前
弹窗与抽屉组件封装:如何做一个全局可控的 Dialog 服务
前端·javascript·vue.js
UrbanJazzerati21 小时前
事件传播机制详解(附直观比喻和代码示例)
前端
青青家的小灰灰21 小时前
透视 React 内核:Diff 算法、合成事件与并发特性的深度解析
前端·javascript·react.js