Skip to content

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 | nullnull
options选项列表Array<Option>[]
placeholder占位符文本string'请选择'
autoOpen是否自动打开下拉框booleanfalse
onChange值变化回调function(value, option): voidnull
onClose下拉框关闭回调function(): voidnull

选项对象 (Option)

参数说明类型默认值
label选项显示文本string-
value选项值string | number-
disabled是否禁用booleanfalse

Data 属性

属性说明类型默认值
data-value当前选中的值string-
data-placeholder占位符文本string'请选择'
data-options选项列表(JSON 字符串)string[]
data-auto-open是否自动打开booleanfalse

方法

方法名说明参数返回值
open()打开下拉框-void
close(triggerCloseCallback?)关闭下拉框triggerCloseCallback?: boolean - 是否触发关闭回调,默认为 truevoid
setOptions(options)设置选项列表options: Array<Option> - 选项列表void
setValue(value)设置选中的值value: string | number | null - 选项值void
destroy()销毁实例-void

静态方法

方法名说明参数返回值
initAll(container?)自动初始化容器内所有带 data-select 属性的元素container?: Element | string - 容器元素或选择器,默认为 documentArray<SaSelect>
init(selector)初始化指定容器内的所有标记元素(同 initAllselector: 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 组件中...
            
          

注意事项

  1. 选项格式:选项可以是对象 { label, value, disabled } 或简单值(字符串/数字)
  2. 值类型value 可以是字符串或数字,但必须与选项中的 value 类型一致
  3. 动态更新:使用 setOptions() 更新选项时,如果当前值不在新选项中,会自动清空
  4. 自动初始化:Select 组件不会通过 SA.init() 自动初始化,需要手动创建实例
  5. 表单集成:在表单中使用时,需要手动调用 form.registerField() 注册字段

常见问题

Q: 如何获取当前选中的值?

A: 通过 config.value 属性:

javascript
const value = select.config.value; // 返回当前选中的值,未选择时为 null

Q: 如何动态更新选项?

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);
};

Released under the MIT License.