一、组件介绍
Vue是一个优秀的前端框架,能够帮助开发者快速构建优秀的Web应用程序。其中,拖拽排序组件是一种非常实用的UI组件,能够帮助用户进行元素的拖拽、移动等操作,提高用户的使用效率。
本文介绍的这个组件使用Vue框架实现,使用简单,且支持多种常见的拖拽排序功能,包括拖拽移动、交换位置、拖拽排序、拖拽删除等,非常适用于需要拖拽排序的场合,包括网页排版、图片库管理等领域。
二、组件应用
下面是一个使用Vue实现的可拖拽排序组件的例子,供读者参考使用:
<template> <ul class="drag-list"> <li v-for="(item, index) in list" :key="index" :class="{ active: activeIndex === index }" @mousedown="handleMousedown(index, $event)" @mousemove="handleMousemove(index, $event)" @mouseup="handleMouseup(index)" :style="getStyle(index)" > {{ item }} <i class="delete" @click="handleDelete(index)"></i> </li> </ul> </template> <script> export default { data() { return { list: ["元素1", "元素2", "元素3", "元素4", "元素5", "元素6", "元素7"], activeIndex: -1, dragStartPos: { x: 0, y: 0 }, draggingPos: { x: 0, y: 0 }, distanceX: 0, distanceY: 0, dragging: false }; }, methods: { handleMousedown(index, e) { this.activeIndex = index; this.dragging = true; this.dragStartPos.x = e.pageX; this.dragStartPos.y = e.pageY; this.draggingPos.x = e.pageX; this.draggingPos.y = e.pageY; }, handleMousemove(index, e) { if (this.dragging) { this.distanceX = e.pageX - this.draggingPos.x; this.distanceY = e.pageY - this.draggingPos.y; this.draggingPos.x = e.pageX; this.draggingPos.y = e.pageY; const targetIndex = this.getTargetIndex(index, e); if (targetIndex !== index) { this.list.splice(targetIndex, 0, this.list.splice(index, 1)[0]); this.activeIndex = targetIndex; } // 限制拖动范围 const limitList = document.querySelector(".drag-list"); const limitTop = limitList.offsetTop; const limitBottom = limitList.offsetHeight + limitTop; if (e.pageY < limitTop) { window.scrollTo(0, window.pageYOffset - 10); } else if (e.pageY > limitBottom) { window.scrollTo(0, window.pageYOffset + 10); } } }, handleMouseup(index) { if (this.dragging) { this.dragging = false; if (this.distanceX !== 0 || this.distanceY !== 0) { this.list.splice(this.activeIndex, 1); this.list.splice(index, 0, this.list[this.activeIndex]); } this.activeIndex = -1; this.distanceX = 0; this.distanceY = 0; } }, handleDelete(index) { this.list.splice(index, 1); }, getStyle(index) { if (this.dragging && this.activeIndex === index) { return { transform: `translate(${this.distanceX}px, ${this.distanceY}px)`, zIndex: 99 }; } }, getTargetIndex(index, e) { const targetEle = document.elementFromPoint( e.clientX - this.distanceX, e.clientY - this.distanceY ); if (targetEle.classList.contains("delete")) { return index; } else { const targetList = targetEle.parentNode; const targetIndex = Array.prototype.indexOf.call( targetList.children, targetEle ); return targetIndex; } } } }; </script> <style> .drag-list { list-style-type: none; padding: 0; margin: 0; border: 1px solid #ccc; } .drag-list li { display: flex; align-items: center; justify-content: space-between; padding: 10px; border-top: 1px solid #eee; } .drag-list li:hover { background-color: #f0f0f0; } .drag-list .active { background-color: #aad8d3; color: #fff; } .drag-list i { color: red; cursor: pointer; } </style>
这是一个简单而功能强大的可拖拽排序组件,解释代码如下:
- 在data中定义list,用来存储排序列表数据
- 该组件提供四个事件回调函数:handleMousedown、handleMousemove、handleMouseup、handleDelete。handleMousedown事件绑定到列表元素上,当用户鼠标按下时会触发该事件;handleMousemove事件绑定到列表元素上,当用户拖动元素时会多次触发该事件;handleMouseup事件绑定到列表元素上,当用户松开鼠标时会触发该事件;handleDelete事件绑定到每个元素的删除按钮。组件内部通过判断拖拽距离是否为0,来判断是否需要进行元素的排序。
- getStyle函数用来设置被拖拽元素的样式
- getTargetIndex函数用来获取列表位置
三、组件优化方案
虽然上面的组件已经实现拖拽排序的功能,但是在特定情况下,该组件还有较大的优化空间,可以提高程序的性能和用户体验。以下是优化方案:
1、使用window.requestAnimationFrame()
使用requestAnimationFrame()方法代替mousemove()事件,可以在不阻塞浏览器的情况下,让组件流畅地运行。
handleMousemove(index, e) { if (this.dragging) { window.requestAnimationFrame(() => { // 处理拖拽元素的位置变化等逻辑 }) } }
2、使用位运算优化性能
在复杂的拖拽操作中,位运算可以帮助提升一些性能,比如位移运算、按位与运算等。
handleMousemove(index, e) { if (this.dragging) { window.requestAnimationFrame(() => { const deltaX = e.pageX - this.draggingPos.x; const deltaY = e.pageY - this.draggingPos.y; const targetIndex = (Math.round(e.pageY / this.$refs.itemHeight) - 1) * this.cols + Math.round(e.pageX / this.$refs.itemWidth) - 1; // 处理拖拽元素的位置变化等逻辑 }) } }
3、使用CSS3动画和transition
在标准的页面布局中,大量使用JS来实现可视化效果,这种实现方式会造成过多的DOM操作和样式请求,导致页面重新渲染。如果我们使用CSS3动画和transition,我们就可以在不占用js的情况下,通过GPU加速来快速渲染页面。
.drag-list li { transition: transform .2s ease-out; }
4、使用虚拟列表
在长列表中,可能存在大量的DOM节点渲染,这一过程可能比较耗时,影响用户体验。使用虚拟列表方案,可以只渲染列表中可视化的部分,避免过多的DOM操作。
<template> <div class="drag-list"> <div :style="{ height: itemHeight * rowCount + 'px' }"></div> <div ref="listWrapper" :style="{ height: wrapperHeight }" @scroll="onScroll" > <ul :style="{ transform: 'translateY(' + scrollTop + 'px)' }"> <li v-for="(item, index) in visibleList" :key="item.id" :style="{ top: (index % cols) * itemHeight + 'px', left: Math.floor(index / cols) * itemWidth + 'px' }" @mousedown="handleMousedown(index, $event)" @mouseup="handleMouseup(index)" > {{ item.value }} </li> </ul> </div> </div> </template> <script> export default { computed: { visibleList() { const start = Math.floor(this.scrollTop / this.itemHeight) * this.cols; const end = start + (this.rowCount + 1) * this.cols; return this.dataList.slice(start, end); } }, methods: { onScroll() { this.scrollTop = this.$refs.listWrapper.scrollTop; } } }; </script> <style> .drag-list { position: relative; } .drag-list ul { position: absolute; list-style: none; padding: 0; margin: 0; width: 100%; } .drag-list li { position: absolute; display: flex; justify-content: center; align-items: center; width: 100px; height: 100px; border: 1px solid #ddd; box-sizing: border-box; } .drag-list li:hover { background: #f8f8f8; } </style>
四、总结
本文介绍了使用Vue框架实现的可拖拽排序组件,并提供了一些常见的优化方案,可以帮助开发者提高程序的性能和用户体验。在实际应用中,我们还可以根据具体情况进行进一步的优化,让程序更加符合用户需求。