- 作者:老汪软件技巧
- 发表时间:2024-10-30 11:02
- 浏览量:
vue@3.3.4 + antdv@3.2.20
一晃几个月没写文章了,每天忙于刷(mō)题(yú),今天突然来了灵感,便来水一篇。
使用select组件,异步获取options列表并对回填数据进行映射时,你一定碰到过这样的情况:
<a-select v-model:value="value" :options="list" placeholder="请选择" />
export default {
setup() {
const value = ref("SHANGHAI");
const list = ref([]);
// 模拟异步
setTimeout(() => {
list.value.push({
label: "上海",
value: "SHANGHAI",
});
}, 2000);
return { value, list }
}
}
要想解决拿到list之前的闪烁,第一反应大概率是:异步获取到options后再回填select的value。
但又面临着一个新的问题:如果碰巧有另一个异步操作中使用到了select的value,那就面临着取不到的风险。(同步更不用说)
<a-select v-model:value="value" :options="list" placeholder="请选择" />
export default {
setup() {
const value = ref(undefined);
const list = ref([]);
setTimeout(() => {
console.log("another value is: ", value.value);
}, 1000);
setTimeout(() => {
list.value.push({
label: "上海",
value: "SHANGHAI",
});
value.value = "SHANGHAI";
console.log("value is: ", value.value);
}, 2000);
return { value, list }
}
}
当然这也不是什么大问题,不管是hack还是从业务逻辑的角度,总能找到解决办法,但本着用正确的方法做事的态度,借助一位登场率不怎么高的朋友——Suspense提供的帮助,来看一种新思路。
众所周知, antdv的select组件提供了一个optionLabel插槽,也就是select选中了某个值后,显示label的那个文本。
为这个插槽提供一个组件:
// comp.vue
<span>{{ options.find(f => f.value === data)?.label }}span>
<script>
export default {
name: "comp",
props: {
options: {
type: Object,
default: () => [],
},
data: {
type: String,
},
},
};
script>
使用异步组件桥接上边这个comp.vue
// asyncComponent.js
import { defineAsyncComponent } from "vue";
const asyncComponent = defineAsyncComponent(async () => {
// 可以将异步获取options的逻辑放在这里,通过store连接起来
// 这里为了方便,就模拟一个时间相同的setTimeout
await new Promise(resolve => {
setTimeout(() => {
resolve();
}, 2000);
});
return import("./comp.vue");
});
export default asyncComponent;
最后,就是修改select的使用方式
<a-select v-model:value="value" :options="list">
<template #optionLabel="props">
<Suspense>
<asyncComponent :options="list" :data="props?.value" />
<template #fallback> 加载中... template>
Suspense>
template>
a-select>
<script>
import asyncComponent from "./asyncComponent";
export default {
components: { asyncComponent },
setup() {
const value = ref("SHANGHAI");
const list = ref([]);
console.log("value is: ", value.value);
// 模拟异步
setTimeout(() => {
list.value.push({
label: "上海",
value: "SHANGHAI",
});
}, 2000);
return { value, list }
}
}
script>
效果如下:加载中...可以换成任何你需要的、合适的内容
既不影响同步操作select值,也没有异步获取options时,真实value闪烁的现象。
使用场景:异步获取options、信息脱敏、国际化翻译等。
这里只是一个思路,可玩性还很大。
优势:
select的文本区域单独抽象成组件利于业务扩展,毕竟labelInValue总有无法满足业务需求的时候;同时也方便处理异步操作中的异常。没有魔改业务逻辑。符合严格贯彻视图与数据分离的MVVM架构项目。处理流程更符合人类认知。为什么这么说,设想一下:
假如你是一个大专前端,名叫小帅,辛勤刷题3个月,终得面试通过拿了大厂offer
某日,你前去办理入职,在楼下费了老鼻子劲才让保安相信你不是要混进去推销信用卡,终于乘电梯来到邮件里约定的楼层
甜美的前台小姐姐:您好~
你:您好,我来办理入职
甜美的前台小姐姐:请问联系您的HR是?
你:小A
小姐姐拿起电话联系HR小A,没多大会便放下了电话:抱歉,请您在那边会议室稍等片刻,小A外出公办,马上就回来了~
此时你有三个选项:
反客为主去楼下等去会议室等选项1结局
你:没关系,你们的前端同事们坐在哪里,我先去干活,等小A回来再给我办就行
说罢,便自顾自的走了进去
甜美的前台小姐姐:???
你狗狗祟祟的转了好几圈,终于找到了藏在厕所门口那片不起眼区域里的前端同学们,也不见外,直接坐在了不知是谁的工位上,熟练的打开vscode、百度、chatgpt三件套,劈里啪啦的操作了起来
众前端:你谁?保安??保安??
剧终。
第二天,你又打开了熟悉的豹斯某聘,开始了日复一日已读不回的生活。
选项2结局
你:没关系,我去楼下等小A,等会我们一起上来
说罢,转身离去。毕竟,高手从不回头看爆炸
甜美的前台小姐姐:诶?啊这。。。
话分两头讲,地铁某号线上
HR小A:歪?我亲爱的小B,坏事了救命,我约了个叫小帅的前端今天来办理入职,时间来不及了我赶不回去,你帮我接一下呗?
电话那头的HR小B:霸某茶姬
小A:成交
小B来到前台:咦,没人啊。咦,前台怎么也不在。啊,一定是小A被鸽了
小B:恍恍惚惚哈哈哈哈你被鸽了,姬不能免
小A:行叭,没事我还有个备选的叫大壮,我联系他叭
剧终。
第二天,你又打开了熟悉的豹斯某聘,开始了日复一日已读不回的生活。
选项3结局
这还有啥好说的啊,正常人不都该这么办嘛?
至于后续,那当然是苦卷数载,终得年薪百万,然后出任CEO,迎娶白富美,走向人生巅峰啊~