多选
<template>
<Picker
label="label"
text-column="name"
:label-width="250"
:dict-data-list="columns"
value-column="value"
v-model="modelValue"
placeholder="请选择"
:multiple="true"
required
:rules="[{ required: true, message: '请选择' }]"
:readonly="readonly"
/>
</template>
<script>
import Picker from '@/views/alpaca/components/Picker'
modelValue:"1,2"
columns:[
{
text:"选项1",
value:"1"
},
{
text:"选项2",
value:"2"
}
]
</script>
单选
<template>
<Picker
label="label"
text-column="text"
v-model="modelValue"
:dict-data-list="columns"
value-column="value"
placeholder="请选择"
:label-width="180"
:readonly="readonly"
required
:rules="[{ required: true, message: '请选择' }]"
/>
</template>
<script>
import Picker from '@/views/alpaca/components/Picker'
modelValue:"1"
columns:[
{
text:"选项1",
value:"1"
},
{
text:"选项2",
value:"2"
}
]
</script>
picker组件
<template>
<div class="clearfix">
<van-field
v-model="text"
:required="required"
readonly
is-link
:class="readonly ? 'dict-select-readonly' : ''"
autocomplete="off"
@click="showComponentTypePicker"
:type="multiple ? 'textarea' : 'text'"
:autosize="multiple"
rows="1"
:label-width="labelWidth"
:label="label"
:colon="colon"
:rules="rules"
:placeholder="placeholder"
:disabled="readonly"
/>
<van-popup
v-model:show="showPicker"
round
position="bottom"
style="height: 300px"
:close-on-click-overlay="false"
:lazy-render="false"
>
<template v-if="multiple">
<!--多选弹出层-->
<div style="display: flex;justify-content: space-between;padding:0 10px;">
<div
@click="onDictSelectCancel"
style="
margin-bottom: 15px;
margin-top: 10px;
color: #969799;
cursor: pointer;
text-align: center;
"
>取消</div
>
<div
@click="onDictMultipleSelectConfirm"
style="
margin-bottom: 15px;
margin-top: 10px;
color: #576b95;
cursor: pointer;
text-align: center;
"
>确定</div
>
</div>
<van-checkbox-group v-model="checkedList">
<van-cell-group>
<van-cell
v-for="(element, index) in dataList"
:key="element.value"
clickable
:title="element.text"
@click="toggle(index)"
>
<template #right-icon>
<van-checkbox :name="JSON.stringify(element)" @click.stop/>
</template>
</van-cell>
</van-cell-group>
</van-checkbox-group>
</template>
<template v-else>
<!--单选弹出层-->
<van-picker
ref="dictSelectPicker"
show-toolbar
v-model="realValuePickerList"
:columns="dataList"
@confirm="onDictSelectConfirm"
@cancel="onDictSelectCancel"
/>
</template>
</van-popup>
</div>
</template>
<script>
import { ref, watch } from 'vue'
export default {
name: 'DictSelect',
props: {
dictType: {
type: String,
default: '',
},
dictDataList: {
type: Array,
default: () => [],
},
label: {
type: String,
default: '字典选择器',
},
labelWidth: {
type: Number,
default: 100,
},
colon: {
type: Boolean,
default: false,
},
placeholder: {
type: String,
default: '请选择',
},
textColumn: {
type: String,
default: 'dictLabel',
},
valueColumn: {
type: [String, Number],
default: 'dictValue',
},
rules: {
type: Array,
default: () => [],
},
readonly: {
type: Boolean,
default: false,
},
required: {
type: Boolean,
default: false,
},
multiple: {
type: Boolean,
default: false,
},
modelValue: {
required: false,
},
},
setup(props, { emit }) {
const showPicker = ref(false)
const text = ref('')
const realValue = ref('')
const realValuePickerList = ref([])
const dataList = ref([])
const checkedList = ref([])
const createDictData = (data) => {
dataList.value = data.map(item => ({
text: item[props.textColumn].toString(),
value: item[props.valueColumn].toString(), // Ensure conversion to string
}))
reloadData()
}
const reloadData = () => {
if (realValue.value) {
const realValueList = realValue.value.split(',')
checkedList.value = []
text.value = ''
realValueList.forEach(value => {
const currentItem = dataList.value.find(item => item.value === value)
if (currentItem) {
if (props.multiple) {
checkedList.value.push(JSON.stringify({
text: currentItem.text,
value: value,
}))
} else {
realValuePickerList.value.push(value)
}
if (text.value === '') {
text.value = currentItem.text
} else {
text.value += ',' + currentItem.text
}
}
})
}
}
const showComponentTypePicker = () => {
reloadData()
showPicker.value = true
}
const onDictSelectCancel = () => {
showPicker.value = false
}
const onDictSelectConfirm = ({ selectedOptions }) => {
if (selectedOptions[0]) {
text.value = selectedOptions[0].text.toString()
realValue.value = selectedOptions[0].value.toString()
realValuePickerList.value = [realValue.value]
emit('update:modelValue', realValue.value)
emit('changeData', selectedOptions[0])
showPicker.value = false
}
}
const onDictMultipleSelectConfirm = () => {
const temTextArray = []
const temValueArray = []
checkedList.value.forEach(item => {
const parsedItem = JSON.parse(item)
temTextArray.push(parsedItem.text)
temValueArray.push(parsedItem.value)
})
text.value = temTextArray.join(',')
realValue.value = temValueArray.join(',')
emit('update:modelValue', realValue.value)
emit('changeData', { text: text.value, value: realValue.value })
showPicker.value = false
}
const toggle = (index) => {
checkedList.value[index] = !checkedList.value[index];
}
watch(() => props.modelValue, (newValue) => {
if (typeof newValue === 'string' || typeof newValue === 'number') {
realValue.value = newValue.toString();
reloadData()
} else {
realValue.value = '';
}
}, { immediate: true })
watch(() => props.dictDataList, (newData) => {
if (newData && newData.length > 0) {
createDictData(newData)
}
}, { immediate: true })
return {
showPicker,
text,
realValue,
realValuePickerList,
dataList,
checkedList,
showComponentTypePicker,
onDictSelectCancel,
onDictSelectConfirm,
onDictMultipleSelectConfirm,
toggle,
}
},
}
</script>
<style scoped>
.van-cell {
padding: 10px 20px;
}
.dict-select-readonly {
pointer-events: none;
}
.van-cell--required::before {
position: absolute;
left: -3px;
color: #ee0a24;
font-size: 14px;
content: '*';
}
</style>