You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
167 lines
4.2 KiB
167 lines
4.2 KiB
<template>
|
|
<el-form-item :class="[{ 'column': column }, 'form-item']" :label="label" :prop="prop" :rules="rules"
|
|
:required="required">
|
|
<el-radio-group v-model="selectedValue" v-bind="$attrs" @change="handleChange">
|
|
<el-radio v-for="(optionValue, optionKey) in normalizedOptions" :key="optionKey"
|
|
:label="getValue(optionValue)" :disabled="isDisabled(optionValue[valueKey])">
|
|
{{ getLabel(optionValue) }}
|
|
</el-radio>
|
|
</el-radio-group>
|
|
</el-form-item>
|
|
</template>
|
|
|
|
<script>
|
|
export default {
|
|
name: 'MyRadioGroup',
|
|
props: {
|
|
// 是否是纵向排列
|
|
column: {
|
|
type: String,
|
|
default: ''
|
|
},
|
|
required: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
selectedLabelKey: {
|
|
type: String,
|
|
default: ''
|
|
},
|
|
// 选项列表,支持多种格式:
|
|
// 1. 数组格式: [{ label: '显示文本', value: '值', disabled: false }]
|
|
// 2. 对象格式: { key1: 'value1', key2: 'value2' }
|
|
// 3.null
|
|
// 4.‘’
|
|
options: {
|
|
// type: [Array, Object],
|
|
default: () => null,
|
|
validator: (value) => {
|
|
// 自定义验证器,允许 null、数组或非空对象
|
|
return value == null ||
|
|
value === '' ||
|
|
Array.isArray(value) ||
|
|
(typeof value === 'object' && value !== null)
|
|
},
|
|
required: true,
|
|
},
|
|
// 当前选中的值,使用 v-model 绑定
|
|
value: {
|
|
type: [String, Number, Boolean],
|
|
default: '',
|
|
},
|
|
// 表单项的 label
|
|
label: {
|
|
type: String,
|
|
default: '',
|
|
},
|
|
// 表单项的 prop(用于表单校验)
|
|
prop: {
|
|
type: String,
|
|
default: '',
|
|
},
|
|
// 校验规则
|
|
rules: {
|
|
type: Array,
|
|
default: () => [],
|
|
},
|
|
labelKey: {
|
|
type: String,
|
|
default: 'label'
|
|
},
|
|
// 自定义value的字段名
|
|
valueKey: {
|
|
type: String,
|
|
default: 'value'
|
|
},
|
|
// 格式化label的函数
|
|
formatter: {
|
|
type: Function,
|
|
default: null
|
|
},
|
|
// 禁用选项的key数组
|
|
disabledKeys: {
|
|
type: Array,
|
|
default: () => []
|
|
}
|
|
},
|
|
computed: {
|
|
// 统一处理数组和对象格式
|
|
normalizedOptions() {
|
|
// 处理null或undefined、‘’情况
|
|
if (this.options == null || !this.options) {
|
|
return [];
|
|
}
|
|
|
|
// 处理数组
|
|
if (Array.isArray(this.options)) {
|
|
return this.options.length ? this.options : [];
|
|
}
|
|
|
|
// 处理对象
|
|
if (typeof this.options === 'object') {
|
|
const keys = Object.keys(this.options);
|
|
return keys.length ? keys.map(key => ({
|
|
key,
|
|
value: this.options[key]
|
|
})) : [];
|
|
}
|
|
|
|
// 其他意外情况返回空数组
|
|
return [];
|
|
}
|
|
},
|
|
data() {
|
|
return {
|
|
selectedValue: this.value, // 内部维护的选中值
|
|
};
|
|
},
|
|
watch: {
|
|
// 监听外部传入的 value 变化,更新内部 selectedValue
|
|
value(newVal) {
|
|
this.selectedValue = newVal;
|
|
},
|
|
},
|
|
methods: {
|
|
// 选中值变化时触发
|
|
handleChange(value) {
|
|
this.$emit('input', value); // 更新 v-model
|
|
this.$emit('change', value); // 触发 change 事件
|
|
},
|
|
getLabel(option) {
|
|
if (this.formatter) return this.formatter(option);
|
|
|
|
// 处理对象格式的选项
|
|
if (typeof option === 'object' && 'key' in option && 'value' in option) {
|
|
return option.value;
|
|
}
|
|
|
|
// 当前选项是否选中
|
|
const isSelected = this.getValue(option) === this.selectedValue;
|
|
|
|
// 选中状态下优先返回selectedLabel,其次返回labelKey指定的属性
|
|
return isSelected && option[this.selectedLabelKey]
|
|
? option[this.selectedLabelKey]
|
|
: option[this.labelKey] || option;
|
|
},
|
|
getValue(option) {
|
|
// 处理对象格式的选项
|
|
if (typeof option === 'object' && 'key' in option && 'value' in option) {
|
|
return option.key;
|
|
}
|
|
|
|
return option[this.valueKey] || option;
|
|
},
|
|
// 判断选项是否禁用
|
|
isDisabled(key) {
|
|
return this.disabledKeys.includes(key);
|
|
}
|
|
},
|
|
};
|
|
</script>
|
|
|
|
<style scoped>
|
|
/* 自定义样式 */
|
|
.el-radio-group {
|
|
margin: 10px 0;
|
|
}
|
|
</style>
|