Select 选择器
基础用法
选项写成子元素而不是数组属性 —— 原生 HTML 里才能不写一行 JS 就用起来。窄屏下弹层会切换成底部抽屉。
<pt-select placeholder="选择环境">
<pt-option value="prod">生产</pt-option>
<pt-option value="staging">预发</pt-option>
<pt-option value="dev">开发</pt-option>
</pt-select>选项写成 pt-option 子元素而不是 options 数组属性:这样在原生 HTML 里 不写一行 JS 就能用起来,也才能往选项里塞图标。
分组与分隔线
分组与分隔线
pt-option-group 给一组选项加上不可选的组标题,pt-separator 在组与组之间画线。方向键与首字母跳转只在选项之间移动,跨过组标题与分隔线。
<pt-select placeholder="选择时区">
<pt-option-group label="亚洲">
<pt-option value="Asia/Shanghai" keywords="china beijing">上海</pt-option>
<pt-option value="Asia/Tokyo" keywords="japan">东京</pt-option>
</pt-option-group>
<pt-separator></pt-separator>
<pt-option-group label="欧洲">
<pt-option value="Europe/London" keywords="uk gmt">伦敦</pt-option>
<pt-option value="Europe/Paris" keywords="france">巴黎</pt-option>
</pt-option-group>
</pt-select>选项多了按类别归组时,用 pt-option-group 包住一组 pt-option,label 是不可选的组标题; 组与组、选项与选项之间可以夹一条 pt-separator。
- 选择与键盘导航只认
pt-option:组里的选项和直接写的选项一样参与选中、方向键、首字母跳转, 组标题与分隔线被自然跨过,首字母跳转也不会匹配到组标题。 - 无障碍结构是
listbox > group > option,组标题经aria-labelledby成为这一组的名字,读屏进入组时先念组名。 - 分隔线在列表里默认改用更淡的颜色(
--pt-bg-secondary)并左右贯通到弹层边缘; 要换颜色直接在pt-separator上设--pt-separator-color。它必须保持默认的装饰性(不要写decorative="false")—— listbox 里只允许出现选项与分组。
pt-option 的 keywords(空格分隔)只存储、不影响显示,留给可搜索的下拉按别名匹配用; pt-select 的首字母跳转仍只看选项文案。
键盘操作
按 WAI-ARIA 的 listbox 模式实现:
| 按键 | 行为 |
|---|---|
| Enter / Space | 展开;已展开时选中当前项 |
| ↑ / ↓ | 移动高亮项(未展开时先展开) |
| Home / End | 跳到首尾 |
| Esc | 收起 |
| 字母键 | 跳到以该字母开头的选项(1 秒内连打可匹配多字符;从当前项之后找,同一字母连按在以它开头的选项间循环) |
弹层
列表进浏览器的顶层(top layer),放在 overflow: hidden 或带 transform 的容器里也不会被裁切, 不需要调 z-index。默认在触发器下方展开、与触发器起始边对齐、至少与触发器同宽;下方放不下时翻到上方。 「起始边」随书写方向:在 dir="rtl" 的页面或容器里,列表与触发器的右边缘对齐。
移动端
窄屏(≤640px)下弹层切换为底部抽屉形态:触屏上贴着触发器的浮层既够不着也容易误触。 抽屉与遮罩同样在顶层,始终贴着视口底边、遮罩盖住整页。 选项行的视觉高度不变,命中区靠伪元素外扩到 44px 的触控目标。
API
属性
| 属性 | Attribute | 类型 | 默认值 | 说明 |
|---|---|---|---|---|
ariaLabelText | aria-label | string | undefined | — | 无障碍名称:原生 HTML 里写 aria-label,React / Vue / Angular 包装层里属性名是 ariaLabelText。 没有可见 label 时必须给;不给时读屏念的是当前显示的值或占位文案。 |
disabled | disabled | boolean | false | 禁用。只反映使用方自己写的值:外层原生 `<fieldset disabled>`、pt-field / pt-field-set 的禁用另经继承通道生效,不改写它 |
inheritedDisabled | inherited-disabled | boolean | false | 外层 pt-field / pt-field-set 下发的禁用。内部继承通道:由它们以 attribute 维护,不建议使用方直接写。 有效禁用是 `disabled` 与它的并集;父元素只写这一条、不碰 `disabled`,读 `el.disabled` 得到的始终是使用方自己写的值 |
inheritedInvalid | inherited-invalid | boolean | false | 外层 pt-field 下发的出错态。内部继承通道:由 pt-field 维护,不建议使用方直接写。有效出错是 `invalid` 与它的并集 |
inheritedRequired | inherited-required | boolean | false | 外层 pt-field 下发的必填。内部继承通道:由 pt-field 维护,不建议使用方直接写。有效必填是 `required` 与它的并集 |
invalid | invalid | boolean | false | 出错态。校验信息由使用方展示,组件只负责视觉、aria-invalid 与表单校验状态(customError) |
name | name | string | undefined | — | 提交表单时的字段名 |
open | open | boolean | false | 列表是否展开。可读可写,一般不用手动设置 |
placeholder | placeholder | string | undefined | — | 未选中时的占位文案 |
required | required | boolean | false | 必填:值为空时表单校验报 valueMissing,并标注 aria-required |
size | size | "lg" | "md" | "sm" | 'md' | 尺寸档位。三档对应 24 / 32 / 40 的控件刻度,与 pt-input 一致 |
value | value | string | '' | 当前值。与某个 pt-option 的 value 对应 |
事件
| 事件 | detail 类型 | 说明 |
|---|---|---|
ptBlur | void | 内部控件失去焦点 |
ptChange | string | 选中值变化 |
ptClose | { reason: PtSelectCloseReason; } | 列表收起,detail 说明是怎么收起的(与 pt-modal 的 ptClose 同形) **不冒泡**:弹层常互相嵌套(弹窗里的菜单、气泡卡片里的下拉),冒泡的话外层上的监听会收到内层的开关。 |
ptFocus | void | 内部控件获得焦点 |
ptOpen | void | 列表展开 **不冒泡**:弹层常互相嵌套(弹窗里的菜单、气泡卡片里的下拉),冒泡的话外层上的监听会收到内层的开关。 |
方法
| 方法 | 说明 |
|---|---|
hide() => Promise<void> | 收起列表 |
refresh() => Promise<void> | 选项变动时重新同步(动态增删选项后调用) |
setFocus(options?: FocusOptions) => Promise<void> | |
show() => Promise<void> | 展开列表 |
插槽
| 名称 | 说明 |
|---|---|
(默认) | `pt-option` 列表,可混放 `pt-option-group` 与 `pt-separator` |
可定制的内部元素(::part())
| part | 说明 |
|---|---|
base | 触发器(组件可见的外层控件,与 trigger 同一元素) |
popup | 弹出的列表容器 |
trigger | 触发器 |
CSS 变量
| 变量 | 说明 |
|---|---|
--pt-select-popup-max-height | 列表最大高度,默认 384px。窄屏抽屉形态下固定 60vh,不受它影响 |
--pt-select-radius | 触发器与弹层的圆角,默认 --pt-radius-md(sm 档触发器默认 --pt-radius-sm) |
pt-option
属性
| 属性 | Attribute | 类型 | 默认值 | 说明 |
|---|---|---|---|---|
active | active | boolean | false | 键盘/指针当前高亮项。由所属的 pt-select / pt-combobox 维护,不要手动设置 |
disabled | disabled | boolean | false | 禁用:点击不选中,方向键与首字母跳转都会跳过它,并标注 aria-disabled |
keywords | keywords | string | undefined | — | 额外的搜索关键词,空格分隔(如 `"production prod 线上"`)。 只存储、不影响渲染:给可搜索的下拉(pt-combobox)按别名、拼音、英文名匹配用, 这样搜「prod」也能命中文案是「生产」的选项(任一关键词包含查询即命中)。pt-select 的首字母跳转仍只看文案。 |
selected | selected | boolean | false | 由所属的 pt-select / pt-combobox 维护,不要手动设置 |
value | value | string | undefined | — | 选项值。省略时取文案本身 |
插槽
| 名称 | 说明 |
|---|---|
(默认) | 选项文案 |
start | 文案前的图标 |
可定制的内部元素(::part())
| part | 说明 |
|---|---|
base | 选项行 |
pt-option-group
属性
| 属性 | Attribute | 类型 | 默认值 | 说明 |
|---|---|---|---|---|
label | label | string | undefined | — | 组标题。不可选、方向键跳过;同时是这一组的无障碍名称。不给时不渲染标题行 |
插槽
| 名称 | 说明 |
|---|---|
(默认) | 这一组的 `pt-option`(可夹 `pt-separator`) |
可定制的内部元素(::part())
| part | 说明 |
|---|---|
base | 分组容器(role="group") |
label | 组标题 |