在实际的开发中,常常会遇到多级联动选择器但是需要使用单独的el-select来实现的场景,例如省市区选择、分类选择等。本文介绍了一个自定义的 useCascaderSelect 组件钩子函数,封装了三个选择器,通过简单的设置即可应用于多级联动选择,而且可以适应不同的选项的属性值label、value、Children这些。也可以根据需求封装四个五个或者更多
组件的用法
const data: any = ref([...])
const data2: any = ref([...])
const { SelectOne, SelectTwo, SelectThree } = useCascaderSelect()
const { SelectOne: SelectOne2, SelectTwo: SelectTwo2 } = useCascaderSelect({
label: 'name',
value: 'id',
children: 'childrens'
})
<div>
<SelectOne options={data.value} v-model={formData.one} />
<SelectTwo v-model={formData.two} />
<SelectThree v-model={formData.three} />
</div>
<div style="margin-bottom: 10px">
<SelectOne2 options={data2.value} v-model={formData2.one} />
<SelectTwo2 v-model={formData2.two} />
</div>
组件的代码
/*
* @Author:
* @Date: 2024-08-24 01:54:47
* @LastEditors: zengzhaoyan
* @LastEditTime: 2024-08-24 13:45:57
* @Description:
* @FilePath: /zzy/src/views/demo/cascaderSelect/useCascaderSelect.tsx
*/
import { ElSelect, ElOption } from 'element-plus'
import { createVNode, ref, computed } from 'vue'
export const useCascaderSelect = (props?: any) => {
const PropOptions = ref(null)
const labelKey = ref('label')
const valueKey = ref('value')
const childrenKey = ref('children')
/**
* @description: 设置键名配置,用于指定数据对象中的 label、value 和 children 字段的对应键名。
* @Date: 2024-08-24 13:43:55
* @Author:
* @param {any} props
*/
const setKeys = (props: any) => {
if (!props) return
const { label = 'label', value = 'value', children = 'children' } = props
labelKey.value = label
valueKey.value = value
childrenKey.value = children
}
setKeys(props)
/**
* @description: 创建选项节点数组,用于生成 ElSelect 组件的选项。
* @Date: 2024-08-24 13:44:37
* @Author:
* @param {any} options
*/
const createOptionVNodes = (options: any[]) => {
return options.map((option) =>
createVNode(ElOption, {
value: option[valueKey.value],
label: option[labelKey.value]
})
)
}
/**
* @description: 第一个选择器
* @Date: 2024-08-24 13:45:54
* @Author:
*/
const currentOne = ref(null)
let onOneOriginChange: any
const onOneChange = (v: any) => {
if (onOneOriginChange) {
onOneOriginChange(v)
}
currentOne.value = v
onTwoChange(null)
onThreeChange(null)
}
const SelectOne = (props: any, context: any) => {
// 因为数据的获取可能是异步的,所以这里在组件内接受传入的数据
PropOptions.value = props.options
const {
'onUpdate:modelValue': onOneOriginChange,
modelValue,
...restAttrs
} = context.attrs
return createVNode(
ElSelect,
{
...restAttrs,
modelValue,
'onUpdate:modelValue': onOneChange
},
createOptionVNodes(props.options)
)
}
/**
* @description: 第二个选择器
* @Date: 2024-08-24 13:46:10
* @Author:
*/
const currentTwo = ref(null)
let onTwoOriginChange: any
const onTwoChange = (v: any) => {
if (onTwoOriginChange) {
onTwoOriginChange(v)
}
currentTwo.value = v
onThreeChange(null)
}
const two = computed(() => {
const currentOneValue = currentOne.value
const options = PropOptions.value || []
const selectedOption = options.find(
(t: any) => t[valueKey.value] == currentOneValue
)
return selectedOption?.[childrenKey.value || 'children'] ?? []
})
const SelectTwo = (_props: any, context: any) => {
const twoOptions = createOptionVNodes(two.value)
const { 'onUpdate:modelValue': onTwoOriginChange, ...restAttrs } =
context.attrs
return createVNode(
ElSelect,
{
...restAttrs,
modelValue: currentTwo.value,
'onUpdate:modelValue': onTwoChange
},
twoOptions
)
}
/**
* @description: 第三个选择器
* @Date: 2024-08-24 13:46:17
* @Author:
*/
const currentThree = ref(null)
let onThreeOriginChange: any
const onThreeChange = (v: any) => {
if (onThreeOriginChange) {
onThreeOriginChange(v)
}
currentThree.value = v
}
const three = computed(() => {
if (currentOne.value == null && currentTwo.value == null) {
return []
}
const selectedOption = two.value.find(
(t: any) => t[valueKey.value] == currentTwo.value
)
return selectedOption?.[childrenKey.value || 'children'] ?? []
})
const SelectThree = (_props, context: any) => {
const threeOptions = createOptionVNodes(three.value)
const { 'onUpdate:modelValue': onThreeOriginChange, ...restAttrs } =
context.attrs
return createVNode(
ElSelect,
{
...restAttrs,
modelValue: currentThree.value,
'onUpdate:modelValue': onThreeChange
},
threeOptions
)
}
return {
SelectOne,
SelectTwo,
SelectThree
}
}
这样做的好处就是很方便,需要的地方直接引用SelectOne,SelectTwo,SelectThree,并且传入数据就行,根据数据不同的label名,Children名也可以做相应的修改,但是没有做动态加载,大家可以参考参考,自己实现动态的加载