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>
结果如下:
暴露被封装组件原来的插槽
/* 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>
结果如下:
暴露组件代码改进
/* 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>
结果如下: