2025-06-08 20:18:35 +08:00

101 lines
2.9 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!-- components/UrlSelect.vue -->
<template>
<el-select
v-bind="$attrs"
v-model="internalValue"
@change="$emit('change', $event)"
@blur="$emit('blur', $event)"
@focus="$emit('focus', $event)"
@clear="$emit('clear', $event)"
@visible-change="$emit('visible-change', $event)"
@remove-tag="$emit('remove-tag', $event)"
@scroll="$emit('scroll', $event)"
>
<!-- 1. 原生 prefix 插槽 -->
<slot name="prefix" />
<!-- 2. 如果要实现分组插槽也照搬 el-option-group 的结构 -->
<slot name="option-group">
<!-- 默认选项渲染 -->
<el-option v-for="item in options" :key="item[valueKey]" :label="item[labelKey]" :value="item[valueKey]" />
</slot>
<!-- 3. 其他自定义插槽不指定 name 的默认为 default slot -->
<slot />
<!-- 4. 下面这几个插槽是 el-select 也常见的 -->
<slot name="empty" />
<slot name="no-match" />
<slot name="footer" />
</el-select>
</template>
<script setup>
import { ref, watch, onMounted } from 'vue';
import request from '@/utils/axios';
// -------------- ① 定义要继承/自定义的 Props --------------
const props = defineProps({
modelValue: {
type: [String, Number, Array],
default: null,
},
url: {
type: String,
default: null,
},
params: {
type: Object,
default: () => ({}),
},
// 可按需让上层指定 label 字段名、value 字段名
labelKey: {
type: String,
default: 'label',
},
valueKey: {
type: String,
default: 'value',
},
});
// -------------- ② 定义要透传回父组件的 Events --------------
const emit = defineEmits(['update:modelValue', 'change', 'blur', 'focus', 'clear', 'visible-change', 'remove-tag', 'scroll']);
// -------------- ③ 内部双向绑定 --------------
// 用一个 ref 存储内部的值
const internalValue = ref(props.modelValue);
// 当 prop 变化时,同步到 internalValue
watch(
() => props.modelValue,
(newVal) => {
internalValue.value = newVal;
}
);
// 当 internalValue 变化时emit update:modelValue
watch(internalValue, (newVal) => {
emit('update:modelValue', newVal);
});
// -------------- ④ 选项列表 --------------
const options = ref([]);
// -------------- ⑤ 请求数据的函数 --------------
async function fetchOptions() {
// console.log('fetchOptions :>> ', props.url, props.params);
if (!props.url) return;
const res = await request.get(props.url, { params: props.params });
const records = res.data.records;
if (Array.isArray(records)) {
options.value = records;
// console.log('option', options.value);
} else {
options.value = [];
console.log('UrlSelect接口返回数据格式不是数组无法解析成 options');
}
}
// -------------- ⑥ 生命周期:组件挂载后立即拉一次数据 --------------
onMounted(() => {
fetchOptions();
});
</script>