antd级联选择首次加载状态

1,552 阅读1分钟

前言

本文是为了提高我使用ant-design-vue的使用体验而制作的一个库,因为我在组件中没有找到类似的示例,其所提供的属性也无法实现该效果,因此自己实现了一下,说实话,ant-design-vue还是有点用不习惯,毕竟element-ui用顺手了。

效果图

GIF 2021-12-4 星期六 10-16-44.gif
主要是级联选择器的首次加载状态效果,在文档中都是第一次自动加载的,如果第一次加载失败就不知道咋搞。

使用示例

<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>