Select 下拉选择
下拉选择组件,支持单选、禁用选项、自定义样式等功能。
基础用法
简单选择。
html
<div id="demo-select" style="width: 200px;"></div>
<script>
const select = new SaSelect('#demo-select', {
options: [
{ label: '选项一', value: '1' },
{ label: '选项二', value: '2' },
{ label: '选项三', value: '3' }
]
});
SA.init('body');
</script>加载 SanoUI 组件中...
设置默认值
通过 value 参数设置默认选中的值。
html
<div id="demo-select-default" style="width: 200px;"></div>
<script>
const select = new SaSelect('#demo-select-default', {
options: [
{ label: '选项一', value: '1' },
{ label: '选项二', value: '2' },
{ label: '选项三', value: '3' }
],
value: '2' // 默认选中选项二
});
SA.init('body');
</script>加载 SanoUI 组件中...
自定义占位符
通过 placeholder 参数自定义占位符文本。
html
<div id="demo-select-placeholder" style="width: 200px;"></div>
<script>
const select = new SaSelect('#demo-select-placeholder', {
options: [
{ label: '选项一', value: '1' },
{ label: '选项二', value: '2' }
],
placeholder: '请选择选项'
});
SA.init('body');
</script>加载 SanoUI 组件中...
禁用选项
在选项对象中设置 disabled: true 可以禁用某个选项。
html
<div id="demo-select-disabled" style="width: 200px;"></div>
<script>
const select = new SaSelect('#demo-select-disabled', {
options: [
{ label: '选项一', value: '1' },
{ label: '选项二(禁用)', value: '2', disabled: true },
{ label: '选项三', value: '3' }
]
});
SA.init('body');
</script>加载 SanoUI 组件中...
自动打开
通过 autoOpen: true 可以在组件创建时自动打开下拉框。
html
<div id="demo-select-auto-open" style="width: 200px;"></div>
<script>
const select = new SaSelect('#demo-select-auto-open', {
options: [
{ label: '选项一', value: '1' },
{ label: '选项二', value: '2' }
],
autoOpen: true
});
SA.init('body');
</script>加载 SanoUI 组件中...
动态更新选项
使用 setOptions() 方法可以动态更新选项列表。
html
<div id="demo-select-dynamic" style="width: 200px; margin-bottom: 12px;"></div>
<div style="display: flex; gap: 8px;">
<button class="sa-button sa-button--primary" id="btn-update-options">更新选项</button>
<button class="sa-button" id="btn-clear-options">清空选项</button>
</div>
<script>
const select = new SaSelect('#demo-select-dynamic', {
options: [
{ label: '选项一', value: '1' },
{ label: '选项二', value: '2' }
]
});
document.getElementById('btn-update-options').addEventListener('click', () => {
select.setOptions([
{ label: '新选项一', value: '1' },
{ label: '新选项二', value: '2' },
{ label: '新选项三', value: '3' }
]);
});
document.getElementById('btn-clear-options').addEventListener('click', () => {
select.setOptions([]);
});
SA.init('body');
</script>加载 SanoUI 组件中...
动态设置值
使用 setValue() 方法可以动态设置选中的值。
html
<div id="demo-select-set-value" style="width: 200px; margin-bottom: 12px;"></div>
<div style="display: flex; gap: 8px;">
<button class="sa-button sa-button--primary" id="btn-set-value-1">设置为"选项1"</button>
<button class="sa-button" id="btn-set-value-2">设置为"选项2"</button>
</div>
<script>
const select = new SaSelect('#demo-select-set-value', {
options: [
{ label: '选项一', value: '1' },
{ label: '选项二', value: '2' },
{ label: '选项三', value: '3' }
]
});
document.getElementById('btn-set-value-1').addEventListener('click', () => {
select.setValue('1');
});
document.getElementById('btn-set-value-2').addEventListener('click', () => {
select.setValue('2');
});
SA.init('body');
</script>加载 SanoUI 组件中...
事件回调
onChange 回调
通过 onChange 回调函数监听值的变化。
html
<div id="demo-select-onchange" style="width: 200px; margin-bottom: 12px;"></div>
<div id="onchange-result" style="padding: 12px; background: #f5f5f5; border-radius: 4px; font-size: 14px; color: #666;">
当前选中的值:<span id="onchange-value">-</span>
</div>
<script>
const select = new SaSelect('#demo-select-onchange', {
options: [
{ label: '选项一', value: '1' },
{ label: '选项二', value: '2' },
{ label: '选项三', value: '3' }
],
onChange: (value, option) => {
document.getElementById('onchange-value').textContent = value || '-';
console.log('选中的值:', value);
console.log('选中的选项:', option);
}
});
SA.init('body');
</script>加载 SanoUI 组件中...
onClose 回调
通过 onClose 回调函数监听下拉框关闭事件。
html
<div id="demo-select-onclose" style="width: 200px; margin-bottom: 12px;"></div>
<div id="onclose-result" style="padding: 12px; background: #f5f5f5; border-radius: 4px; font-size: 14px; color: #666;">
下拉框关闭次数:<span id="onclose-count">0</span>
</div>
<script>
let closeCount = 0;
const select = new SaSelect('#demo-select-onclose', {
options: [
{ label: '选项一', value: '1' },
{ label: '选项二', value: '2' }
],
onClose: () => {
closeCount++;
document.getElementById('onclose-count').textContent = closeCount;
console.log('下拉框已关闭,关闭次数:', closeCount);
}
});
SA.init('body');
</script>加载 SanoUI 组件中...
API
构造函数
javascript
new SaSelect(container, config)参数
| 参数 | 说明 | 类型 | 默认值 |
|---|---|---|---|
container | 容器选择器或元素 | string | HTMLElement | - |
config | 配置选项 | SaSelectOptions | {} |
配置选项
| 参数 | 说明 | 类型 | 默认值 |
|---|---|---|---|
value | 当前选中的值 | string | number | null | null |
options | 选项列表 | Array<Option> | [] |
placeholder | 占位符文本 | string | '请选择' |
autoOpen | 是否自动打开下拉框 | boolean | false |
onChange | 值变化回调 | function(value, option): void | null |
onClose | 下拉框关闭回调 | function(): void | null |
选项对象 (Option)
| 参数 | 说明 | 类型 | 默认值 |
|---|---|---|---|
label | 选项显示文本 | string | - |
value | 选项值 | string | number | - |
disabled | 是否禁用 | boolean | false |
Data 属性
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
data-value | 当前选中的值 | string | - |
data-placeholder | 占位符文本 | string | '请选择' |
data-options | 选项列表(JSON 字符串) | string | [] |
data-auto-open | 是否自动打开 | boolean | false |
方法
| 方法名 | 说明 | 参数 | 返回值 |
|---|---|---|---|
open() | 打开下拉框 | - | void |
close(triggerCloseCallback?) | 关闭下拉框 | triggerCloseCallback?: boolean - 是否触发关闭回调,默认为 true | void |
setOptions(options) | 设置选项列表 | options: Array<Option> - 选项列表 | void |
setValue(value) | 设置选中的值 | value: string | number | null - 选项值 | void |
destroy() | 销毁实例 | - | void |
静态方法
| 方法名 | 说明 | 参数 | 返回值 |
|---|---|---|---|
initAll(container?) | 自动初始化容器内所有带 data-select 属性的元素 | container?: Element | string - 容器元素或选择器,默认为 document | Array<SaSelect> |
init(selector) | 初始化指定容器内的所有标记元素(同 initAll) | selector: Element | string - 容器选择器或元素 | Array<SaSelect> |
获取值
获取当前选中的值,使用 config.value 属性:
javascript
const value = select.config.value; // 返回当前选中的值,未选择时为 null事件回调
| 事件名 | 说明 | 回调参数 |
|---|---|---|
onChange | 值变化时触发 | value: string | number | null - 选中的值option: Option | null - 选中的选项对象 |
onClose | 下拉框关闭时触发 | - |
实际使用场景
场景 1:级联选择
两个 Select 组件级联,选择省份后动态加载城市选项。
html
<div style="display: flex; gap: 1rem; margin-bottom: 1rem;">
<div id="province-select" style="width: 200px;"></div>
<div id="city-select" style="width: 200px;"></div>
</div>
<script>
SA.init('body');
// 省份数据
const provinces = [
{ label: '北京', value: 'beijing' },
{ label: '上海', value: 'shanghai' },
{ label: '广东', value: 'guangdong' }
];
// 城市数据映射
const citiesMap = {
beijing: [
{ label: '东城区', value: 'dongcheng' },
{ label: '西城区', value: 'xicheng' },
{ label: '朝阳区', value: 'chaoyang' }
],
shanghai: [
{ label: '黄浦区', value: 'huangpu' },
{ label: '徐汇区', value: 'xuhui' },
{ label: '长宁区', value: 'changning' }
],
guangdong: [
{ label: '广州市', value: 'guangzhou' },
{ label: '深圳市', value: 'shenzhen' },
{ label: '珠海市', value: 'zhuhai' }
]
};
const provinceSelect = new SaSelect('#province-select', {
options: provinces,
placeholder: '请选择省份',
onChange: (value) => {
// 省份变化时,更新城市选项
if (value && citiesMap[value]) {
citySelect.setOptions(citiesMap[value]);
citySelect.setValue(null); // 清空城市选择
} else {
citySelect.setOptions([]);
citySelect.setValue(null);
}
}
});
const citySelect = new SaSelect('#city-select', {
options: [],
placeholder: '请先选择省份',
disabled: true
});
</script>加载 SanoUI 组件中...
场景 2:动态加载选项
从服务器动态加载选项数据。
html
<div id="async-select" style="width: 300px; margin-bottom: 1rem;"></div>
<button class="sa-button sa-button--primary" onclick="loadOptions()">重新加载选项</button>
<script>
SA.init('body');
const asyncSelect = new SaSelect('#async-select', {
options: [],
placeholder: '正在加载...'
});
// 模拟从服务器加载数据
async function loadOptions() {
asyncSelect.setOptions([]);
asyncSelect.setValue(null);
// 显示加载状态
const originalPlaceholder = asyncSelect.config.placeholder;
asyncSelect.config.placeholder = '正在加载...';
asyncSelect._syncTriggerLabel();
try {
// 模拟 API 调用
await new Promise(resolve => setTimeout(resolve, 1000));
// 模拟返回的数据
const options = [
{ label: '选项一', value: '1' },
{ label: '选项二', value: '2' },
{ label: '选项三', value: '3' },
{ label: '选项四', value: '4' },
{ label: '选项五', value: '5' }
];
asyncSelect.setOptions(options);
asyncSelect.config.placeholder = '请选择';
asyncSelect._syncTriggerLabel();
} catch (error) {
asyncSelect.config.placeholder = '加载失败,请重试';
asyncSelect._syncTriggerLabel();
}
}
// 初始加载
loadOptions();
</script>加载 SanoUI 组件中...
场景 3:表单中的 Select
在表单中使用 Select 组件,配合表单验证。
html
<form class="sa-form" id="select-form" style="max-width: 500px;" data-label-position="right" data-label-width="100px">
<div class="sa-form-item">
<label class="sa-form-item__label">用户角色</label>
<div class="sa-form-item__content">
<div id="role-select" style="width: 100%;"></div>
</div>
</div>
<div class="sa-form-item">
<label class="sa-form-item__label">部门</label>
<div class="sa-form-item__content">
<div id="department-select" style="width: 100%;"></div>
</div>
</div>
<div style="margin-top: 20px;">
<button type="button" class="sa-button sa-button--primary" onclick="submitForm()">提交</button>
<button type="button" class="sa-button" onclick="resetForm()">重置</button>
</div>
</form>
<script>
SA.init('body');
const roleSelect = new SaSelect('#role-select', {
options: [
{ label: '管理员', value: 'admin' },
{ label: '编辑', value: 'editor' },
{ label: '用户', value: 'user' }
],
placeholder: '请选择角色',
onChange: (value) => {
console.log('角色选择:', value);
}
});
const departmentSelect = new SaSelect('#department-select', {
options: [
{ label: '技术部', value: 'tech' },
{ label: '产品部', value: 'product' },
{ label: '运营部', value: 'operation' }
],
placeholder: '请选择部门'
});
// 注册到表单(需要手动注册,因为 Select 不是通过 data-prop 自动注册的)
const form = new SaForm('#select-form', {
rules: {
role: [
{ required: true, message: '请选择用户角色' }
],
department: [
{ required: true, message: '请选择部门' }
]
}
});
// 手动注册字段
form.registerField('role', document.getElementById('role-select'), [
{
required: true,
message: '请选择用户角色',
validator: (rule, value) => {
return roleSelect.config.value !== null;
}
}
]);
form.registerField('department', document.getElementById('department-select'), [
{
required: true,
message: '请选择部门',
validator: (rule, value) => {
return departmentSelect.config.value !== null;
}
}
]);
async function submitForm() {
try {
const formData = await form.validate();
const data = {
role: roleSelect.config.value,
department: departmentSelect.config.value
};
alert('提交成功:' + JSON.stringify(data));
} catch (errors) {
console.log('验证失败:', errors);
}
}
function resetForm() {
roleSelect.setValue(null);
departmentSelect.setValue(null);
form.resetFields();
}
</script>加载 SanoUI 组件中...
场景 4:搜索过滤选项
带搜索功能的选择器,可以过滤选项。
html
<div style="margin-bottom: 1rem;">
<div class="sa-input"
id="search-input"
data-placeholder="搜索选项..."
data-prefix-icon="search"
data-clearable="true"
style="width: 300px; margin-bottom: 1rem;">
</div>
<div id="filtered-select" style="width: 300px;"></div>
</div>
<script>
SA.init('body');
// 所有选项
const allOptions = [
{ label: '苹果', value: 'apple' },
{ label: '香蕉', value: 'banana' },
{ label: '橙子', value: 'orange' },
{ label: '葡萄', value: 'grape' },
{ label: '西瓜', value: 'watermelon' },
{ label: '草莓', value: 'strawberry' },
{ label: '蓝莓', value: 'blueberry' },
{ label: '樱桃', value: 'cherry' }
];
const filteredSelect = new SaSelect('#filtered-select', {
options: allOptions,
placeholder: '请选择水果'
});
const searchInput = document.getElementById('search-input');
// 监听搜索输入
if (searchInput._saInputInstance) {
searchInput._saInputInstance.config.onInput = (keyword) => {
if (!keyword) {
filteredSelect.setOptions(allOptions);
return;
}
// 过滤选项
const filtered = allOptions.filter(option =>
option.label.toLowerCase().includes(keyword.toLowerCase())
);
filteredSelect.setOptions(filtered);
// 如果过滤后没有选项,打开下拉框显示"暂无选项"
if (filtered.length === 0) {
filteredSelect.open();
}
};
}
</script>加载 SanoUI 组件中...
场景 5:禁用状态管理
根据业务逻辑动态启用/禁用 Select 组件。
html
<div style="margin-bottom: 1rem;">
<label>
<input type="checkbox" id="enable-select" checked onchange="toggleSelect()">
启用选择器
</label>
</div>
<div id="toggle-select" style="width: 300px;"></div>
<script>
SA.init('body');
const selectInstance = new SaSelect('#toggle-select', {
options: [
{ label: '选项一', value: '1' },
{ label: '选项二', value: '2' },
{ label: '选项三', value: '3' }
],
placeholder: '请选择'
});
function toggleSelect() {
const enableCheckbox = document.getElementById('enable-select');
const selectWrapper = document.getElementById('toggle-select').querySelector('.sa-select');
if (enableCheckbox.checked) {
selectWrapper.classList.remove('sa-select--disabled');
selectInstance.config.disabled = false;
} else {
selectWrapper.classList.add('sa-select--disabled');
selectInstance.config.disabled = true;
selectInstance.close();
}
}
</script>加载 SanoUI 组件中...
场景 6:手动控制打开/关闭
使用 open() 和 close() 方法手动控制下拉框的显示。
html
<div id="manual-control-select" style="width: 300px; margin-bottom: 1rem;"></div>
<div style="display: flex; gap: 8px;">
<button class="sa-button sa-button--primary" onclick="openSelect()">打开下拉框</button>
<button class="sa-button" onclick="closeSelect()">关闭下拉框</button>
</div>
<script>
SA.init('body');
const manualSelect = new SaSelect('#manual-control-select', {
options: [
{ label: '选项一', value: '1' },
{ label: '选项二', value: '2' },
{ label: '选项三', value: '3' }
],
placeholder: '请选择'
});
function openSelect() {
manualSelect.open();
}
function closeSelect() {
manualSelect.close();
}
</script>加载 SanoUI 组件中...
场景 7:获取当前值
通过 config.value 获取当前选中的值。
html
<div id="get-value-select" style="width: 300px; margin-bottom: 1rem;"></div>
<button class="sa-button sa-button--primary" onclick="getCurrentValue()">获取当前值</button>
<div id="value-display" style="margin-top: 1rem; padding: 12px; background: #f5f5f5; border-radius: 4px; font-size: 14px; color: #666;">
当前值:<span id="current-value">-</span>
</div>
<script>
SA.init('body');
const getValueSelect = new SaSelect('#get-value-select', {
options: [
{ label: '选项一', value: '1' },
{ label: '选项二', value: '2' },
{ label: '选项三', value: '3' }
],
placeholder: '请选择',
onChange: () => {
updateValueDisplay();
}
});
function getCurrentValue() {
updateValueDisplay();
}
function updateValueDisplay() {
const value = getValueSelect.config.value;
document.getElementById('current-value').textContent = value !== null ? value : '-';
}
</script>加载 SanoUI 组件中...
场景 8:自动初始化
使用 data-select 属性和 SaSelect.initAll() 自动初始化选择器。
html
<!-- 使用 data-select 属性自动初始化 -->
<div class="sa-select-container"
data-select
data-placeholder="请选择选项"
data-options='[{"label":"选项一","value":"1"},{"label":"选项二","value":"2"},{"label":"选项三","value":"3"}]'
style="width: 300px;">
</div>
<!-- 或使用 data-value 设置默认值 -->
<div class="sa-select-container"
data-select
data-value="2"
data-placeholder="已选择选项二"
data-options='[{"label":"选项一","value":"1"},{"label":"选项二","value":"2"},{"label":"选项三","value":"3"}]'
style="width: 300px; margin-top: 1rem;">
</div>
<script>
// 自动初始化所有带 data-select 属性的元素
SaSelect.initAll();
</script>加载 SanoUI 组件中...
场景 9:销毁实例
使用 destroy() 方法销毁选择器实例。
html
<div id="destroy-select" style="width: 300px; margin-bottom: 1rem;"></div>
<button class="sa-button sa-button--danger" onclick="destroySelect()">销毁选择器</button>
<div id="destroy-status" style="margin-top: 1rem; padding: 12px; background: #f5f5f5; border-radius: 4px; font-size: 14px; color: #666;">
状态:<span id="status-text">已创建</span>
</div>
<script>
SA.init('body');
let destroySelectInstance = new SaSelect('#destroy-select', {
options: [
{ label: '选项一', value: '1' },
{ label: '选项二', value: '2' },
{ label: '选项三', value: '3' }
],
placeholder: '请选择'
});
function destroySelect() {
if (destroySelectInstance) {
destroySelectInstance.destroy();
destroySelectInstance = null;
document.getElementById('status-text').textContent = '已销毁';
document.getElementById('destroy-select').innerHTML = '<div style="padding: 12px; color: #999;">选择器已销毁</div>';
} else {
alert('选择器已被销毁');
}
}
</script>加载 SanoUI 组件中...
注意事项
- 选项格式:选项可以是对象
{ label, value, disabled }或简单值(字符串/数字) - 值类型:
value可以是字符串或数字,但必须与选项中的value类型一致 - 动态更新:使用
setOptions()更新选项时,如果当前值不在新选项中,会自动清空 - 自动初始化:Select 组件不会通过
SA.init()自动初始化,需要手动创建实例 - 表单集成:在表单中使用时,需要手动调用
form.registerField()注册字段
常见问题
Q: 如何获取当前选中的值?
A: 通过 config.value 属性:
javascript
const value = select.config.value; // 返回当前选中的值,未选择时为 nullQ: 如何动态更新选项?
A: 使用 setOptions() 方法:
javascript
select.setOptions([
{ label: '新选项一', value: '1' },
{ label: '新选项二', value: '2' }
]);Q: 如何清空选择?
A: 使用 setValue(null) 方法:
javascript
select.setValue(null);Q: 如何实现搜索过滤?
A: 监听输入框的 onInput 事件,然后使用 setOptions() 更新选项:
javascript
inputInstance.config.onInput = (keyword) => {
const filtered = allOptions.filter(opt =>
opt.label.includes(keyword)
);
select.setOptions(filtered);
};Q: 如何在表单中使用 Select?
A: 需要手动注册字段到表单:
javascript
const form = new SaForm('#form');
form.registerField('fieldName', selectElement, [
{ required: true, message: '请选择' }
]);Q: 如何实现级联选择?
A: 在父级 Select 的 onChange 回调中更新子级 Select 的选项:
javascript
parentSelect.config.onChange = (value) => {
const childOptions = getChildOptions(value);
childSelect.setOptions(childOptions);
childSelect.setValue(null);
};