深入理解javascript原生拖放
前面的话
拖放(drag-and-drop,DnD)其实是两个动作——拖和放。所以,它涉及到两个元素。一个是被拖的元素,称为拖放源;另一个是要放的目标,称为拖放目标。本文将通过拆分这两个概念来详细介绍原生拖放
拖放源
什么样的元素才是拖放源呢?
HTML5为所有HTML元素规定了一个draggable属性,表示元素是否可以拖动
图像和链接的draggable属性自动被设置成了true,而其他元素这个属性的默认值都是false
[注意]必须设置draggable='true'才能生效,只设置draggable不起作用
默认情况下,文本只有在被选中的情况下才能拖动,而图像和链接在任何时候都可以拖动。而其他元素则无法被拖放
<input value="文字可拖动"> <img alt="图像可拖动" src="http://files.cnblogs.com/files/xiaohuochai/zan.gif"> <a href="#">链接可拖动</a> <div id="test" style="height:30px;width:300px;background:pink;">元素不可拖动</div>
当为元素设置draggable属性后,普通元素也可以拖动
<div draggable="true" style="height:30px;width:100px;background:pink;"></div>
兼容
IE9-浏览器不支持draggable属性,但可通过mousedown事件处理程序调用dragDrop()方法来实现拖动效果
<div id="test" style="height:30px;width:300px;background:pink;"></div> <script> test.onmousedown = function(){this.dragDrop(); } </script>
[注意]如果让firefox支持draggable属性,必须添加一个ondragstart事件处理程序,并在dataTransfer对象使用setData()方法来启动效果
拖放事件
拖放源涉及到3个拖放事件。拖动拖放源时,依次触发dragstart、drag和dragend这3个事件
dragstart
按下鼠标键并开始移动鼠标时,会在被拖放的元素上触发dragstart事件。此时光标变成“不能放”符号(圆环中有一条反斜线),表示不能把元素放到自己上面
drag
触发dragstart事件后,随即会触发drag事件,而且在元素被拖动期间会持续触发该事件
dragend
当拖动停止时(无论是把元素放到了有效的放置目标,还是放到了无效的放置目标上),会触发dragend事件
<div id="test" draggable="true" style="height:30px;width:100px;background:pink;">0</div> <script> var timer,i=0; test.ondragstart = function(){this.style.backgroundColor = 'lightgreen'; } test.ondrag = function(){if(timer) return;timer = setInterval(function(){test.innerHTML = i++;},100) } test.ondragend = function(){clearInterval(timer);timer = 0;this.style.backgroundColor = 'pink'; } </script>
拖放目标
拖放目标是指被拖动的元素松开鼠标时被放置的目标
拖放源被拖动到拖放目标上时,将依次触发dragenter、dragover和dragleave或drop这四个事件
dragenter
只要有元素被拖动到放置目标上,触发dragenter事件
dragover
被拖动的元素在放置目标的范围内移动时,持续触发dragover事件
dragleave
如果元素被拖出了放置目标,触发dragleave事件
drop
如果元素被放到了放置目标中,触发drop事件
[注意]firefox浏览器的drop事件的默认行为是打开被放到放置目标上的URL。为了让firefox支持正常的拖放,还要取消drop事件的默认行为
默认情况下,目标元素是不允许被放置的,所以不会发生drop事件。只要在dragover和dragenter事件中阻止默认行为,才能成为被允许的放置目标,才能允许发生drop事件。此时,光标变成了允许放置的符号
<div id="test" draggable="true" style="height:30px;width:130px;background:pink;float:left;">拖放源</div> <div id="target" style="float:right;height: 200px;width:200px;background:lightblue;">拖放目标</div> <script> var timer,i=0; var timer1,i1=0; //兼容IE8-浏览器 test.onmousedown = function(){if(this.dragDrop){this.dragDrop();} } test.ondragstart = function(){this.style.backgroundColor = 'lightgreen';this.innerHTML = '开始拖动'; } test.ondrag = function(){if(timer) return;timer = setInterval(function(){test.innerHTML = '元素已被拖动' + ++i + '秒';},1000); } test.ondragend = function(){clearInterval(timer);timer = 0;i =0;this.innerHTML = '结束拖动';this.style.backgroundColor = 'pink'; } target.ondragenter = function(e){e = e || event;if(e.preventDefault){e.preventDefault();}else{e.returnValue = false;}this.innerHTML = '有元素进入目标区域';this.style.background = 'red'; } target.ondragover = function(e){e = e || event;if(e.preventDefault){e.preventDefault();}else{e.returnValue = false;}if(timer1) return;timer1 = setInterval(function(){target.innerHTML = '元素已进入' + (++i1) + '秒';},1000); } target.ondragleave = function(){clearInterval(timer1);timer1 = 0;i1=0;this.innerHTML = '元素已离开目标区域';this.style.backgroundColor = 'lightblue'; } target.ondrop = function(){clearInterval(timer1);timer1 = 0;i1=0;this.innerHTML = '元素已落在目标区域';this.style.backgroundColor = 'orange'; } </script>
dataTransfer对象
为了在拖放操作时实现数据交换,引入了dataTransfer对象,它是事件对象的一个属性,用于从被拖动元素向放置目标传递字符串格式的数据
dataTransfer对象有两个主要方法:getData()和setData()
getData()可以取得由setData()保存的值。setData()方法的第一个参数,也是getData()方法唯一的一个参数,是一个字符串,表示保存的数据类型,取值为"text"或"URL"
IE只定义了"text"和"URL"两种有效的数据类型,而HTML5则对此加以扩展,允许指定各种MIME类型。考虑到向后兼容,HTML5也支持"text"和"URL",但这两种类型会被映射为"text/plain"和"text/uri-list"
实际上,dataTransfer对象可以为每种MIME类型都保存一个值。换句话说,同时在这个对象中保存一段文本和一个URL不会有任何问题
[注意]保存在dataTransfer对象中的数据只能在drop事件处理程序中读取
在拖动文本框中的文本时,浏览器会调用setData()方法,将拖动的文本以"text"格式保存在dataTransfer对象中。类似地,在拖放链接或图像时,会调用setData()方法并保存URL。然后,在这些元素被拖放到放置目标时,就可以通过getData()读到这些数据
<div>请将从这行文字中挑选一些移动到拖放目标中</div> <div id="target" style="margin-top:20px;height: 100px;width:200px;background:lightblue;">拖放目标</div> <div id="result"></div> <script> target.ondragenter = function(e){e = e || event;if(e.preventDefault){e.preventDefault();}else{e.returnValue = false;}this.innerHTML = '有元素进入目标区域';this.style.background = 'red'; } target.ondragover = function(e){e = e || event;if(e.preventDefault){e.preventDefault();}else{e.returnValue = false;} } target.ondragleave = function(e){e = e || event; this.innerHTML = '元素已离开目标区域';this.style.backgroundColor = 'lightblue'; } target.ondrop = function(e){e = e || event;if(e.preventDefault){e.preventDefault();}else{e.returnValue = false;}result.innerHTML = '落入目标区域的文字为:' + e.dataTransfer.getData('text');this.innerHTML = '元素已落在目标区域';this.style.backgroundColor = 'orange'; } </script>
当然,也可以在dragstart事件处理程序中调用setData(),手动保存自己要传输的数据,以便将来使用
<div id="test" draggable="true" data-value="这是一个秘密" style="height:30px;width:100px;background:pink;">拖动源</div> <div id="target" style="margin-top:20px;height: 100px;width:200px;background:lightblue;">拖放目标</div> <div id="result"></div> <script>//兼容IE8-浏览器 test.onmousedown = function(){if(this.dragDrop){this.dragDrop();} } test.ondragstart = function(e){e = e || event;e.dataTransfer.setData('text',test.getAttribute('data-value')); } target.ondragenter = function(e){e = e || event;if(e.preventDefault){e.preventDefault();}else{e.returnValue = false;}this.innerHTML = '有元素进入目标区域';this.style.background = 'red'; } target.ondragover = function(e){e = e || event;if(e.preventDefault){e.preventDefault();}else{e.returnValue = false;} } target.ondragleave = function(e){e = e || event; this.innerHTML = '元素已离开目标区域';this.style.backgroundColor = 'lightblue'; } target.ondrop = function(e){e = e || event;if(e.preventDefault){e.preventDefault();}else{e.returnValue = false;}result.innerHTML = '落入目标区域的文字为:' + e.dataTransfer.getData('text');this.innerHTML = '元素已落在目标区域';this.style.backgroundColor = 'orange'; } </script>
改变光标
利用dataTransfer对象,不仅可以传输数据,还能通过它来确定被拖动的元素以及作为放罝目标的元素能够接收什么操作。为此,需要访问dataTransfer对象的两个属性:dropEffect和effectAllowed
实际上,这两个属性并没有什么用,只是拖动源在拖动目标上移动时,改变不同的光标而已(但是,有一种情况除外)
dropEffect
dropEffect属性可以知道被拖动的元素能够执行哪种放置行为。这个属性有下列4个可能的值
"none":不能把拖动的元素放在这里。这是除文本框之外所有元素的默认值(此时,将无法触发drop事件)
"move":应该把拖动的元素移动到放置目标
"copy":应该把拖动的元素复制到放置目标
"link":表示放置目标会打开拖动的元素(但拖动的元素必须是一个链接,有URL)
在把元素拖动到放置目标上时,以上每一个值都会导致光标显示为不同的符号
[注意]必须在ondragover事件处理程序中针对放置目标来设置dropEffect属性
effectAllowed
dropEffect属性只有搭配effectAllowed属性才有用。effectAllowed属性表示允许拖动元素的哪种dropEffect
effectAllowed属性可能的值如下
"uninitialized":没有给被拖动的元素设置任何放置行为
"none":被拖动的元素不能有任何行为
"copy":只允许值为"copy"的dropEffect
"link"只允许值为"link"的dropEffect
"move":只允许值为"move"的dropEffect
"copyLink":允许值为"copy"和"link"的dropEffect
"copyMove":允许值为"copy"和"move"的dropEffect
"linkMove":允许值为"link"和"move"的dropEffect
"all":允许任意dropEffect
[注意]必须在ondragstart事件处理程序中设置effectAllowed属性
<div id="test" draggable="true" style="height:30px;width:100px;background:pink;display:inline-block;">拖放源</div> <br> <div id="target1" style="margin-top:20px;height: 100px;width:150px;background:lightblue;display:inline-block;">(none)拖放目标</div> <div id="target2" style="margin-top:20px;height: 100px;width:150px;background:lightblue;display:inline-block;">(move)拖放目标</div> <div id="target3" style="margin-top:20px;height: 100px;width:150px;background:lightblue;display:inline-block;">(copy)拖放目标</div> <div id="target4" style="margin-top:20px;height: 100px;width:150px;background:lightblue;display:inline-block;">(link)拖放目标</div> <div id="result"></div> <script> //兼容IE8-浏览器 test.onmousedown =function(){if(this.dragDrop){this.dragDrop();} } test.ondragstart = function(e){e = e || event;//兼容firefox浏览器 e.dataTransfer.setData('text','');e.dataTransfer.effectAllowed = 'all'; } target1.ondragenter = target2.ondragenter =target3.ondragenter =target4.ondragenter =function(e){e = e || event;if(e.preventDefault){e.preventDefault();}else{e.returnValue = false;}this.style.background = 'red'; } target1.ondragover = function(e){e = e || event;if(e.preventDefault){e.preventDefault();}else{e.returnValue = false;}e.dataTransfer.dropEffect = 'none'; } target2.ondragover = function(e){e = e || event;if(e.preventDefault){e.preventDefault();}else{e.returnValue = false;}e.dataTransfer.dropEffect = 'move'; } target3.ondragover = function(e){e = e || event;if(e.preventDefault){e.preventDefault();}else{e.returnValue = false;}e.dataTransfer.dropEffect = 'copy'; } target4.ondragover = function(e){e = e || event;if(e.preventDefault){e.preventDefault();}else{e.returnValue = false;}e.dataTransfer.dropEffect = 'link'; } target1.ondragleave = target2.ondragleave =target3.ondragleave =target4.ondragleave =function(e){e = e || event; this.style.backgroundColor = 'lightblue'; } target1.ondrop = target2.ondrop =target3.ondrop =target4.ondrop =function(e){e = e || event;if(e.preventDefault){e.preventDefault();}else{e.returnValue = false;}this.style.backgroundColor = 'orange'; } </script>
深入理解javascript原生拖放相关推荐
- 深入理解JavaScript系列(5):强大的原型和原型链
前言 JavaScript 不包含传统的类继承模型,而是使用 prototypal 原型模型. 虽然这经常被当作是 JavaScript 的缺点被提及,其实基于原型的继承模型比传统的类继承还要强大.实 ...
- 深入理解JavaScript系列:根本没有“JSON对象”这回事!
前言 写这篇文章的目的是经常看到开发人员说:把字符串转化为JSON对象,把JSON对象转化成字符串等类似的话题,所以把之前收藏的一篇老外的文章整理翻译了一下,供大家讨论,如有错误,请大家指出,多谢. ...
- JavaScript原生实现《贪吃蛇》
概述 JavaScript原生实现<贪吃蛇>,每吃掉一个食物,蛇的身体会变长,食物会重新换位置. 详细 代码下载:http://www.demodashi.com/demo/10728.h ...
- javascript原生初级到非凡-姜威-专题视频课程
javascript原生初级到非凡-248人已学习 课程介绍 本套课程是<初级的前端工程师系列课程>中重要的一部课程,课程需要有HTML5+CSS3基础来学习,课程从初级入 ...
- vue 加载页面时触发时间_5.6 vue更新数组时触发视图更新的方法,熟记JavaScript原生方法...
问题:vue更新数组时触发视图更新的方法 变异方法: Vue 包含一组观察数组的变异方法,所以它们也将会触发视图更新.什么是变异方法呢?简单理解就是改变了原来的数组,可能包括数组长度length,或者 ...
- 视频教程-javascript原生初级到非凡-JavaScript
javascript原生初级到非凡 全栈工程师.2000年建设第一网站项目起,15年行业经验,从早期WAP到APP,从SP.IVR到流媒体,云框架: 项目解决顾问. 姜威 ¥49.00 立即订阅 扫码 ...
- 全方位深入理解JavaScript面向对象
JavaScript面向对象程序设计 本文会碰到的知识点: 原型.原型链.函数对象.普通对象.继承 读完本文,可以学到 面向对象的基本概念 JavaScript对象属性 理解JavaScript中的函 ...
- 理解JavaScript中部分设计模式
理解JavaScript中部分设计模式 什么是设计模式 在软件工程中,设计模式是软件设计中常见问题可重用的方案.设计模式代表着经验丰富的软件开发人员使用的最佳实践.设计模式可以被认为是编程模板. 为什 ...
- 深入理解javascript函数系列第二篇——函数参数
前面的话 javascript函数的参数与大多数其他语言的函数的参数有所不同.函数不介意传递进来多少个参数,也不在乎传进来的参数是什么数据类型,甚至可以不传参数.本文是深入理解javascript函数 ...
最新文章
- CSDN写作Markdown编辑器中的Python命令帮手
- 手机扫一扫,现实物体隔空「复制粘贴」进电脑!北大校友的AI新研究,现在变成AR酷炫应用...
- 两个奇技淫巧,将 Docker 镜像体积减小 99%
- Java NIO之Channel(通道)
- 机器为什么可以学习(2)---一般化理论
- Transformers中的Beam Search高效实现
- BIM平台 http://gzcd.bim001.cn
- Windows控制台cmd默认代码页修改的办法【GBK、UTF-8】
- y7000p屏幕亮度低_联想拯救者y7000p怎么样 评测结果揭晓屏幕优点
- 0712CF解题报告
- 为什么我玩游戏那么卡?
- 人工智能的最新进展:比失业更严重?
- vue 使用 :class 根据不同状态值设置状态文字颜色不同
- 2023临沂大学计算机考研信息汇总
- 「Ubuntu」ubuntu18.04键盘输入卡顿、延迟输入
- matlab验证线性卷积与圆周卷积的关系
- Defensive Programming 防御式编程(Defensive Programming)
- 重新开始学Java——集合框架之Collection
- 伙伴分配器的内核实现
- 学习笔记20220513
热门文章
- 办公室计算机技巧知识,办公室电脑常用技巧有哪些【详解】
- 华南理工统考计算机应用基础,华南理工大学计算机应用基础平时作业
- (二十九)arcpy开发利用arcpy在arcgis中实现批量计算图斑四至坐标(polygon顶点计算,范围获取、pyhon类创建)
- Web打印组件jatoolsPrinter
- 51单片机的轮胎气压监测系统_汽车轮胎压力监测系统
- 门禁布线系统常见错误详解
- 2016总结与2017展望
- 旅行世界显示服务器繁忙,旅行世界,玩法介绍!无充值入口,每日遛狗赚
- 基于捕捉漂移布谷鸟搜索算法的函数寻优算法
- jav.moo_Moo 1.2即将发布…