iter(g159): 多选下拉支持标签折叠

This commit is contained in:
HIsheR
2026-10-26 16:02:24 +08:00
parent cbf0526408
commit 312e80118f
7 changed files with 51 additions and 7 deletions
+8 -2
View File
@@ -60,11 +60,17 @@ export function multiSelect(props: MultiSelectProps): HTMLElement {
const render = (): void => {
const cur = value();
const full = props.max != null && cur.length >= props.max; // 是否已达上限
const tags = cur.map((v) => {
const label = props.options.find((o) => o.value === v)?.label ?? v;
const cut = props.maxTagCount != null && cur.length > props.maxTagCount ? cur.slice(0, props.maxTagCount) : cur; // 折叠后仍显示的标签
const labelOf = (v: string): string => props.options.find((o) => o.value === v)?.label ?? v;
const tags = cut.map((v) => {
const label = labelOf(v);
const del = h('button', { type: 'button', class: 'ua-multiselect-x', 'aria-label': `移除 ${label}`, onClick: () => toggle(v) }, '×');
return h('span', { class: 'ua-multiselect-tag' }, h('span', {}, label), del);
});
if (cut.length < cur.length) { // 溢出项折成一枚 +N,悬停给全量、点击展开弹层
const rest = cur.slice(cut.length).map(labelOf).join('、');
tags.push(h('span', { class: 'ua-multiselect-tag is-more', title: rest, 'aria-label': `另有 ${cur.length - cut.length} 项:${rest}`, onClick: () => open(true) }, `+${cur.length - cut.length}`));
}
tagWrap.replaceChildren(...tags); // 只换标签,输入框保持挂载(重建会丢焦点与输入内容)
input.placeholder = cur.length ? '' : props.placeholder ?? '请选择'; // 有标签时不挤占占位文案
const rows = visible().map((o, i) => {
+1
View File
@@ -700,6 +700,7 @@ export interface MultiSelectProps {
value?: Signal<string[]>; // 选中值数组信号;不传则内部维护
placeholder?: string; // 未选时占位文案;缺省「请选择」
max?: number; // 最多选几项:到上限后未选项禁用
maxTagCount?: number; // 标签区最多显示几个,超出折成「+N」;缺省全显示
searchable?: boolean; // 是否可输入过滤;缺省 true
disabled?: boolean | Signal<boolean>; // 禁用整个下拉
onChange?: (values: string[]) => void; // 变更回调(传副本)
+7 -1
View File
@@ -2858,6 +2858,11 @@
"t": "number",
"d": "最多选几项:到上限后未选项自动禁用"
},
{
"n": "maxTagCount",
"t": "number",
"d": "标签区最多显示几个,超出的折成一枚「+N」(悬停看全量、点击展开弹层);缺省全部显示"
},
{
"n": "searchable",
"t": "boolean",
@@ -2880,7 +2885,8 @@
"点输入区展开弹层并聚焦输入框,输入字符即时过滤(大小写不敏感)",
"点选项只切换该项、弹层不收起,适合连续多选;到 max 后未选项置灰不可点",
"↑↓ 环形移动高亮、Enter 切换当前项、Esc 收起(与其它弹层共用一个 Esc 栈)",
"value 传数组信号即受控,外部写入会同步标签区"
"value 传数组信号即受控,外部写入会同步标签区",
"选中项多时传 maxTagCount: 2 折叠:前 2 枚标签照常逐个删除,其余折成虚线「+N」,悬停 title 给出被折叠的项名,点它直接展开弹层;受控数组一变折叠数就重算"
]
},
{
+10
View File
@@ -3611,6 +3611,16 @@ button.ua-step-dot:hover {
white-space: nowrap;
text-overflow: ellipsis;
}
.ua-multiselect-tag.is-more {
color: var(--ua-color-accent);
border: 1px dashed color-mix(in srgb, var(--ua-color-accent) 40%, transparent);
background: transparent;
cursor: pointer;
font-variant-numeric: tabular-nums;
}
.ua-multiselect-tag.is-more:hover {
background: color-mix(in srgb, var(--ua-color-accent) 12%, transparent);
}
.ua-multiselect-x {
padding: 0;
font-size: 12px;