> 文章列表 > 前端实现拖拽的方案

前端实现拖拽的方案

前端实现拖拽的方案

  1. 三方类库实现拖拽 PixiJS Examples
  2. H5设置元素 draggable 属性
    每个元素都有draggable 属性,不过默认是false,我们把需要拖放的元素 draggable 属性设置为 true,可实现拖拽功能
    <div draggable="true"></div>

    此时,元素已经可以拖动了,但会显示一个禁止的图标,这是因为没有可放置的区域。
    创建一个区域 只需要在标签上添加 ondragover 和 ondrop 方法即可,表示这个区域可放置并进行处理。

    <div @drop.prevent="drop" @dragover.prevent="dragover"></div>

    还需要在需要拖动的元素上添加 ondragstart 方法。

    <div draggable="true" @dragstart="dragstart()"></div>

    vue中demo代码如下:

    <template><div class="body flex"><div draggable="true"></div><ul><lidraggable="true":ref="'li' + index + 1"v-for="(item, index) in list":key="index"@dragstart="dragstart(index)">{{ item }}</li></ul><div class="box center" @drop.prevent="drop" @dragover.prevent="dragover"><div class="delete" @click="deleteBox()">删除</div><p v-show="content">{{ text }}</p></div></div>
    </template><script>
    export default {name: "",components: {},data() {return {list: ["拖放内容1","拖放内容2","拖放内容3","拖放内容4","拖放内容5","拖放内容6"],text: "",content: false};},computed: {},watch: {},mounted() {},methods: {deleteBox() {this.content = false;},// 拖动开始dragstart(index) {this.text = "您已成功拖放元素" + (index + 1);},// 进行放置drop(event) {this.content = true;console.log("drop", event);},// 放置位置 - 阻止默认事件dragover(event) {event.preventDefault();}}
    };
    </script>
    <style lang="scss" scoped>
    .body {user-select: none; // 禁止选中文字margin: 20px;font-size: 16px;ul {li {border-radius: 5px;cursor: pointer;margin-bottom: 10px;padding: 5px 10px;line-height: 26px;background-color: rgb(221, 221, 221);}}.box {position: relative;margin-left: 100px;width: 500px;height: 500px;border: 1px solid #999;.delete {cursor: pointer;position: absolute;top: 0;right: 0;padding: 5px 10px;background-color: rgba(243, 89, 84, 0.3);border-radius: 5px 0px 5px 5px;}.delete:hover {color: #fff;background-color: rgb(243, 89, 84);}p {font-size: 26px;font-weight: bold;animation: light 1s linear 1;}}@keyframes light {0% {transform: rotate(0deg);}50% {transform: rotate(180deg);}100% {transform: rotate(360deg);}}
    }
    </style>

    效果如下:

  3. canvas 实现拖拽功能
    先创建一个canvas元素
    <canvas id="canvas" width="400" height="300"></canvas>

    生成canvas对象并绑定鼠标事件

    window.onload = function () {canvas = document.getElementById('canvas')context = canvas.getContext('2d')canvas.onmousedown = mouseDowncanvas.onmousemove = mouseMovecanvas.onmouseup = mouseUp
    }

    实现一个绘制矩形方法

    function Rect(startX, startY, endX, endY, color) {this.startX = startXthis.startY = startYthis.endX = endXthis.endY = endYthis.color = colorthis.isSelected = false
    }function drawRects() {clearCanvas()for (let i = 0; i < rectList.length; i++) {let rect = rectList[i]context.globalAlpha = 0.3context.beginPath()context.moveTo(rect.startX, rect.startY)context.lineTo(rect.endX, rect.startY)context.lineTo(rect.endX, rect.endY)context.lineTo(rect.startX, rect.endY)context.lineTo(rect.startX, rect.startY)context.fillStyle = rect.colorcontext.fill()if (rect.isSelected) {context.strokeStyle = 'black'context.stroke()}}
    }function clearCanvas() {// 去除所有圆圈// rectList = []context.clearRect(0, 0, canvas.width, canvas.height)
    }

    鼠标按下时获取基准点,并判断此处位置是否已经存在一个绘制完成的图形,若不存在则标记为 isDrawing = true,若存在则标记为 isDragging = true,
     

    let startX
    let startY
    let width = 0
    let height = 0
    let isDrawing = false
    let isDragging = falsefunction mouseDown(e) {startX = e.offsetXstartY = e.offsetYrectIndex = rectList.findIndex(item => {if (item.startX < item.endX) {if (item.startY < item.endY) {return startX > item.startX && startX < item.endX && startY > item.startY && startY < item.endY} else {return startX > item.startX && startX < item.endX && startY > item.endY && startY < item.startY}} else {if (item.startY < item.endY) {return startX > item.endY && startX < item.startY && startY > item.startY && startY < item.endY} else {return startX > item.startX && startX < item.endX && startY > item.endY && startY < item.startY}}})if (rectIndex !== -1) {currentRect = rectList[rectIndex]isDragging = truecurrentRect.isSelected = trueundoArray.pop()const tempRectList = rectList.slice()const tempCurrentRect = Object.assign({}, currentRect)tempRectList.splice(rectIndex, 1, tempCurrentRect)undoArray.push(tempRectList)} else {isDrawing = true}color = colors[randomFromTo(0, 8)]
    }

    鼠标拖动实时获取所在坐标值,isDrawing 为true 时调用drewRects​​​​​() 方法实时绘制图形,isDragging 为true 时获取新的位差绘制新图形。

    function mouseMove(e) {endX = e.offsetXendY = e.offsetYif (isDrawing) {// context.clearRect(0, 0, canvas.width, canvas.height)drawRects()context.globalAlpha = 0.3context.beginPath()context.moveTo(startX, startY)context.lineTo(endX, startY)context.lineTo(endX, endY)context.lineTo(startX, endY)context.lineTo(startX, startY)context.fillStyle = colorcontext.strokeStyle = 'black'context.fill()context.stroke()} else if (isDragging) {const w = Math.abs(startX - endX)const h = Math.abs(startY - endY)if (endX < startX) {startX -= wendX -= wcurrentRect.startX -= wcurrentRect.endX -= w}if (endX >= startX) {startX += wendX += wcurrentRect.startX += wcurrentRect.endX += w}if (endY < startY) {startY -= hendY -= hcurrentRect.startY -= hcurrentRect.endY -= h}if (endY >= startY) {startY += hendY += hcurrentRect.startY += hcurrentRect.endY += h}// context.clearRect(0, 0, canvas.width, canvas.height)drawRects()}
    }
    

    鼠标抬起时生成一个 Rect()实例完成一个图像绘制,放入图形列表。

    function mouseUp(e) {if (isDrawing) {rectList.unshift(new Rect(startX, startY, endX, endY, color))}if (isDragging) {rectList.forEach(item => {item.isSelected = false})}undoArray.push(rectList.slice())redoArray = []isDrawing = falseisDragging = false
    }

效果图如下: