Element Plus 组件库实现:5. Dropdown组件
前言
在数字时代的浪潮中,用户界面的设计与交互体验日益成为软件产品成功与否的关键因素。Dropdown组件,作为用户界面中的常见元素,承载着提供选项列表、优化用户选择流程的重要职责。它不仅简化了用户的操作,也提升了界面的整体美观度和使用便捷性。本文将简单介绍开发Dropdown组件的基本实现。
需求分析
- 可以根据已有的Tooltip组件进行二次开发
- 显示内容为菜单列表
- 菜单中有多个选项,用户可自定义复杂选项
- 使用语义化结构
确定方案
- 属性
import type { VNode } from "vue";
import type { TooltipProps } from "../Tooltip/types";
// 需要在Tooltip组件的属性上进行继承和拓展
export interface DropdownProps extends TooltipProps {
// 传入的菜单项,用一个数组保存
menuOptions: MenuOption[];
// 点击某一项之后关闭菜单展示
afterClickItem?: boolean;
}
// 每一项列表具有的属性
export interface MenuOption {
// 字符串或自定义节点
label: string | VNode;
key: string | number;
disabled?: boolean;
// 分割线
divided?: boolean;
}
- 事件
export interface DropdownEmits {
// 打开列表派发事件
(e: "visible-change", value: boolean): void;
// 选中选项派发事件
(e: "select", value: MenuOption): void;
}
- 实例
export interface DropdownInstance {
show: () => void;
hide: () => void;
}
- 组件
<template>
<div class="yv-dropdown">
<Tooltip>
<!-- 触发区域 -->
<slot></slot>
<!-- 内容区域 -->
<template #content>
<ul>
<template >
<!-- 分割线 -->
<hr >
<!-- 列表 -->
<li>
<RenderVnode />
</li>
</template>
</ul>
</template>
</Tooltip>
</div>
</template>
设计思路
- 使用Tooltip组件进行二次开发
- 菜单列表使用Vnode节点,用户可自定义
- 列表之间可以添加分割线
- 默认插槽为触发区域,触发区域设置为Tooltip中预留的content部分
代码实现
<script>
import { ref } from 'vue'
import Tooltip from '../Tooltip/Tooltip.vue';
import RenderVnode from '@/common/RenderVnode';
import type { DropdownProps, DropdownEmits, MenuOption, DropdownInstance } from './types';
import type { TooltipInstance } from '../Tooltip/types';
defineOptions({
name: "YvDropdown"
})
// 通过ref属性拿到实例
const tooltipRef = ref<TooltipInstance | null>(null)
// 定义属性
const props = withDefaults(defineProps<DropdownProps>(), {
afterClickItem: true
})
// 定义变量
const emits = defineEmits<DropdownEmits>()
// 切换菜单显示/隐藏
const visibleChange = (e: boolean) => {
emits('visible-change', e)
}
// 选中菜单某一项
const itemClick = (e: MenuOption) => {
if (e.disabled) {
return
}
emits('select', e)
if (props.afterClickItem) {
tooltipRef.value?.hide()
}
}
// 暴露出实例属性对应的方法
defineExpose<DropdownInstance>({
// 通过闭包的形式,直接赋值会拿收不到对应的节点,因为是在setup函数中,此时实例还未被挂载
show: () => tooltipRef.value?.show(),
hide: () => tooltipRef.value?.hide()
})
</script>
<template>
<div class="yv-dropdown">
<!-- 其他Tooltip属性不再赘述,这里只列出用到的 -->
<Tooltip @visible-change="visibleChange" ref="tooltipRef">
<slot></slot>
<template #content>
<ul class="yv-dropdown__menu">
<template v-for="item in menuOptions" :key="item.key">
<!-- 分割线 -->
<hr
v-if="item.divided"
role="separator"
class="divided-placeholder"
>
<li
class="yv-dropdown__item"
@click="itemClick(item)"
:class="{
'is-disabled': item.disabled,
'is-divided': item.divided
}
"
:id="`dropdown-item-${item.key}`">
<!-- 中介组件,用户可自定义 -->
<RenderVnode :v-node="item.label" />
</li>
</template>
</ul>
</template>
</Tooltip>
</div>
</template>
总结
本文简单介绍了Dropdown组件的基本实现,基本思路是根据已有的Tooltip组件进行二次开发,在Tooltip的基础上拓展属性,用户可以自定义进行菜单列表的内容,不止可以是文本,还可以是其他更复杂的节点显示。
转载自:https://juejin.cn/post/7362023585518157864