Select 下拉框
Select 组件是一个基于 ElementPlus 下拉框的封装组件, 支持单选、多选、分组、过滤等功能.
基本用法
tsx
import { defineOption } from '@xiaohaih/json-form-plus';
defineOption({
status: {
t: 'select',
label: '状态',
options: [
{ label: '启用', value: 1 },
{ label: '禁用', value: 0 },
],
},
});Props
除了 共享 Props 和 ElSelect 自带的 Props 外, Select 组件还支持以下特定属性:
group
- 类型:
boolean - 默认:
-
是否将选项进行分组
groupChildrenKey
- 类型:
string - 默认:
'children'
存在分组时的读取的子级键
labelKey
- 类型:
string - 默认:
'label'
展示的字段
valueKey
- 类型:
string - 默认:
'value'
提交的字段
valueIsWhole
- 类型:
boolean - 默认:
-
是否将整个选项都作为值传递给 ElOption(相当于忽略 valueKey)
filterable
- 类型:
boolean - 默认:
true
是否可过滤
clearable
- 类型:
boolean - 默认:
true
是否可清除
filterMethod
- 类型:
(val: string, option: T) => boolean - 默认:
-
过滤方法(第一项是搜索值, 第二项是筛选数据, 过滤掉返回 false 的数据)
disabledKey
- 类型:
string - 默认:
'disabled'
选项禁用字段
插槽
插槽项请参考
ElSelect.slots插槽实际的
Props等于插槽自带的Props+SlotProps
插槽示例
tsx
defineOption({
items: {
t: 'select',
label: '项目',
options: Array.from({ length: 100 }, (_, i) => ({
label: `项目 ${i + 1}`,
value: `item_${i + 1}`,
})),
itemSlots: {
header: () => h('div', 'please...'),
},
},
});SlotProps 声明如下
ts
export interface SlotProps {
/**
* 获取传递给 FormItem props
* 可参考 https://element-plus.org/zh-CN/component/form.html#formitem-api
*/
getFormItemProps: () => Record<string, any>;
/** 获取传递给当前 ElementPlus 组件 props */
getItemProps: () => Record<string, any>;
/** 获取传递给当前组件 props */
getProps: () => Record<string, any>;
/** 额外的参数(纯纯的语法糖配置) */
extraOptions: {
/** 传递给组件的值 */
modelValue: any;
/** 数据源 */
options: any;
/** 更新值 */
onChange: (value: any) => void;
};
/** 封装给组件的通用选项 */
plain: PlainReturnValue;
}ts
/** usePlain 的返回值 */
export interface PlainReturnValue {
/** 覆盖 props 的最新的值(defaultValue, initialValue) */
coverProps: Record<'defaultValue' | 'initialValue', any>;
/** HForm 暴露给组件的选项 */
wrapper: WrapperProvideValue;
/** 在特定时机中 HForm 会调用该选项下的方法 */
option: CommonMethod;
/** 数据加载状态 */
loading: Ref<boolean>;
/** 可主动获取远程数据 */
getOptions: (trigger: 'initial' | 'depend' | 'other', option?: {
/** 筛选值 */
filterValue?: string;
}) => Promise<void>;
/** 当前组件的值 */
checked: Ref<any>;
/** 获取当前组件提交给后端的值 */
getQuery: () => Record<string, any>;
/** 远程数据(getOptions 返回的数据) */
remoteOption: Ref<Record<string, any>[]>;
/** 优先返回 remoteOption, 其次返回外部传递的 options */
finalOption: ComputedRef<Record<string, any>[]>;
/** 是否隐藏组件 */
insetHide: ComputedRef<boolean>;
/** 更新值但不触发外部的搜索事件 */
updateCheckedValue: (value: any) => void;
/**
* 更新值并根据 HForm realtime 状态判断
* - realtime: true 则触发搜索事件
* - realtime: false 则仅更新值(等同于 updateCheckedValue 函数)
*/
change: (value: any) => void;
/** 等同于 updateCheckedValue, 只是可以选择不传值(用来兼容低版本) */
trigger: (value?: any) => void;
/** 触发搜索事件 */
search: () => void;
/** 重置 */
reset: () => void;
/** 传递给 HForm 的 readonly 属性 */
globalReadonly: Ref<boolean>;
/** 传递给 HForm 的 disabled 属性 */
globalDisabled: Ref<boolean>;
}
/** 组件提供给 HForm 的选项 */
export interface CommonMethod {
/** 重置 */
reset: () => void;
/** 更新 HForm 中 query 的值 */
updateWrapperQuery: () => void;
/** 校验方法 */
validator?: (query: Record<string, string>) => Promise<any> | any;
/** 获取该组件拼接的参数 */
getQuery: () => Record<string, any>;
/** 在 watch 中 backfill 改变后, 需要执行回调 */
onChangeByBackfill?: () => void;
}
/** HForm 暴露给组件的选项 */
export interface WrapperProvideValue {
/** 表单是否只读 */
readonly?: Ref<boolean | undefined>;
/** 表单是否禁用 */
disabled?: Ref<boolean | undefined>;
/**
* 是否实时触发
*/
realtime: Ref<boolean | undefined>;
/**
* 子组件需主动注册组件, 否则不会生效
* @param {CommonMethod} config 提供父组件校验, 重置等方法
*
* @returns {() => void} 取消注册 - 默认会自动取消, 如果是异步任务内注册, 需自己手动取消
*/
register: (config: CommonMethod) => () => void;
/**
* 子组件通知父级更新 query 中的值 - 静默修改, 不触发搜索事件
* @param {string} field 更新的字段
* @param {*} value 更新的值
* @param {string} nativeField 原始提供的字段(不受 as, fields 等属性的影响)
*/
updateQueryValue: (field: string, value: any, nativeField: string) => void;
/**
* 子组件内部值发生了变动, 由父级决定是否触发搜索事件(实时搜索时需要区分这两种方式)
* @param {string | string[]} [tryFields] 比较 query[tryFields] 与 backfill[tryFields]是否一致, 不一致时才触发搜索
*/
insetSearch: (tryFields?: string | string[]) => void;
/**
* 提供给组件内部的直接触发到外部的搜索事件
*/
search: () => Promise<string | void>;
/** 删除内部无引用的字段 */
removeUnreferencedField: (field: string) => void;
/** 所有条件的 options 数据 */
options: Record<string, any[]>;
}示例
基础下拉框 + 分组下拉框
tsx
defineOption({
category: {
t: 'select',
label: '分类',
options: [
{ label: '技术', value: 'tech' },
{ label: '设计', value: 'design' },
{ label: '产品', value: 'product' },
],
},
city: {
t: 'select',
label: '城市',
group: true,
options: [
{
label: '一线城市',
children: [
{ label: '北京', value: 'beijing' },
{ label: '上海', value: 'shanghai' },
],
},
{
label: '二线城市',
children: [
{ label: '杭州', value: 'hangzhou' },
{ label: '南京', value: 'nanjing' },
],
},
],
},
});自定义过滤 + 远程搜索
tsx
defineOption({
product: {
t: 'select',
label: '产品',
filterable: true,
// 第一项是搜索值, 第二项是筛选数据, 过滤掉返回 false 的数据
filterMethod: (val, option) => {
return option.label.toLowerCase().includes(val.toLowerCase());
},
async getOptions(callback, query) {
const users = await searchUsers();
callback(users);
},
},
user: {
t: 'select',
label: '用户',
// 开启远程搜索
remote: true,
filterable: true,
async getOptions(callback, query, { filterValue }) {
// filterValue 为远程搜索的值
if (!filterValue) return callback([]);
const users = await searchUsers(filterValue);
callback(users);
},
},
});注意事项
- 支持
ElFormItem组件所有的Props - 支持
ElSelect组件所有的Props - 选项对象需要包含
label和value字段或者使用labelKey和valueKey指定 - 启用分组时, 选项需要包含
children字段或使用groupChildrenKey指定 filterMethod和remoteMethod进行过调整, 示例请参考 远程数据 + 远程搜索数据
tips: 当 ElFormItem 组件与 ElSelect 组件的 Props 冲突时
可通过
formItemProps将属性传递给ElFormItem可通过
staticProps将属性传递给ElSelect