likes
comments
collection
share

Vue3二次封装UI组件3板斧

作者站长头像
站长
· 阅读数 21

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

vite创建vue3项目

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

Vue3二次封装UI组件3板斧

属性

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

Vue3二次封装UI组件3板斧

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

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

<!-- 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>

<!-- 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上了,我们在绑定过属性后,同时的也绑定了事件,实在是太方便了

Vue3二次封装UI组件3板斧

<!--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>

<!--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,获取父组件传过来的所有插槽

Vue3二次封装UI组件3板斧

<!--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>


<!--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组件上所有的方法,然后循环挂载到一个对象上,然后将对象暴露出去,父组件就可以直接使用子组件暴露的方法!

Vue3二次封装UI组件3板斧

<!--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>



<!-- 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板斧已会,赶紧自己在项目上秀几手吧!