52 lines
2.3 KiB
TypeScript
52 lines
2.3 KiB
TypeScript
import { h } from '@ui-arch/frame';
|
|
|
|
const MIN = 56; // 列宽下限:小于这个值表头文字会被压成竖排
|
|
|
|
/*** 列宽手柄:右缘拖动改 <col> 宽度(双击复位),← → 每次微调 8px,两者共用 apply 收口 ***/
|
|
export function attachResize(th: HTMLElement, col: HTMLElement, start: number, label: string): void {
|
|
// —— 状态集中声明 ——
|
|
let dragging = false; // 是否处于拖拽中
|
|
let originX = 0; // 按下时的指针横坐标
|
|
let originW = 0; // 按下时的实际列宽
|
|
|
|
/*** 唯一写宽入口:夹取下限后写回 <col> ***/
|
|
const apply = (w: number): void => { col.style.width = `${Math.max(MIN, Math.round(w))}px`; };
|
|
|
|
const grip = h('span', {
|
|
class: 'ua-col-grip',
|
|
role: 'separator', // 可调节分隔符语义:读屏可识别为「可调整」
|
|
'aria-orientation': 'vertical',
|
|
'aria-label': `调整「${label}」列宽`,
|
|
tabindex: '0',
|
|
onpointerdown: (e: PointerEvent) => {
|
|
dragging = true;
|
|
originX = e.clientX;
|
|
originW = col.getBoundingClientRect().width; // 取实际渲染宽度,避免与 min-width 打架
|
|
grip.setPointerCapture(e.pointerId); // 捕获指针:拖出表头也继续跟手
|
|
e.preventDefault(); // 不触发列头排序
|
|
e.stopPropagation();
|
|
document.body.classList.add('ua-col-resizing'); // 拖拽期间全局禁用文本选中
|
|
},
|
|
onpointermove: (e: PointerEvent) => { if (dragging) apply(originW + e.clientX - originX); },
|
|
onpointerup: stop,
|
|
onpointercancel: stop,
|
|
onclick: (e: MouseEvent) => e.stopPropagation(), // 点手柄不该触发排序
|
|
ondblclick: (e: MouseEvent) => { e.stopPropagation(); apply(start); }, // 双击回到声明宽度
|
|
onkeydown: (e: KeyboardEvent) => {
|
|
if (e.key !== 'ArrowLeft' && e.key !== 'ArrowRight') return; // 卫语句:只接管方向键
|
|
e.preventDefault();
|
|
e.stopPropagation(); // 不冒泡到表格的行选择等外层快捷键
|
|
apply(col.getBoundingClientRect().width + (e.key === 'ArrowRight' ? 8 : -8));
|
|
},
|
|
}) as HTMLElement;
|
|
|
|
/*** 拖拽收尾:复位标志与全局样式 ***/
|
|
function stop(): void {
|
|
if (!dragging) return; // 卫语句:不在拖拽中
|
|
dragging = false;
|
|
document.body.classList.remove('ua-col-resizing');
|
|
}
|
|
|
|
th.append(grip);
|
|
}
|