资讯专栏INFORMATION COLUMN

浏览器拖动API全解析

VioletJack / 1486人阅读

摘要:前言拖动是添加的提供了元素拖动的原生支持拖动相对于其他的事件复杂了一些原因就在于拖动是被拖动元素与被放置元素的互动涉及到了两个元素而不是一个导致流程的复杂但是其中的很多设计是有规律可循的现在我们来看一个基本的使用场景这里有两个元素和是可拖动

前言

拖动api是HTML5添加的API,提供了元素拖动的原生支持

拖动API相对于其他的事件API复杂了一些,原因就在于拖动是被拖动元素与被放置元素的互动涉及到了两个元素,而不是一个导致流程的复杂,但是其中的很多设计是有规律可循的.

现在我们来看一个基本的使用场景,这里有两个元素A和B,A是可拖动元素而B是可放置元素,我们将A放置到B中

鼠标按下后拖动元素A,触发A的dragstart事件

开始移动A元素

刚刚触碰到B容器,触发B的dragenter事件

移动到B上方

触发B容器的dragover事件,该事件类似于mouseover事件是连续触发的

松开鼠标放置A

触发B容器的drop事件

触发A元素的dragend事件

基本流程

我们来实现上面的几个步骤

html

目标区域

注意:被拖动的元素需要设置draggable属性

css

html,
body {
    height: 100%;
}

html,
body,
div {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

#test {
    margin: 0 auto;
    margin-top: 10%;
    width: 50%;
    height: 50%;
    background: #4CB8C4;
    background: linear-gradient(to right, #3CD3AD, #4CB8C4);
    box-shadow: 0 0 15px -3px black;
}

#display {
    margin: 0 auto;
    margin-top: 10%;
    width: 30%;
    height: 30%;
    background-color: rgba(0, 0, 0, 0.055);
}

javascript

let dargElem = document.getElementById("test");
let targetElem = document.getElementById("display");

dargElem.addEventListener("dragstart", (event) => {

    // 被拖动元素开始事件
    console.log(event);
})

// 拖动结束事件
dargElem.addEventListener("dragend", (event) => {

    console.log("拖动结束事件");
})

// 进入容器的事件
targetElem.addEventListener("dragenter", (event) => {

    event.preventDefault();
    console.log("拖动进入事件");
})

// 悬浮到容器上方的事件
targetElem.addEventListener("dragover", (event) => {
    
    event.preventDefault();
})

// 拖动事件
targetElem.addEventListener("drop", (event) => {

    console.log("触发放置事件")
})

这个例子中dargElem保存的是被拖动元素,我们为他注册了dragstartdragend事件,
另外一个变量targetElem是容器元素我们为他注册了dragenter dragover drop 事件

控制台输出:

开始拖动
拖动进入事件
触发放置事件
拖动结束事件

注意:这个例子中使用了event.preventDefault()用于阻止默认的行为,例如拖动a标签的时候有可能触发默认的跳转行为

所有事件列表(不包含厂商事件和浏览器不支持事件):

被拖动的对象

dragstart 拖动开始触发

drag 拖动过程中触发 连续触发

dragend 拖动结束后触发

被当作容器的元素

dragenter 元素进入时候触发

dragover 可拖动元素置于容器元素上方时触发 连续触发

drop 可拖动元素置入到容器元素中触发

dragleave 可拖动元素移动出容器元素时候触发

注意:容器元素一定需要监听dragover事件并且一开始调用event.preventDefault()后续的drop才会触发dragover相当于是一个过滤器,只允许指定的元素可以触发drop事件

数据的交互

前面说道拖动事件是两个元素的互动,但是仅仅使用事件是不够的,我们需要其他的手段在两个元素之间传递信息

dragstart事件触发的时候所提供的event对象中含有一个DataTransfer对象,这个对象允许在多个事件中保存信息且在所有拖动事件中存在

简单信息传递操作:

被拖动元素调用该对象的setData()方法设置值

容器元素在drop事件中使用event对象的DataTransfer属性的getData()方法获取在dragstart事件中设置的值

例子:

let dargElem = document.getElementById("test");
let targetElem = document.getElementById("display");

dargElem.addEventListener("dragstart", (event) => {

    event.dataTransfer.setData("test",[1,2,3]);
})

// 必须设置
targetElem.addEventListener("dragover", (event) => {
    event.preventDefault();
})

// 拖动事件
targetElem.addEventListener("drop", (event) => {

    event.preventDefault();
    console.log(event.dataTransfer.getData("test"));
})

可以看到DataTransfer数据的设置就是典型的键值操作而已

综合实例一个来自MDN的例子:

html

This div is draggable

css

#draggable {
width: 200px;
height: 20px;
text-align: center;
background: white;
}

.dropzone {
width: 200px;
height: 20px;
background: blueviolet;
margin-bottom: 10px;
padding: 10px;
}

javascript

var dragged;

/* 可拖动的目标元素会触发事件 */
document.addEventListener("drag", function( event ) {

}, false);

document.addEventListener("dragstart", function( event ) {
  // 保存拖动元素的引用(ref.)
  dragged = event.target;
  // 使其半透明
  event.target.style.opacity = .5;
}, false);

document.addEventListener("dragend", function( event ) {
  // 重置透明度
  event.target.style.opacity = "";
}, false);

/* 放下目标节点时触发事件 */
document.addEventListener("dragover", function( event ) {
  // 阻止默认动作
  event.preventDefault();
}, false);

document.addEventListener("dragenter", function( event ) {
  // 当可拖动的元素进入可放置的目标高亮目标节点
  if ( event.target.className == "dropzone" ) {
      event.target.style.background = "purple";
  }

}, false);

document.addEventListener("dragleave", function( event ) {
  // 当拖动元素离开可放置目标节点,重置其背景
  if ( event.target.className == "dropzone" ) {
      event.target.style.background = "";
  }

}, false);

document.addEventListener("drop", function( event ) {
  // 阻止默认动作(如打开一些元素的链接)
  event.preventDefault();
  // 移动拖动的元素到所选择的放置目标节点
  if ( event.target.className == "dropzone" ) {
      event.target.style.background = "";
      dragged.parentNode.removeChild( dragged );
      event.target.appendChild( dragged );
  }

}, false);
DataTransfer详解

DataTransfer不仅仅用于元素之间信息的传递,同时可以控制拖动的样式,以及传递额外的信息

属性:

dropEffect 类型 String

effectAllowed 类型 String

files 类型 FileList

types 类型 DOMStringList

方法:

void addElement(in Element element)

void clearData([in String type])

String getData(in String type)

void setData(in String type, in String data)

void setDragImage(in nsIDOMElement image, in long x, in long y)

这里只讲解一下dropEffecteffectAllowed因为这里有坑files属性用于从浏览器外部拖入文件时候使用types使用较少这里不提了

提供MDN链接,看完本文后可以查阅剩下的方法和属性:

https://developer.mozilla.org...

dropEffecteffectAllowed用于控制拖动的时候光标角标的样式,过滤不同的类型拖动行为

dropEffect可能的值:

copy: 复制到新的位置

move: 移动到新的位置.

link: 建立一个源位置到新位置的链接.

none: 禁止放置(禁止任何操作).

effectAllowed可能的值:

copy: 复制到新的位置.

move:移动到新的位置 .

link:建立一个源位置到新位置的链接.

copyLink: 允许复制或者链接.

copyMove: 允许复制或者移动.

linkMove: 允许链接或者移动.

all: 允许所有的操作.

none: 禁止所有操作.

uninitialized: 缺省值(默认值), 相当于 all.

简单来说在被拖动元素的事件中设置effectAllowed属性表示期待的拖动样式,而在容器元素中设置dropEffect表示容器指定的样式,其他的设置都会被忽视

对于dropEffect只有在dragover事件中中修改值才会影响样式,我用的是Chrome66

对于effectAllowed只有在dragstart事件中有效

例子双方都使用link样式:

let dargElem = document.getElementById("test");
let targetElem = document.getElementById("display");

// 拖动开始事件
dargElem.addEventListener("dragstart", (event) => {
    event.dataTransfer.effectAllowed = "link";
})

// 悬浮到容器上方的事件
targetElem.addEventListener("dragover", (event) => {
    event.dataTransfer.dropEffect = "link";
    event.preventDefault();
})

// 拖动事件
targetElem.addEventListener("drop", (event) => {
    console.log("pass")
    event.preventDefault();
})

这个例子中drop事件被触发

例子effectAllowed设置为copydropEffect设置为link:

let dargElem = document.getElementById("test");
let targetElem = document.getElementById("display");

// 拖动开始事件
dargElem.addEventListener("dragstart", (event) => {
    event.dataTransfer.effectAllowed = "link";
})

// 悬浮到容器上方的事件
targetElem.addEventListener("dragover", (event) => {
    event.dataTransfer.dropEffect = "link";
    event.preventDefault();
})

// 拖动事件
targetElem.addEventListener("drop", (event) => {
    console.log("pass")
    event.preventDefault();
})

这个例子执行的结果就是拖动时候的角标一直是禁止符号,在容器元素上松开也不会触发drop事件

参考链接
https://developer.mozilla.org...

https://developer.mozilla.org...

https://blog.csdn.net/baidu_3...

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/96738.html

相关文章

  • FileSystem -- 文件夹拖动上传

    摘要:回调函数回调函数文件夹拖动拦截默认行为,并阻止冒泡文件夹拖动或者文件拖动,浏览器默认会直接打开显示,图片尤为明显,所以首先需要阻止默认行为。 前言 文件拖动上传,对于个别应用场景十分有效,实现起来也并不难。参见 浏览器图片预览 --http://blog.segmentfault.com/bornkiller/1190000000428572。 现在更进一步,做到文件夹拖动。Fils...

    Freeman 评论0 收藏0
  • 什么是 HTML 5?

    摘要:该区域代表可以被所控制的画布。那么现在第二个问题,识别该文档,这或许不是大部分用户的需求,但小部分用户并不意味着人数少。因此一个基于的请求于标准内提出。 前言 作为程序员,技术的落实与巩固是必要的,因此想到写个系列,名为 why what or how 每篇文章试图解释清楚一个问题。 这次的 why what or how 主题:现在几乎所有人都知道了 HTML5 ,那么 H5 到底相...

    zhaofeihao 评论0 收藏0

发表评论

0条评论

VioletJack

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<