前言
本文是为了提高我使用ant-design-vue的使用体验而制作的一个库,因为我在组件中没有找到类似的示例,其所提供的属性也无法实现该效果,因此自己实现了一下,说实话,ant-design-vue还是有点用不习惯,毕竟element-ui用顺手了。
效果图
主要是级联选择器的首次加载状态效果,在文档中都是第一次自动加载的,如果第一次加载失败就不知道咋搞。
使用示例
<my-select placeholder="请选择" @load-data="loadData" :options="options" v-model:value="value"></my-select>
...
const value = ref([])
const options = ref<any[]>([])
let num = 0
function loadData(action: () => void, done: (isDone?: boolean) => void) {
action()
num++
setTimeout(() => {
if(num>=3){
options.value = [ {value: 1, label: "苹果"}, {value: 2, label: "香蕉"}, ]
done()
}else
done(false)
}, 2000);
}
组件源代码
比较简单,暂时不写解析,直接贴上代码
<template>
<div class="my-select">
<a-cascader
@change="changeSite"
:value="value"
@update:value="(v:any)=>emit('update:value', v)"
:options="options"
:placeholder="placeholder"
style="width: 220px"
:popupVisible="showSitePopup"
@click="click"
@focus="curSitePopup = true"
@blur="curSitePopup = false"
@popupVisibleChange="popupVisibleChange"
>
<template #suffixIcon
><LoadingOutlined v-if="siteStatus == EStatus.Loading" />
<CloseCircleOutlined style="color: red" v-if="siteStatus == EStatus.Error"
/></template>
</a-cascader>
</div>
</template>
<script lang="ts" setup>
import { ref } from "vue"
import { LoadingOutlined, CloseCircleOutlined } from "@ant-design/icons-vue"
enum EStatus {
Normal,
Loading,
Error,
}
const props = withDefaults(
defineProps<{
value?: number[]
options?: any[]
alwaysLoad?: boolean
placeholder?: string
}>(),
{
value: () => [],
options: () => [],
alwaysLoad: false,
placeholder: "",
},
)
const siteStatus = ref<EStatus>(EStatus.Normal)
const curSitePopup = ref(false)
const showSitePopup = ref(false)
function popupVisibleChange(isOpen: boolean) {
if (!isOpen) {
showSitePopup.value = false
}
}
function done(isDone: boolean = true) {
if (isDone) {
siteStatus.value = EStatus.Normal
showSitePopup.value = curSitePopup.value
} else {
siteStatus.value = EStatus.Error
}
}
function action() {
siteStatus.value = EStatus.Loading
}
const emit = defineEmits<{
(e: "loadData", action: () => void, done: (isDone?: boolean) => void): void
(e: "change", value: number[]): void
(e: "update:value", value: any): void
}>()
function click() {
if (siteStatus.value == EStatus.Loading) return
if (!props.alwaysLoad && siteStatus.value == EStatus.Normal && props.options.length) {
done()
return
}
emit("loadData", action, done)
}
function changeSite(value: number[]) {
emit("change", value)
}
</script>
<style lang="less" scoped>
.my-select {
display: inline-block;
:deep(.ant-cascader-picker-clear) {
margin-right: 15px;
}
}
</style>