2024.1.19
需求
在element-plus组件库基础上,自定义select内容,左右联动,点击左侧列表内容查看右侧children内容,点击右侧内容选中收起弹框,选项框显示children选中项,如下图:
组件引用
<el-form-item required :label="label" :prop="propKey" :label-width="labelWidth">
<CustomSelectV2
:style="widthStyle"
:defaultValue="formData[propKey]"
:optionList="optionList"
:onSelect="(val) => onChange(propKey, val)"
/>
</el-form-item>
const {
propKey='failProcess',
label='失败处理',
labelWidth='120px',
optionList,onChange
} = props
组件代码
<!--
* @Author: SunnyYang
* @Date: 2024-01-19 14:47:28
* @LastEditors: SunnyYang
* @LastEditTime: 2024-04-07 16:07:39
* @Description:
-->
<template>
<el-select
ref="configSelect"
popper-class="custom-select"
:model-value="selectValue"
clearable
:placeholder="placeholder"
:fit-input-width="true"
:style="{ ...style, minWidth: 'none' }"
@clear="handleClear"
>
<div class="options-left">
<el-option
v-for="item in optionList"
:hide-on-click="false"
:key="item[keyValue]"
:label="item[keyName]"
:value="item[keyValue]"
:class="`el-select-dropdown__item ${fatherSelectValue === item[keyValue] ? 'selected hover' : ''}`"
@click.stop="() => handleLeftClick(item[keyValue])"
>
<span class="option-label">{{ item[keyName] }}</span>
</el-option>
</div>
<div class="options-right">
<el-option
v-for="(stems, index) in childrenOptions[childrenKey]"
:key="stems[childrenKeyValue]"
:label="stems[childrenKeyName]"
:value="stems[childrenKeyValue]"
@click="() => handleRightClick(stems[childrenKeyValue])"
>
<span v-if="childrenKeyIndex">{{ index + 1 }}.</span>
<span class="name">{{ stems[childrenKeyName] }}</span>
<span class="tips" v-if="stems[childrenKeyTips]">{{ stems[childrenKeyTips] }}</span>
</el-option>
</div>
</el-select>
</template>
<script setup name="CustomSelectV2">
import { ref, onMounted ,watch} from 'vue'
const props = defineProps({
defaultValue: {
type: String,
default: '',
},
onSelect: {
type: Function,
default: () => {},
},
optionList: {
type: Array,
default: () => [
// {
// dataCode: '1',
// dataValue: '1',
// children: [{ dataCode: 'children1', dataValue: 'children1' }],
// },
],
},
keyName: {
type: String,
default: 'dataValue',
},
keyValue: {
type: String,
default: 'dataCode',
},
childrenKey: {
type: String,
default: 'children',
},
childrenKeyName: {
type: String,
default: 'dataValue',
},
childrenKeyValue: {
type: String,
default: 'dataCode',
},
childrenKeyTips: {
type: String,
default: 'dataTips',
},
childrenKeyIndex: {
type: Boolean,
default: false,
},
placeholder: {
type: String,
default: '请选择',
},
style: {
type: Object,
default: {
width: '480px',
minWidth: 'none',
},
},
})
const { keyName, keyValue, childrenKey, childrenKeyName, childrenKeyValue } = props
const fatherSelectValue = ref(''), //只用于数据回显 左侧
selectValue = ref(''), //model-value 参数 右侧
childrenOptions = ref({}), //左右联动--右侧子数据
option = ref(props.optionList), //初始化option数据
configSelect = ref(null) // 获取el-select组件实例
onMounted(() => {
option.value = props.optionList
getData()
})
watch(
() => props.optionList,
(newVal) => {
if (newVal) {
option.value = newVal
getData()
}
},
{ deep: true },
)
//input 选中项
function getData() {
// 设置选中项
selectValue.value = props.defaultValue || ''
//通过for in 循环return终止遍历
for (let i in option.value) {
const item = option.value[i],
find = item[childrenKey].find((val) => val[keyValue] === props.defaultValue)
if (find) {
fatherSelectValue.value = item[keyValue] //左侧选中项
childrenOptions.value = item //筛选右侧列表项
return
} else {
// 初始化数据
fatherSelectValue.value = option.value[0][keyValue] //左侧选中项
childrenOptions.value = option.value[0] //筛选右侧列表项
}
}
}
function handleLeftClick(value) {
configSelect.value.visible = true //点击弹框取消隐藏
fatherSelectValue.value = value //左侧选中项
childrenOptions.value = { ...option.value.find((val) => val[keyValue] === value) } //筛选右侧列表项
}
//input 选中项 返回父组件选中项
function handleRightClick(value) {
selectValue.value = value
props.onSelect(value)
}
function handleClear() {
selectValue.value = ''
fatherSelectValue.value = ''
props.onSelect('')
}
</script>
<style lang="scss">
.custom-select {
.el-select-dropdown__list {
width: 100%;
display: flex;
}
.options-left {
width: 40%;
border-right: 1px solid #ccc;
}
.options-right {
width: 60%;
}
.tips {
color: #666;
}
.option-label {
line-height: 34px;
display: block;
width: 100%;
height: 100%;
text-overflow: ellipsis;
overflow: hidden;
word-break: break-all;
white-space: nowrap;
}
}
</style>