尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

elementplus结合sortablejs做出表格可拖拽效果的组件

elementplus结合sortablejs做出表格可拖拽效果的组件 1.安装npm install sortablejs2.在src下新建可复用的组合式函数文件夹composablessrc/composables/useSortableDrag.jsimport { ref, onMounted, onBeforeUnmount, nextTick } from vue import Sortable from sortablejs /** * 拖拽排序配置选项 * typedef {Object} SortableOptions * property {string} handle - 拖拽手柄选择器默认为 .drag-handle * property {number} animation - 动画持续时间ms默认为 150 * property {string} easing - 缓动函数默认为 cubic-bezier(0.25, 0.46, 0.45, 0.94) * property {number} scrollThreshold - 触发滚动的边缘距离px默认为 80 * property {number} scrollSpeed - 滚动速度默认为 15 * property {boolean} autoScroll - 是否启用自动滚动默认为 true * property {Function} onSort - 排序完成后的回调函数 * property {Function} onStart - 拖拽开始时的回调函数 * property {Function} onEnd - 拖拽结束时的回调函数 * property {Function} onMove - 拖拽移动时的回调函数 */ /** * 拖拽排序组合式函数 * param {string|Ref} tableRef - 表格引用 * param {RefArray} dataList - 数据列表引用 * param {SortableOptions} options - 配置选项 * returns {Object} 拖拽控制方法 */ export function useSortableDrag(tableRef, dataList, options {}) { const { handle .drag-handle, animation 150, easing cubic-bezier(0.25, 0.46, 0.45, 0.94), scrollThreshold 80, scrollSpeed 15, autoScroll true, onSort null, onStart null, onEnd null, onMove null } options let sortableInstance null let autoScrollTimer null let autoScrollDirection 0 // 0: 停止, 1: 向下, -1: 向上 const isDragging ref(false) // 停止自动滚动 const stopAutoScroll () { if (autoScrollTimer) { clearInterval(autoScrollTimer) autoScrollTimer null } autoScrollDirection 0 } // 启动自动滚动 const startAutoScroll (tableWrapper) { if (!autoScroll || autoScrollTimer) return autoScrollTimer setInterval(() { if (autoScrollDirection 0 || !tableWrapper) return const scrollTop tableWrapper.scrollTop const maxScrollTop tableWrapper.scrollHeight - tableWrapper.clientHeight let newScrollTop scrollTop autoScrollDirection * scrollSpeed // 限制滚动范围 if (newScrollTop 0) { newScrollTop 0 autoScrollDirection 0 stopAutoScroll() } else if (newScrollTop maxScrollTop) { newScrollTop maxScrollTop autoScrollDirection 0 stopAutoScroll() } tableWrapper.scrollTop newScrollTop }, 16) // 约 60fps } // 获取表格包装器 const getTableWrapper () { if (!tableRef.value) return null // 兼容不同的表格组件 if (tableRef.value.$el) { return tableRef.value.$el.querySelector(.el-table__body-wrapper) } return tableRef.value.querySelector?.(.el-table__body-wrapper) || null } // 获取表格主体 const getTableBody () { const wrapper getTableWrapper() return wrapper?.querySelector(tbody) || null } // 初始化拖拽 const initSortable () { if (!tableRef.value) { console.warn(useSortableDrag: tableRef is not ready) return } const tableBody getTableBody() const tableWrapper getTableWrapper() if (!tableBody || !tableWrapper) { console.warn(useSortableDrag: table body or wrapper not found) return } // 如果已经存在实例先销毁 destroySortable() sortableInstance Sortable.create(tableBody, { handle, animation, easing, scroll: false, // 禁用默认滚动使用自定义滚动 onStart: (evt) { isDragging.value true document.body.style.cursor grabbing if (onStart) onStart(evt) }, onMove: (evt) { if (!autoScroll) { if (onMove) onMove(evt) return } const { originalEvent } evt const clientY originalEvent.clientY if (!tableWrapper) return const rect tableWrapper.getBoundingClientRect() const relativeY clientY - rect.top // 检查是否在边缘区域 if (relativeY scrollThreshold) { // 向上滚动 autoScrollDirection -1 startAutoScroll(tableWrapper) } else if (relativeY rect.height - scrollThreshold) { // 向下滚动 autoScrollDirection 1 startAutoScroll(tableWrapper) } else { // 停止滚动 autoScrollDirection 0 stopAutoScroll() } if (onMove) onMove(evt) }, onEnd: (evt) { // 拖拽结束时停止自动滚动 stopAutoScroll() document.body.style.cursor isDragging.value false const { oldIndex, newIndex } evt if (oldIndex newIndex) { if (onEnd) onEnd(evt) return } // 移动数据 const [movedItem] dataList.value.splice(oldIndex, 1) dataList.value.splice(newIndex, 0, movedItem) if (onSort) onSort(evt, movedItem, oldIndex, newIndex) if (onEnd) onEnd(evt) } }) } // 销毁拖拽实例 const destroySortable () { if (sortableInstance) { sortableInstance.destroy() sortableInstance null } stopAutoScroll() } // 更新拖拽实例当数据变化时重新初始化 const refreshSortable () { nextTick(() { initSortable() }) } // 禁用拖拽 const disableSortable () { if (sortableInstance) { sortableInstance.option(disabled, true) } } // 启用拖拽 const enableSortable () { if (sortableInstance) { sortableInstance.option(disabled, false) } } // 设置拖拽手柄选择器 const setHandle (selector) { if (sortableInstance) { sortableInstance.option(handle, selector) } } // 生命周期钩子 onMounted(() { // 延迟初始化确保 DOM 已渲染 setTimeout(initSortable, 100) }) onBeforeUnmount(() { destroySortable() }) return { initSortable, destroySortable, refreshSortable, disableSortable, enableSortable, setHandle, isDragging, stopAutoScroll } }3.在需要用到的地方添加el-table-column aligncenter fixed width40 label template #default el-icon classdrag-handle stylecursor: grab; color: #909399 Operation / /el-icon /template /el-table-column // 使用拖拽排序功能 const { refreshSortable } useSortableDrag(tableRef, chainTableList, { handle: .drag-handle, animation: 150, autoScroll: true, scrollThreshold: 80, scrollSpeed: 15, disabled: false }) async function getData() { …… refreshSortable() }
返回列表