UNPKG

ivue-material-plus

Version:

A high quality UI components Library with Vue.js

363 lines (284 loc) • 10.1 kB
import { inject, ref, getCurrentInstance } from 'vue'; import { hasClass, removeClass, addClass } from '../../../utils/assist'; import { on, off } from '../../../utils/dom'; // type import { TableContextKey } from '../table/defaults'; import type { TableColumnCtx } from '../table-column/defaults'; import type { DragState, SortOrder, TableHeaderProps } from './types'; function useEvent(props: TableHeaderProps, emit) { // vm const vm = getCurrentInstance(); // inject const IvueTable = inject(TableContextKey); // data // 当前鼠标移动到的拖动列 const draggingColumn = ref<TableColumnCtx>(null); // 拖动中 const dragging = ref<boolean>(false); // 拖动开始 const dragState = ref<DragState>({}); // 切换排序 const toggleOrder = ({ order, sortOrders }) => { // 表示升序 if (order === '') { return sortOrders[0]; } // 下标 const index = sortOrders.indexOf(order || null); return sortOrders[index > sortOrders.length - 2 ? 0 : index + 1]; }; // 点击排序 const handleSortClick = ( event: Event, column: TableColumnCtx, givenOrder: string | boolean ) => { // stopPropagation event.stopPropagation(); // 顺序 const order = column.order === givenOrder ? null : givenOrder || toggleOrder(column); let target = event.target as HTMLElement; while (target && target.tagName !== 'TH') { target = target.parentNode as HTMLElement; } // 点击th if (target && target.tagName === 'TH') { // 是否有 noclick 防止开启排序时点击 if (hasClass(target, 'noclick')) { removeClass(target, 'noclick'); return; } } // 没有排序 if (!column.sortable) { return; } // states const states = props.store.states; // 排序的key 对应列内容的字段名 let sortProp = states.sortProp.value; // 需要排序的列 const sortingColumn = states.sortingColumn.value; // 排序 let sortOrder: SortOrder; // 不是当前列 if ( sortingColumn !== column || (sortingColumn === column && sortingColumn.order === null) ) { // 初始化排序 if (sortingColumn) { sortingColumn.order = null; } // 保存当前列 states.sortingColumn.value = column; // 排序的key 对应列内容的字段名 sortProp = column.property; } // 没有排序顺序 if (!order) { column.order = null; sortOrder = null; } // 设置排序顺序 else { sortOrder = order; column.order = order; } // 排序的key 对应列内容的字段名 states.sortProp.value = sortProp; // 设置排序顺序 descending | ascending | null states.sortOrder.value = sortOrder; // 改变排序 IvueTable.store.commit('changeSortCondition'); }; // 头部点击 const handleHeaderClick = (event: Event, column: TableColumnCtx) => { event.preventDefault(); // 没有过滤筛选数据,只有排序 if (!column.filters && column.sortable) { handleSortClick(event, column, false); } IvueTable.emit('on-header-click', column, event); }; // 鼠标按下 const handleMouseDown = (event: MouseEvent, column: TableColumnCtx) => { // 有子节点 if (column.children && column.children.length > 0) { return; } // 可以拖动列 有开启边框 if (draggingColumn.value && props.border) { // 拖动中 dragging.value = true; emit('on-drag-visible', true); // 表格节点 const tableDom = IvueTable.vnode.el; // 表格距离左边窗口的距离 const tableLeft = tableDom.getBoundingClientRect().left; // 当前拖动的列 const currentColumnDom = vm!.vnode.el!.querySelector(`th.${column.id}`); // 当前列距离窗口的距离 const columnRect = currentColumnDom.getBoundingClientRect(); // 单元格宽度 const cellDom = currentColumnDom.querySelector('.cell-content'); // 最小左边距离 const minLeft = columnRect.left - tableLeft + (cellDom.offsetWidth + 30); // 添加class noclick 防止开启排序时点击 addClass(currentColumnDom, 'noclick'); // 开始拖动 dragState.value = { // 触发点相对浏览器可视区域左距离 startMouseLeft: event.clientX, // 当前列距离窗口的距离右边 - 表格距离左边窗口的距离 startLeft: columnRect.right - tableLeft, // 当前列距离窗口的距离 - 表格距离左边窗口的距离 startColumnLeft: columnRect.left - tableLeft, // 表格距离左边窗口的距离 tableLeft, }; // 拖拽时的虚线 const draggingDottedDom = IvueTable.refs.draggingDotted as HTMLElement; // 设置拖拽时的虚线距离 draggingDottedDom.style.left = `${dragState.value.startLeft}px`; // 禁止document选择事件 document.onselectstart = () => { return false; }; // 禁止document拖拽事件 document.ondragstart = () => { return false; }; // 鼠标移动 const handleDocumentMouseMove = (event) => { // 当前触发点相对浏览器可视区域左距离 - 开始拖动时 触发点相对浏览器可视区域左距离 const deltaLeft = event.clientX - dragState.value.startMouseLeft; // 可拖动最大值 let maxLeft = dragState.value.startLeft + deltaLeft; // 最大表格宽度 if (maxLeft >= tableDom.offsetWidth) { maxLeft = tableDom.offsetWidth; } // minLeft | maxLeft draggingDottedDom.style.left = `${Math.max(minLeft, maxLeft)}px`; }; // 鼠标放开 const handleDocumentMouseUp = () => { // 拖动中 if (dragging.value) { const { startColumnLeft, startLeft } = dragState.value; // 拖拽时的虚线位置 const draggingDottedDomLeft = Number.parseInt( draggingDottedDom.style.left, 10 ); // 列的宽度 = 拖拽虚线后的位置 - 开始列左边到窗口的距离 const columnWidth = draggingDottedDomLeft - startColumnLeft; // 设置列的宽度 column.width = columnWidth; column.columnWidth = columnWidth; IvueTable.emit( 'on-header-dragend', // 设置列的宽度 column.width, // 拖拽后的位置 startLeft - startColumnLeft, column, event ); // 更新dom重新执行布局 requestAnimationFrame(() => { props.store.scheduleLayout(false, true); }); // 初始化样式 document.body.style.cursor = ''; // 拖动中 dragging.value = false; // 当前鼠标移动到的拖动列 draggingColumn.value = null; // 拖动开始 dragState.value = {}; // 隐藏拖动虚线 emit('on-drag-visible', false); } // 移除鼠标移动 off(document, 'mousemove', handleDocumentMouseMove); // 移除鼠标放开 off(document, 'mouseup', handleDocumentMouseUp); // 开启document选择事件 document.onselectstart = null; // 开启document拖拽事件 document.ondragstart = null; // 删除样式 setTimeout(() => { removeClass(currentColumnDom, 'noclick'); }, 0); }; // 鼠标移动 on(document, 'mousemove', handleDocumentMouseMove); // 鼠标放开 on(document, 'mouseup', handleDocumentMouseUp); } }; // 鼠标移动 const handleMouseMove = (event: MouseEvent, column: TableColumnCtx) => { // 有子节点 if (column.children && column.children.length > 0) { return; } // 获取当前节点的父节点->列的头部 let target = event.target as HTMLElement; // 获取th while (target && target.tagName !== 'TH') { target = target.parentNode as HTMLElement; } // 不能拖动 if (!column || !column.resizable) { return; } // 没有拖动 开启边框 if (!dragging.value && props.border) { // 当前头部的大小 const rect = target.getBoundingClientRect(); // body样式 const bodyStyle = document.body.style; // dom宽度 > 12px && dom右边距离body的距离 - 当前手势距离窗口的距离 < 8px if (rect.width > 12 && rect.right - event.pageX < 8) { bodyStyle.cursor = 'col-resize'; // 是否有排序 if (hasClass(target, 'is-sortable')) { target.style.cursor = 'col-resize'; } // 当前鼠标移动到的拖动列 draggingColumn.value = column; } // 没有拖动初始化手势样式 else if (!dragging.value) { bodyStyle.cursor = ''; // 是否有排序 if (hasClass(target, 'is-sortable') && column.filterable) { target.style.cursor = 'inherit'; } // 是否有排序 else if (hasClass(target, 'is-sortable')) { target.style.cursor = 'pointer'; } // 当前鼠标移动到的拖动列 draggingColumn.value = null; } } }; // 鼠标退出 const handleMouseOut = () => { document.body.style.cursor = ''; }; return { handleSortClick, handleHeaderClick, handleMouseDown, handleMouseMove, handleMouseOut, }; } export default useEvent;