前言
下面谈谈如何使用provide
和inject
来封装一个列表项信息展示高级组件。比如UI
组件库的表单组件除了展示表单输入项,也可以进行表单项的信息展示。本文的目的也是通过这个列表项信息展示的栗子,来使大家对高级组件封装和provide
/inject
能有更深的理解。
关键词: vue3、ts、provide/inject、高级组件封装,列表项信息展示。
组件封装
下面封装了一个列表项容器组件VList
和列表项组件VListItem
。
1.
VList
容器组件负责定义向所有VListItem
组件传递的公共参数,比如labelWidth
标签宽度和suffix
标签后缀,从而不需要每一个VListItem
列表项都传递一遍。2.
VListItem
则只负责维护自身组件的内部状态。
VList列表容器组件
<template>
<div class="v-list">
<slot></slot>
</div>
</template>
<script setup lang="ts">
import { provide } from 'vue'
import type { VListProps } from './index.d'
import { Props } from './constant'
const props = withDefaults(defineProps<VListProps>(), {
labelWidth: '100px'
})
provide(Props, props)
</script>
./index.d文件
export type VListProps = {
suffix?: string,
labelWidth?: string
}
./constant文件
import type { InjectionKey } from 'vue'
import type { VListProps } from './index.d'
export const Props = Symbol() as InjectionKey<VListProps>
provide
和 inject
通常会在不同的组件中运行。要正确地为注入的值标记类型,Vue
提供了一个 InjectionKey
接口,它是一个继承自 Symbol
的泛型类型,可以用来在提供者和消费者之间同步注入值的类型。参考:为 provide / inject 标注类型
VListItem列表项组件
<template>
<div class="v-list-item">
<div class="label">
{{ label }}
<span class="suffix" v-if="vListProps.suffix">{{ vListProps.suffix }}</span>
</div>
<div class="value">{{ value }}</div>
</div>
</template>
<script setup lang="ts">
import { inject, computed } from 'vue'
import { Props } from './constant'
const vListProps = inject(Props, {})
const props = defineProps<{
label: string,
value: string,
labelWidth?: string
}>()
const labelWidth = computed(() => {
// 优先使用自身组件的label宽度
return props.labelWidth || vListProps.labelWidth
})
</script>
<style scoped lang="scss">
.v-list-item {
display: flex;
padding: 10px;
.label {
width: v-bind(labelWidth);
}
}
</style>
在列表项组件注入了列表容器组件的Props
(包括labelWidth
和suffix
参数),并在组件内部定义了一个计算属性labelWidth
优先使用列表容器组件的labelWidth
,最后在css
中通过v-bind(labelWidth)
应用样式;suffix
参数(标签后缀)的道理也是一样。看到这,相信大家完全有能力进行举一反三,实现更多其他需求!
用法
<script setup lang="ts">
import { VList, VListItem } from '@/components/VList';
</script>
<template>
<div>
<VList suffix=":" label-width="150px">
<VListItem label="姓名" value="张三"></VListItem>
<VListItem label="性别" value="男"></VListItem>
<VListItem label="手机号码" value="152********"></VListItem>
</VList>
</div>
</template>
components/VList/index.ts文件
export { default as VList } from './VList.vue'
export { default as VListItem } from './VListItem.vue'
页面效果:
总结
在本例子中的核心思想就是把所有子组件的公共参数提取到容器组件当中,再通过provide
向所有子组件注入所有公共参数;在子组件中通过inject
接收父组件注入的参数。从而达到简化代码,提升代码可维护性的目的。
掘金2024年度人气创作者打榜中,快来帮我打榜吧~ activity.juejin.cn/rank/2024/w…