a-select标签mode属性使用及相关操作

1,393 阅读3分钟

最近做的项目中有个小功能比较有趣,拿来跟大家分享一下~

情景

使用<a-select>标签,输入内容并按enter键,实现内容的选中,同时需通过接口将新输入的内容新增。下拉框中选项,需在鼠标移上去时显示删除键和是否已选中的状态。

思路

将a-select标签的mode设置为tags,即可实现输入的内容变成下拉框中的一个标签,即使下拉框中没有该选项,输入后选择就自动添加到下拉框中了。 但是,如果该操作需关联接口的新增功能,那么需要我们注意的地方还有很多!新输入的内容有添加进接口中吗?输入的内容是作为label还是value存在?回显时又是如何?

分析

大家先看如下几张图:

image.png image.png

"tag-enter"是我们手动输入的内容,输入后按enter键,或者点击选中下拉框中新增项就得到了上图中的效果。首先,输入框中有"tag-enter";其次,下拉框中有tag-enter选项,且是已选中的效果。但是我们会发现,鼠标移上去时没有出现删除按钮。

把列表数据打印出来才发现列表数据中压根没有新增的这一项,如下图: image.png

输入框中的数据是[51, "tag-enter"],而下拉选择框中并没有"tag-enter"相关的键值,这明显是不合理的。

以下才是我们需要的效果图和正确的数据:

image.png image.png

有几处细节需要我们格外注意:

1.a-select标签的inputKeyDown方法触发时也会连带着触发select方法,所以在按下enter键或者点击选项时需要判断新数据是否存在,不存在的话再调接口进行新增,避免接口多次调用也是在节省资源。

2.新增数据后,列表数据进行刷新,那么输入框中的数据也需处理成正确格式,比如下拉框选项数据是以idname作为键值对的,那我们的输入框内容就必须是由id组成的数组数据,如果存在name对应的值,需移除并新增对应的id值。

3.通过下拉框选项中的删除键,删除某选项时,输入框中的内容也需过滤掉已删除的内容。

上代码

<a-select
	v-model:value="formRef.relation"
	mode="tags"
	class="w-279px!"
	placeholder="请选择标签(新增标签时最多20字)"
	allow-clear
	@input-key-down="inputKeyDown"
	@select="selectOption"
>
	<a-select-option class="select-item" v-for="item in tagOptions" :key="item.id" :value="item.id">
		<div class="select-option flx-justify-between">
			<div>{{ item.name }}</div>
			<a class="delete-tag-btn" @click.stop="handleDeleteTag(item)">删除</a>
		</div>
	</a-select-option>
</a-select>
const newAddTag = ref(""); // 调新增接口成功新增的标签内容
const isEnter = ref(false); // 判断是否按了 enter 键
function handleNewAddTag() {
	// 如果成功新增了数据
	if (newAddTag.value) {
		// 从接口返回的列表数据中,找到新增数据的具体内容,因为接下来需要用到它的键值
		const newTag = tagOptions.value.find((item: any) => item.name === newAddTag.value);
		// 将输入框中手动输入新增的内容移除(移除的内容是”name“)
		formRef.relation = isArray(formRef.relation)
				? formRef.relation.filter((item: any) => (item.length > 20 ? item.substring(0, 20) : item) !== newAddTag.value)
				: [];
		// 再将新数据的“id”添加进来,这样我们的回显才不会有问题
		if (newTag.id) {
			formRef.relation.push(newTag.id);
		}
	}
}
const tagListApi = async () => {
	try {
		const { data } = await getTagList({
			name: "",
			pageNo: 1,
			pageSize: 1000
		});
		tagOptions.value = data?.list; // 给下拉框中的数据重新赋值
		handleNewAddTag();
	} finally {
	}
};
const deleteTagApi = async (tagInfo: any) => {
	try {
		newAddTag.value = "";
		const { code } = await deleteTag({ id: tagInfo.id });
		if (code === ResultEnum.SUCCESS) {
			message.success("成功");
			tagListApi();
			// 删除下拉框中某选项后,输入框中对应的选项也需移除
			formRef.relation = formRef.relation.filter((item: number) => item !== tagInfo.id);
		}
	} finally {
	}
};
const addTagApi = async (name: string) => {
	try {
		newAddTag.value = "";
		const { code } = await addTag({
			name: name,
			status: 1 // 新增的标签默认有效  1:有效  0:无效
		});
		if (code === ResultEnum.SUCCESS) {
			newAddTag.value = name;
			isEnter.value = false;
			tagListApi();
		}
	} finally {
	}
};
const inputKeyDown = (e: any) => {
	e.target.value = e.target.value.trim(); // 去掉前后空格
	if (e.target.value.length > 20) {
		e.target.value = e.target.value.substring(0, 20);
	}
	if (e.key === "Enter" && e.target.value) {
		isEnter.value = true;
		addTagApi(e.target.value);
	}
};
const selectOption = (value: any) => {
	const hasOldTag = (isArray(tagOptions.value) ? tagOptions.value : []).find(
		(item: any) => item.id === value || item.name === value
	);
	formRef.relation = formRef.relation.filter((tagId: number | string) => Number(tagId) > 0);
	// a-select标签的 inputKeyDown 方法触发时也会触发 select 方法,所以在这里需加上判断,如果是已按下enter键或者点击选项时发现内容已存在或者输入框为空又按了enter,就return出去,否则再调接口进行新增
	if (!value || isEnter.value || hasOldTag) return;
	addTagApi(value);
};