10分钟实现简易vue拖拽排序(代码片段)

毕竟我是崔战神阿 毕竟我是崔战神阿     2022-12-11     488

关键词:

背景

平平无奇的一天,博主正在敲着自己的项目,这时候被领导告知要我写一个工程自动化工具,接到需求的时候我的大脑便开始疯狂转圈(因为我需要前后端都做,相对来说思考的东西要多一点),后来在思考数据设计,接口数据处理的一些细节之后,终于是有条不紊的进行了。
But ,一个Vue的拖拽排序功能如何实现却让我犯了难,在痛苦的学习中我终于明白了这个东西是怎么玩的 记录的同时进行分享,希望能帮助到有同样需求的码农们(狗头)

文章目录


第一步是MDN拖拽方法总结,若无兴趣可以略过。

本着做什么功能都尽量不导入包的思维,
我放弃了使用vue的插件(需要导入的包太大,冗余代码太多)
转而选择使用H5原生来实现这个功能


一、官方关于拖拽方法和属性有哪些?

首先让我们看一下MDN上对拖拽的方法的一些总结。

1.可拖拽属性 draggable

在 HTML 中,除了图像、链接和选择的文本默认的可拖拽行为之外,其他元素在默认情况下是不可拖拽的。要使其他的 HTML 元素可拖拽,
必须做三件事:
1.将想要拖拽的元素的 draggable 属性设置成 draggable="true"
2.为 dragstart () 事件添加一个监听程序
3.在上一步定义的监听程序中 设置拖拽数据

	<p draggable="true" 
	   ondragstart="event.dataTransfer.setData('text/plain', 'This text may be dragged')">
	  这个文本 <strong>可以</strong> 被拖拽.
	</p>

2.开始拖拽操作 dragstart

当用户开始拖拽时,会触发 dragstart ()。 事件
在这个例子中, dragstart ()。事件监听程序被添加到可拖拽元素本身;然而,你可以监听一个 祖先元素,因为就像大多数其他事件一样,拖拽事件会冒泡。
dragstart ()。事件中,你可以指定拖拽数据、反馈图像和拖拽效果,所有这些都将在下面描述。不过,我们只需要设置拖拽数据,因为在大多数情况下默认的图像和拖拽效果都是适用的。

	<p draggable="true" ondragstart="event.dataTransfer.setData('text/plain', 'This text may be dragged')">
	  这个文本 <strong>可以</strong> 被拖拽.
	</p>

3.拖拽数据 dataTransfer

所有 拖拽事件 都有一个名为 dataTransfer 的属性,它持有拖拽数据(dataTransfer 是一个 DataTransfer 对象)。
这个属性有两个参数,简而言之,第一个参数是你允许拖拽的类型,第二个是放置到指定链接的数据

	event.dataTransfer.setData("text/plain", "可拖拽的文本");
  • 你还可以提供多种类型的数据,代码如下:
	const dt = event.dataTransfer;
	dt.setData("application/x.bookmark", bookmarkString);
	dt.setData("text/uri-list", "http://www.abc.org");
	dt.setData("text/plain", "http://www.abc.org");
  • 如果你用相同格式重复添加,新数据会替换旧数据,你可以清除它们,代码如下:
	event.dataTransfer.clearData("text/uri-list");

4.设置拖拽反馈图像 setDragImage

当拖拽发生时,会生成拖拽目标的一个半透明图像(触发"event("dragstart")" 事件的元素),并在拖拽过程中跟踪鼠标指针。这个图像是自动创建的,所以你不需要自己创建它。但是,你可以使用 setDragImage() 方法来自定义拖拽反馈图像。

	event.dataTransfer.setDragImage(image, xOffset, yOffset);
  • 这三个参数都是必要的。第一个是图像的引用。这个引用通常是一个 <img> 元素
    但也可以是 <canvas> 或任何其他元素。生成的反馈图像就是该图像在屏幕上的样子,
    以图像原始的大小绘制。
    setDragImage() 方法的第二、三个参数是图像位置相对于鼠标指针位置的偏移量。
    也可以使用不在文档中的图像和画布。这种技术在使用 canvas 元素绘制自定义的拖拽反馈图像时非常有用,如下面的例子:

    function dragWithCustomImage(event) 
      var canvas = document.createElementNS("http://www.w3.org/1999/xhtml","canvas");
      canvas.width = canvas.height = 50;
    
      var ctx = canvas.getContext("2d");
      ctx.lineWidth = 4;
      ctx.moveTo(0, 0);
      ctx.lineTo(50, 50);
      ctx.moveTo(0, 50);
      ctx.lineTo(50, 0);
      ctx.stroke();
    
      var dt = event.dataTransfer;
      dt.setData('text/plain', 拖拽的数据');
      dt.setDragImage(canvas, 25, 25);
    
    

    在这个例子中,我们做了一个是画布的拖拽图像。当画布宽 50 像素,高 50 像素时,我们使用一半的偏移量(25 和 25),这样鼠标指针即为图像中心。

5.拖拽效果 effectAllowed

拖拽过程中可能会执行一些操作。 copy 操作用来指示被拖拽的数据将从当前位置复制到放置位置。 move 操作指示被拖拽的数据会被移动,link 操作表示在源和放置位置之间将会创建某种形式的关系或连接。
可以在 dragstart () 事件监听程序中设置 effectAllowed 属性以指定允许拖拽源头执行三种操作中的哪几种。

	event.dataTransfer.effectAllowed = "copy";
 	以上代码示例为只允许复制,你可以用不用的方式来实现你的需求:
	 1. none:不允许操作
	 2. copy:只复制
	 3. move:只移动
	 4. link:只链接
	 5. copyMove:复制或移动
	 6. copyLink:复制或链接
	 7. linkMove:链接或移动
	 8. all:复制,移动或链接

6.指定放置目标 dragover

dragenter ()dragover () 事件的监听程序用于表示有效的放置目标,也就是被拖拽项目可能放置的地方。网页或应用程序的大多数区域都不是放置数据的有效位置。因此,这些事件的默认处理是不允许放置。

如果你想要允许放置,你必须取消 dragenterdragover事件来阻止默认的处理。你可以在属性定义的事件监听程序返回 false,或者调用事件的 preventDefault() 方法来实现这一点。在一个独立脚本中的定义的函数里,可能后者更可行。

<div ondragover="return false">
<div ondragover="event.preventDefault()">

7.放置反馈 -moz-drag-over CSS

有几种方法可以向用户表明哪个位置允许放置。鼠标指针将根据 dropEffect 属性的值做必要的更新。鼠标指针具体的外观取决于用户平台,典型的如加号图标会出现在 ‘copy’ 中,而不允许放置时,会出现禁止放置的图标。在许多情况下,鼠标指针反馈就足够了。

但是,你还可以根据需要更新用户界面,如添加一个插入标记或使用高亮显示。对于简单的高亮显示,你可以在放置目标上使用 -moz-drag-over CSS 伪类。

.droparea:-moz-drag-over 
  border: 1px solid black;

注意:要使这个伪类生效,必须要在 dragenter 事件添加preventDefault()方法

8.执行放置 drop

当用户放开鼠标,拖放操作就会结束。

如果在有效的放置目标元素(即取消了 dragenter ()dragover () 的元素)上放开鼠标,放置会成功实现,drop () 事件在目标元素上被触发。否则拖拽会被取消,
不会触发 drop () 事件。

在所有拖拽操作相关的事件中,事件的 domxref("DragEvent.dataTransfer","dataTransfer") 属性会一直保存着拖拽数据。可使用 getData() 方法来取回数据。

function onDrop(event) 
  const data = event.dataTransfer.getData("text/plain");
  event.target.textContent = data;
  event.preventDefault();

8.完成拖拽 dragend

一旦拖拽完成,dragend () 事件会在拖拽源头(即触发 dragstart () 的元素)上发生。无论拖拽是成功还是被取消,这个事件都会被触发。然而,你可以使用 dropEffect 属性来决定执行什么放置操作。
如果在dragend () 事件中,dropEffect 属性值为 none,则拖拽会被取消。否则,这个属性会规定需要执行什么操作。源头元素可使用这个信息以在拖拽操作完成后从原来的位置移除被拖拽的项目。mozUserCancelled () 属性会在用户取消拖拽(按下 Esc 键)时设置为 true,在拖拽因为其他原因如无效放置目标等被取消时,或拖拽成功时,则设置为 false

放置可发生在同一窗口或另一个应用程序中。两种情况都会触发 dragend () 事件。事件的 screenXscreenY 属性会被设置为放置发生时鼠标在屏幕上的坐标。

event("dragend") 事件结束后,整个拖放操作就完成了。

二、开始实现

1.在总结完拖拽方法之后,拖拽-开始-进入-结束应当是正常流程

任何一个单独的事件都不可能完成我的业务需求,但是组合就可以,于是我用了以下事件

  1. dragstart 通过传给函数的index来知晓拖动的是哪个元素
  2. dragenter 通过index来知晓最后进入的是哪个元素
  3. dragend 元素放置时立马执行对应逻辑,将拖动元素的数据和最后放置元素的数据进行交换
  4. dragover 通过禁用父级的默认属性,来取消掉子元素的拖动禁止按钮

于是我添加了如下代码(示例):

	<view
		@dragstart="dragstart(index)"
		@dragenter.prevent="dragenter($event, index)"
		@dragend="dragend($event, index)"
	>
		拖拽测试代码
	</view>

对应函数为:

		dragstart(index) 
			console.log(index)
			this.startIndex = index;//存储开始拖动时候的下标,可以知道从哪个地方开始拖动的
		,
		dragenter(e, index) 
			console.log(e,index)
			this.endIndex = index;//存储结束拖动时候的下标,可以知道最后进入的是哪个元素
		,
		dragend(e, index) 
			console.log(e,index)
			let  startIndex, endIndex  = this; //有开始和结束直接把对应数据交换值就可以了
		,

值得注意的地方是,如果用第三方变量交换数据的时候,建议使用深拷贝给数据源进行复制,
Vue2.0的数组和对象的双向绑定一直是硬伤,
切记赋值的时候要用this.$set('必定有的数据','哪个属性','赋值数据源')

2.渐入佳境

值得欣慰的是现在简易版的基础拖动排序已经基本完成了,但这个时候出现一个问题:
在进行拖拽的时候,一直有一个禁用的图标显示,我意识到肯定是哪个地方做得不对了,经过多处查询文档,发现了出现这个的原因:
原来在拖拽的元素上,其父级必须要禁用默认阻止其放置的属性才会不出现这个禁止图标,
于是对代码进行修改,最后的代码如下所示:

<view  @dragover.prevent="allowDrop($event)">
	<view
		@dragstart="dragstart(index)"
		@dragenter.prevent="dragenter($event, index)"
		@dragend="dragend($event, index)"
	>
		拖拽测试代码
	</view>
</view>
		dragstart(index) 
			console.log(index)
			this.startIndex = index;//存储开始拖动时候的下标,可以知道从哪个地方开始拖动的
		,
		dragenter(e, index) 
			console.log(e,index)
			this.endIndex = index;//存储结束拖动时候的下标,可以知道最后进入的是哪个元素
		,
		dragend(e, index) 
			console.log(e,index)
			let  startIndex, endIndex  = this; //有开始和结束直接把对应数据交换值就可以了
		,
		allowDrop(e)
			e.preventDefault()  //禁用父级元素默认阻止放置的属性,使元素可进行放置(不出现禁用图标)
		,
		

3.打完收工

由于每人的业务需求不一样,具体的逻辑要自己写,成品实例如下图:


由于录制软件原因,拖动过程的动画被默认压缩了,显得动画不够流畅,这个没有办法,因为是白嫖的


总结

好记性不如烂笔头
随时随地给自己对项目的状态进行实时的记录,想来以后回忆起来也是极美的

明天,又是充满希望的一天!

最后放上一张镇楼图

uni-app技术分享|10分钟实现一个简易uniapp视频通话(代码片段)

视频讲解视频地址创建uniapp项目创建uniapp项目前往anyRTC控制台-项目管理创建新项目,获取appid引入插件前往uniapp插件市场搜索anyRTC,选中anyRTC音视频SDK插件云打包购买插件(免费引入)引入创建的对应uniapp项目uniapp项目的man... 查看详情

基于vue实现可以拖拽的树形表格实例详解(代码片段)

...合适的,大部分树形表格都没有拖拽功能,所以决定自己实现一个。这里分享一下实现过程,项目源代码请看github,插件已打包封装好,发布到npm上 本博文会分为两部分,第一部分为使用方式,第二部分为实现方式安装方式npm... 查看详情

5分钟实现一个可拖拽矩形(代码片段)

一、写在前面写这个原因很简单,有这么一个需求如下:编写代码实现以下要求:画一个矩形,拖拽矩形的4个角可以将矩形缩放,在矩形上按住鼠标拖动可以移动该矩形的位置。要求如下:整个矩形的最... 查看详情

vue实现拖拽(代码片段)

...creenX和screenY2、clientX和clientY3、pageX和pageY4、offsetX和offsetY实现拖拽拖拽拖拽是我们在项目开发中,必不可少的技能之一,关于拖拽,我们有些人很是头疼,因为搞不懂搞用哪个属性,那么我们先来说说关于页... 查看详情

vue实现拖拽(代码片段)

...creenX和screenY2、clientX和clientY3、pageX和pageY4、offsetX和offsetY实现拖拽拖拽拖拽是我们在项目开发中,必不可少的技能之一,关于拖拽,我们有些人很是头疼,因为搞不懂搞用哪个属性,那么我们先来说说关于页... 查看详情

gridview实现拖拽排序以及数据交互(代码片段)

...查找资料过程中发现有人有这么一种需求,就是GridView在实现拖拽排序的基础上,如果是两个GridView之间实现拖拽效果,并要实现数据交互。一、效果图:                &n... 查看详情

vue基于vuedraggable实现拖拽(代码片段)

进入项目目录npmivuedraggable-S在vue页面script中引入并且注册<!--1组无法拖拽到2组--><draggablev-model="resultList"@end="dragged"><divv-for="iteminresultList"v-if=' 查看详情

vue使用websocket模拟实现聊天功能-简易版(代码片段)

vue使用WebSocket模拟实现聊天功能-简易版效果展示两个浏览器相互模拟1.创建模拟node服务在vue根目录下创建server.js文件模拟后端服务器**在server终端目录下载**npminstall--sws2.编写server.js文件代码如下varuserNum=0;//统计在线人数varchat... 查看详情

图片上传拖拽排序(代码片段)

...多图片上传,并且可以拖拽排序。前面多图片上传比较好实现,网上一大片的教程、插件可供学习使用,可又要求可以拖拽排序,我也没找到现有的代码,自己也就研究着尝试实现了下,实现的结果还是比较好的。大家有需要的... 查看详情

vue实现bar左右拖拽(代码片段)

效果图功能实现bar左右拖拽左侧:js通过width控制 :style="width: lwidth"右侧:盒子设置定位position,js通过的left来控制,同时样式需要设置 right: 0; bottom: 0; 才会出现width中间:设置定位position,使用calc计算... 查看详情

ngdraggable简单使用及实现拖拽排序(代码片段)

  ngDraggable.js是一款比较简单实用的angularJS拖拽插件,借助于封装好的一些自定义指令,能够快速的进行一些拖拽应用开发。首先先介绍一些基本的概念;ng-drop:是否允许放入拖拽元素ng-drop-success($data,$event):拖拽元素放入的回调;... 查看详情

ios利用uicollectionview拖拽排序实现的仿照腾讯新闻频道管理功能xlchannelcontrol(代码片段)

一、实现效果   频道界面的显示------------》点击进行添加/删除--------》按住可以进行拖拽排序        二、UICollectionView拖拽排序的实现方法1、大概思路*拖拽排序的主要思路是利用在UICollectionView上添加一个长按的手势(... 查看详情

vue+elementui项目实现表格-单行拖拽(代码片段)

最近在项目的中用到了表格单行拖拽的功能,当时直接复制粘贴别人的代码,今天有时间再回头看看:首先VUE+ELEMENT+SORTABLEJS 准备好,对应的是以下版本    1.  "element-ui": "^2.13.2" 2.  "vue":&nb... 查看详情

怎么简单实现菜单拖拽排序的功能(代码片段)

...个「辅助类」,主要用于拖拽以及滑动处理。以接口实现的方式,达到配置简单、逻辑解耦、职责分明的效果,并且支持所有的布局方式。3、功能拆解4、功能实现4.1、实现接口自定义一个类,实现ItemTouchHelper.Call... 查看详情

怎么简单实现菜单拖拽排序的功能(代码片段)

...个「辅助类」,主要用于拖拽以及滑动处理。以接口实现的方式,达到配置简单、逻辑解耦、职责分明的效果,并且支持所有的布局方式。3、功能拆解4、功能实现4.1、实现接口自定义一个类,实现ItemTouchHelper.Call... 查看详情

vue中使用拖拽排序插件awe-dnd(代码片段)

1.安装插件npminstallawe-dnd--save2.引入插件importVueDNDfrom'awe-dnd'Vue.use(VueDND)3.使用插件<template><divclass="title-list"><divv-dragging="item:item,list:list"v 查看详情

vue实现一个简易popover组件(代码片段)

...组件,非常不灵活。最近看museUI库,发现它的下拉框Select实现的非常灵活,点击组件外也能控制下拉框关闭,于是想探究一番, 查看详情

10分钟手把手教你用android手撸一个简易的个人记账app(代码片段)

用Android手撸一个简易的个人记账系统⛱️序言📋一、系统结构设计Design1.需求分析2.数据库设计3.界面设计4.过程设计📘二、编码阶段Coding1.项目结构🗂️(1)文件目录(2)AndroidManifest.xml(3)... 查看详情