zhzf/client/src/components/BaseSelector.vue

153 lines
3.9 KiB
Vue

<template>
<el-select
v-model="cvalue"
class="base-selector"
popper-class="base-selector-popper"
ref="elselect"
clearable
:filterable="config.filterable"
:filter-method="config.filterMethod ? config.filterMethod : filterMethod"
:multiple="config.multiple"
:remote-method="config.remote ? remoteFilter : null"
:remote="config.remote"
:placeholder="computePlaceholder"
:loading="loading"
v-bind="$attrs"
@change="changeSelect"
>
<template #prefix v-if="config.filterable">
<font-awesome-icon :icon="['fas', 'search']" />
</template>
<el-checkbox v-if="config.multiple && config.useSelectAll" v-model="checked" @change="selectAll">全选</el-checkbox>
<el-option
v-for="item in optionData"
:disabled="doDisabledOptionsBy(item)"
v-show="!doDisabledOptionsBy(item)"
:key="item[optionProps.key]"
:label="item[optionProps.label]"
:value="item[optionProps.value]"
/>
<slot name="loadMore"></slot>
</el-select>
</template>
<script setup>
import { ref, computed, watch, onMounted } from 'vue'
const props = defineProps({
config: {
type: Object,
default: () => ({
remote: false,
filterable: false,
multiple: false,
useSelectAll: true,
filterMethod: null,
}),
},
optionProps: {
type: Object,
default: () => ({ key: 'value', label: 'display', value: 'value' }),
},
modelValue: {
type: [Array, String, Number],
default: () => (config.multiple ? [] : ''),
},
data: {
type: Array,
default: () => [],
},
disabledOptions: {
type: Array,
default: () => [],
},
disabledOptionsBy: Function,
placeholder: String,
})
const emit = defineEmits(['update:modelValue', 'remote-filter', 'selected-clear', 'select-load-option', 'change'])
const loading = ref(false)
const checked = ref(false)
const elselect = ref(null)
// 计算属性
const cvalue = computed({
get: () => props.modelValue,
set: (val) => emit('update:modelValue', val),
})
const computePlaceholder = computed(() => props.placeholder || (props.config.filterable ? '请输入查找内容' : '请选择'))
const optionData = ref(props.data)
// 方法
const doDisabledOptionsBy = (item) =>
props.disabledOptionsBy ? props.disabledOptionsBy(item) : props.disabledOptions.includes(item[props.optionProps.value])
const remoteFilter = (query) => {
loading.value = true
setTimeout(() => {
loading.value = false
emit('remote-filter', query)
}, 200)
}
const filterMethod = (query) => {
if (!query) optionData.value = props.data
optionData.value = props.data.filter((option) => {
const label = option[props.optionProps.label]
const value = option[props.optionProps.value]
return label.toLowerCase().includes(query.toLowerCase()) || value.toString().toLowerCase().includes(query.toLowerCase())
})
}
const selectAll = () => {
cvalue.value = checked.value ? optionData.value.map((obj) => obj[props.optionProps.value]) : []
}
const changeSelect = (val) => {
checked.value = Array.isArray(val) ? val.length === optionData.value.length : false
emit('change', val)
}
watch(
() => props.data,
(val) => {
optionData.value = val
}
)
// 生命周期
onMounted(() => {
emit('select-load-option')
})
</script>
<style lang="scss">
.base-selector {
.filter-prefix {
text-align: center;
width: 25px;
}
}
.base-selector-popper {
.left-info-bar {
font-size: 12px;
padding: 0 20px;
position: relative;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
height: 34px;
line-height: 34px;
-webkit-box-sizing: border-box;
box-sizing: border-box;
cursor: pointer;
color: var(--el-color-primary);
font-weight: 700;
font-weight: 700;
}
}
</style>