一文搞懂drag&drop浏览器拖放功能的实现
拖放功能,即将一个元素从一个区域,通过拖拽,放置到另一个区域。常见的应用是将文件或图片从一个区域,拖放到另一个区域。中文常常把这表述成拖拽,实际上拖拽的描述并不准确,应该叫拖放,因为drag事件和drop事件是成对使用的,即拖拽和放置。
drag在拖拽动作发生时触发,携带被拖拽元素的信息,drop在放置元素时触发,接收传递的拖拽元素的信息。
由于常常表述成拖拽,所以有些人在实现拖动功能时以为会触发drag事件,比如侧边栏拖拽。实际上drag是为拖放功能设计的(要配合drop),拖动(or拖拽)的功能应该用mousemove事件去实现,用错事件就会觉得怎么拖拽功能好难啊。
P.S.
drag和mousemove事件都是在移动鼠标的过程中触发,所以两个事件是会冲突的,如果发现其中一个事件不生效,可以检查下是不是因为有元素绑定了其中一个事件,导致另一个事件没有trigger。
具体实现
拖放,拖拽和放置,那么自然需要一个拖拽的区域,和一个放置的区域。
首先,要定义允许拖拽的元素。浏览器的默认行为是,文本、图像和链接是允许拖拽的。即<p>、<img>、<a>标签是默认允许拖拽的,其他元素要允许拖拽,则要设置draggle="true"。这个属性不允许简写。<div draggable ></div>并不会生效。
其次,要定义拖拽的数据。比如,拖拽的是文本,则设置成文本格式,并设置拖拽的数据内容。拖拽的是图片,则设置成图片格式,设置数据内容。定义成图片格式,那么拖拽的时候,鼠标旁边就会显示一张设置的图片。设置的拖拽数据可以有多个。
先给拖拽的元素绑定dragstart事件,再设置dataTransfer。示例代码如下:
function dragstart_handler(ev) {
// 添加拖拽数据
ev.dataTransfer.setData("text/plain", ev.target.innerText);
ev.dataTransfer.setData("text/html", ev.target.outerHTML);
ev.dataTransfer.setData(
"text/uri-list",
ev.target.ownerDocument.location.href,
);
}
拖放相关的事件对象event中,有一个dataTranster属性,这个属性保存着拖放过程中的数据。并有一些属性和方法设置和操作这些数据。
比较常用到的属性和方法有:
dropEffect:设置放置操作的类型,可以修改放置时鼠标的显示。比如设置成none,鼠标就会显示成禁止的样式。
effectAllowed:设置拖放过程的操作类型,同样影响鼠标的显示。
setData():设置拖放的数据。一般会在dragstart事件中用到。一个事件中,setData可以设置多个数据。但同类型的数据只能添加一项,重复添加会被最后添加的覆盖。
getData():检索获取拖放的数据。一般会在drop事件中用到。
具体可以参考MDN文档。
最后,就是在drop区域中放置拖拽的元素。
一个代码示例:
function drop_handler(ev) {
const data = ev.dataTransfer.getData("text/plain");
ev.target.textContent = data;
}
这样,拖放就结束了。拖放功能也完成了。
在拖放过程中,有一些全局事件触发,可以参考下表,具体请查看MDN文档。
| 事件 | 触发时刻 |
|---|---|
drag |
当拖拽元素或选中的文本时触发。 |
dragend |
当拖拽操作结束时触发 (比如松开鼠标按键或敲“Esc”键). |
dragenter |
当拖拽元素或选中的文本刚进入到一个可释放目标时触发。 |
dragleave |
当拖拽元素或选中的文本离开一个可释放目标时触发。 |
dragover |
当元素或选中的文本被拖到一个可释放目标上时触发(每 100 毫秒触发一次)。 |
dragstart |
当用户开始拖拽一个元素或选中的文本时触发。 |
drop |
当元素或选中的文本在可释放目标上被释放时触发。 |
一些问题
但是,这样实现拖放功能会有一些体验问题,鼠标的样式显示可能不正确。
以下是一些可能的问题:
1.禁止放置的区域没有显示禁止图标。
在区域上绑定dragover事件,设置dataTransfer.dropEffect='none'并禁止默认行为e.preventDefault()。
2.禁止放置的区域可以放置。
通常默认可以放置的区域是一些输入标签,比如<input>、<textarea>。在drop事件中,禁止默认行为e.preventDefault()可以禁止放置。
3.拖拽过程和可放置区域中,鼠标显示禁止图标。
在经过或者放置的区域上,在dragover和dragenter事件中禁止默认行为e.preventDefault(),设置dataTransfer为none以外的值。
4.拖拽图片时,鼠标旁边没有出现图片。
要在dragstart事件中,设置dataTransfer为图片类型才会显示一张图片。如果拖拽的不是图片,但是希望拖拽时有拖拽元素的图片效果显示,也可以设置dataTransfer为图片,设置要显示的图片效果,然后再设置其他的数据。dataTransfer.setData()方法是可以设置多个类型的数据的。
这样拖放功能的实现基本就完善了。最后在开始拖拽和放置的时候,可能会给拖拽元素和放置区域设置一些高亮的css效果,整个拖放功能的体验就会很流畅。
参考:
draggable属性:draggable - HTML(超文本标记语言) | MDN (mozilla.org)
拖放API:HTML 拖放 API - Web API | MDN (mozilla.org)
DataTransfer:DataTransfer - Web API | MDN (mozilla.org)
一文搞懂drag&drop浏览器拖放功能的实现的更多相关文章
- Web端即时通讯基础知识补课:一文搞懂跨域的所有问题!
本文原作者: Wizey,作者博客:http://wenshixin.gitee.io,即时通讯网收录时有改动,感谢原作者的无私分享. 1.引言 典型的Web端即时通讯技术应用场景,主要有以下两种形式 ...
- 三文搞懂学会Docker容器技术(下)
接着上面一篇:三文搞懂学会Docker容器技术(上) 三文搞懂学会Docker容器技术(中) 7,Docker容器目录挂载 7.1 简介 容器目录挂载: 我们可以在创建容器的时候,将宿主机的目录与容器 ...
- 一文搞懂RAM、ROM、SDRAM、DRAM、DDR、flash等存储介质
一文搞懂RAM.ROM.SDRAM.DRAM.DDR.flash等存储介质 存储介质基本分类:ROM和RAM RAM:随机访问存储器(Random Access Memory),易失性.是与CPU直接 ...
- 基础篇|一文搞懂RNN(循环神经网络)
基础篇|一文搞懂RNN(循环神经网络) https://mp.weixin.qq.com/s/va1gmavl2ZESgnM7biORQg 神经网络基础 神经网络可以当做是能够拟合任意函数的黑盒子,只 ...
- 一文搞懂 Prometheus 的直方图
原文链接:一文搞懂 Prometheus 的直方图 Prometheus 中提供了四种指标类型(参考:Prometheus 的指标类型),其中直方图(Histogram)和摘要(Summary)是最复 ...
- 一文搞懂vim复制粘贴
转载自本人独立博客https://liushiming.cn/2020/01/18/copy-and-paste-in-vim/ 概述 复制粘贴是文本编辑最常用的功能,但是在vim中复制粘贴还是有点麻 ...
- 三文搞懂学会Docker容器技术(中)
接着上面一篇:三文搞懂学会Docker容器技术(上) 6,Docker容器 6.1 创建并启动容器 docker run [OPTIONS] IMAGE [COMMAND] [ARG...] --na ...
- 一文搞懂所有Java集合面试题
Java集合 刚刚经历过秋招,看了大量的面经,顺便将常见的Java集合常考知识点总结了一下,并根据被问到的频率大致做了一个标注.一颗星表示知识点需要了解,被问到的频率不高,面试时起码能说个差不多.两颗 ...
- 一文搞懂 js 中的各种 for 循环的不同之处
一文搞懂 js 中的各种 for 循环的不同之处 See the Pen for...in vs for...of by xgqfrms (@xgqfrms) on CodePen. for &quo ...
- 一文搞懂如何使用Node.js进行TCP网络通信
摘要: 网络是通信互联的基础,Node.js提供了net.http.dgram等模块,分别用来实现TCP.HTTP.UDP的通信,本文主要对使用Node.js的TCP通信部份进行实践记录. 本文分享自 ...
随机推荐
- 绘制三元图、颜色空间图:R语言代码
本文介绍基于R语言中的Ternary包,绘制三元图(Ternary Plot)的详细方法:其中,我们就以RGB三色分布图为例来具体介绍. 三元图可以从三个不同的角度反映数据的特征,因此在很多领 ...
- Lambda表达式编写递归函数
class Program { //Fix求出的是函数f的不动点,它就是我们所需要的递归函数: static Func<T, TResult> Fix<T, TResult>( ...
- KingbaseESV8R6全局临时表不能进行reindex操作
背景 我们经常遇到两种情况下会重建索引,reindex 1.索引崩溃,由于软件或硬件问题导致索引内数据失效而不可用. 2.索引膨胀,当索引膨胀会占用过多磁盘空间,reindex可以解决此问题. 对于临 ...
- KingbaseES V8R6 运维案例 --ksql访问动态库问题
KingbaseES V8R6数据库运维案例之---ksql访问动态库问题 案例说明: CentOS环境下,在安装和初始化数据库实例后,启动数据库服务,通过ksql连接访问时出现以下故障: 经检查,是 ...
- stm32F103 移植Free RTOS
stm32F103 移植Free RTOS 1. 下载FreeRTOS 源码 [官网下载] (http://www.freertos.org) [代码托管网站下载] (https://sourcefo ...
- Windows10系统重装教程
.
- Linux下Bochs,NASM安装和使用
安装环境 以Ubuntu为例,先更新一下: sudo apt-get update sudo apt-get upgrade 然后安装Bochs环境: sudo apt-get install bui ...
- #三分,分治,计算几何,prim#JZOJ 3860 地壳运动
题目 \(q\)组询问查询最小生成树,边权为\(u*k1+v*k2\)(\(k1,k2\)每次询问都不同) \(n\leq 35,m\leq 25000,q\leq 200000\) 分析 纯\(\t ...
- easyexcel实现导出添加文字水印
引入jar包 由于easyexcel没有引入ooxml-schemas包,所以需要额外添加. <!-- easyexcel依赖 --> <dependency> <gro ...
- 2024-04-13:用go语言,给定一个整数数组 `nums`, 请编写一个函数,返回一个新的数组 `counts`。 满足以下条件:对于每个 `nums[i]`, `counts[i]` 表示在
2024-04-13:用go语言,给定一个整数数组 nums, 请编写一个函数,返回一个新的数组 counts. 满足以下条件:对于每个 nums[i], counts[i] 表示在 nums[i] ...