From 53137a184b051ace18c4f178096d50e5fd3d597a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=98=BF=E8=8F=9C=20Cai?= Date: Sat, 11 Apr 2026 01:58:42 +0800 Subject: [PATCH] =?UTF-8?q?feat(tag-input):=20=E6=A0=87=E7=AD=BE=E8=BE=93?= =?UTF-8?q?=E5=85=A5=E6=A1=86=E6=BB=9A=E5=8A=A8=E5=85=B1=E4=BA=AB=E9=80=BB?= =?UTF-8?q?=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- js/utils/tagInputScroll.ts | 50 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 js/utils/tagInputScroll.ts diff --git a/js/utils/tagInputScroll.ts b/js/utils/tagInputScroll.ts new file mode 100644 index 0000000000..946ac9e2e0 --- /dev/null +++ b/js/utils/tagInputScroll.ts @@ -0,0 +1,50 @@ +/** + * TagInput 滚动相关共享逻辑(React / Vue 通用) + * 当标签数量过多时,输入框显示不下则需要滚动查看 + */ + +const SCROLL_CONTAINER_CLASS = 'input__prefix'; +const SCROLLABLE_CLASS = 'input__prefix--scrollable'; + +/** 根据根元素查找滚动容器 .{classPrefix}-input__prefix */ +export function getScrollContainer(root: HTMLElement, classPrefix: string): HTMLElement | null { + return root.querySelector(`.${classPrefix}-${SCROLL_CONTAINER_CLASS}`); +} + +/** 计算元素的最大可滚动距离 scrollWidth - clientWidth */ +export function getScrollDistance(el: HTMLElement): number { + return el.scrollWidth - el.clientWidth; +} + +/** 设置/移除 scrollable 状态类,控制 overflow 是否开放 */ +export function setScrollableClass(el: HTMLElement, classPrefix: string, scrollable: boolean): void { + const className = `${classPrefix}-${SCROLLABLE_CLASS}`; + if (scrollable) { + el.classList.add(className); + } else { + el.classList.remove(className); + } +} + +/** 处理滚轮事件:MAC deltaX / Windows deltaY 兼容 */ +export function handleWheelScroll(el: HTMLElement, e: { deltaX: number; deltaY: number }): void { + const delta = Math.abs(e.deltaX) >= Math.abs(e.deltaY) ? e.deltaX : e.deltaY; + if (delta === 0) return; + const max = getScrollDistance(el); + // eslint-disable-next-line no-param-reassign + el.scrollLeft = Math.max(0, Math.min(el.scrollLeft + delta, max)); +} + +/** 滚动到最左侧并移除 scrollable class(鼠标离开时) */ +export function scrollToLeft(el: HTMLElement, classPrefix: string): void { + // eslint-disable-next-line no-param-reassign + el.scrollLeft = 0; + setScrollableClass(el, classPrefix, false); +} + +/** 滚动到最右侧并开启 scrollable class */ +export function scrollToRight(el: HTMLElement, classPrefix: string): void { + setScrollableClass(el, classPrefix, true); + // eslint-disable-next-line no-param-reassign + el.scrollLeft = getScrollDistance(el); +}