学习笔记三:vue3 组件二次封装

110 阅读1分钟

vue3 组件封装

为什么要封装组件

1.组件本身功能无法满足业务需要。
2.同时组件本身又有很多基本功能。

如何封装组件

1.直接从父级能够传递原组件的属性和事件。
2.能够直接使用原组件的插槽。
3.添加自己的业务特性。

暴露封装组件原来的全部属性和事件

/*  my-input2.vue  */
<template>
  <div>
    <t-input v-bind="{...$attrs}"></t-input>
  </div>
</template>

<script setup lang="ts"></script>

<style scoped></style>

使用$attrs一个包含了组件所有透传attributes的对象;使用v-bind绑定所有从父组件传递过来的属性

app.vue中使用

<script setup lang="ts">
import {ref} from 'vue';
import MyInput2 from './components/my-input2.vue'
const val=ref('a')
function onChange(val:string){
  console.log('dagn',val);
}
</script>
<template>

  <div>
     <MyInput2 v-model='val' label="姓名" placeholder="请输入姓名" @change='onChange'/>
  </div>
</template>

<style scoped>

</style>

结果如下:

1.png

暴露被封装组件原来的插槽

/*  my-input2.vue  */
<template>
  <div>
    <t-input v-bind="{...$attrs}">
        <template v-for='(val,name,index) in $slots' :key="name" #[name]>
            <slot :name="name"></slot>
        </template>
    </t-input>
  </div>
</template>

<script setup lang="ts">
</script>

<template v-for='(val,name,index) in $slots' #[name]>遍历插槽对象,使用template标签显示input组件的插槽,如果不是input的插槽则不用显示。<slot :name="name"></slot>表示在疯转组件添加新的插槽,插槽名称和 input 的插槽名称一样,这个插槽才是封装组件对外暴露的插槽。

app.vue中使用:

/* app.vue */
<MyInput2
      label="姓名"
      v-model="val"
      placeholder="请输入姓名"
      @change="onChange"
    >
      <template #prefixIcon>*</template>
    </MyInput2>

结果如下:

2.png

暴露组件代码改进

/* my-input.vue */
<template>
    <div>
       我是封装的组件
       <component :is="h(Input,{...props},$slots)"></component>
    </div>
</template>

<script setup lang="ts">
import { h } from 'vue';
import { Input } from 'tdesign-vue-next';
import type {InputProps} from 'tdesign-vue-next'
const props=defineProps<Partial<InputProps>>() // 这样外层就会有t-input组件的属性智能提示
</script>

<style scoped>

</style>

使用h渲染函数直接返回一个动态组件;不在需要$attrs,因为props已经添加了t-input组件的所有属性不需要$attrs再去挂载。但是v-model的属性需要$attrs,在这里$attrs起作用的就不一样了。 在app.vue中使用:

<script setup lang="ts">
import { ref } from "vue";
import myInput from "./components/my-input.vue";
const val = ref("a");
function onChange(val) {
  console.log("输出", val);
}
</script>
<template>
 <myInput v-model='val' placeholder='提示' status='success' @change='onChange'>
      <template #prefixIcon>*</template>
    </myInput>
</template>

结果如下:

3.png