antdvue下拉框仿写Select选择器

149 阅读1分钟

a-dropdown组件

  1. overlay插槽 定义自定义内容
  2. 默认插槽是点击区域,使用a-input 组件
  3. a-input 组件中的前缀和后缀。前缀 编写选中后的内容的(可以自定义),后缀展示下拉图标,添加清除图标(更改样式)
  4. 组件封装中a-input有v-model:value, 在封装组件中再定义一个v-model:select,并监听a-input的value值变化来改变 select

a-dropdown :trigger="['click']"实现点击,a-input添加readonly属性让input禁止输入,suffix后缀展示下拉图标,prefix前缀展示自定义内容(类似输入框里面的内容是自定义),清除图标无内容时不展示

<template>
    <a-dropdown :trigger="['click']">
	<template #overlay>
            <slot name="overlay"></slot>
	</template>
	<a-input class="m-input" :style="{width: width}" v-model:value="con" :allow-clear="con != ''" placeholder="请选择" readonly unselectable="on">
            <template v-if="con != ''" #prefix>
		<slot name="oContent"></slot>
            </template>
            <template #suffix>
		<down-outlined class="downIcon" />
            </template>
	</a-input>
    </a-dropdown>
</template>

外面使用v-model, 组件内部也使用v-model,需要使用watchEffect,watch进行分别监听。 没有透传 Attributes,没有往回传值功能

<script setup lang="ts">
	import {
		defineProps,
		defineEmits,
		ref,
		watchEffect,
		watch
	} from "vue"
	import {
		DownOutlined
	} from '@ant-design/icons-vue';

	const con = ref('')

	const prop = defineProps({
		select: String,
		width: String
	})
	const emits = defineEmits(['update:select'])
	watchEffect(() => {
		con.value = prop.select
	})
	watch(con, (value) => {
		emits('update:select', value)
	})
</script>

a-input 悬浮时样式,清除图标展示(有内容时),修改清除图标摆放位置

<style scoped lang="less">
	.m-input:hover {
		:deep(.anticon.ant-input-clear-icon-hidden) {
			visibility: visible;
		}
	}

	:deep(.anticon.ant-input-clear-icon-hidden) {
		position: absolute;
		right: 7px;
		color: #bfbfbf;
	}

	.downIcon {
		font-size: 12px;
		color: #bfbfbf;
	}
</style>

封装组件使用,width 定义input的宽度,v-model:select 进行数据绑定

<my-custom-select width="400px" v-model:select="formState.menuIcon.title">
    <template #overlay>
	<div class="menu-icon-list">
            <div class="menu-icon-item" v-for="info in menuIcons" :key="info.title" @click="iconClick(info)">
		<svg-icon class="m-icon" :icon-class="info.icon" />
		{{info.title}}
            </div>
	</div>
    </template>
    <template #oContent>
	<svg-icon class="m-icon" :icon-class="formState.menuIcon.icon" />
	</template>
</my-custom-select>