该文章于2020/8/21改,主要针对 重学前端第一阶段完 钢琴项目(document.querySelector js改变css样式的3种方式 思路 成品) 的拖动的解析!
一、将 HTML5 元素定义为块元素
HTML5 定了 8 个新的 HTML 语义(semantic) 元素。所有这些元素都是 块级 元素。
为了能让旧版本的浏览器正确显示这些元素,你可以设置 CSS 的 display 属性值为 block:
实例:
header, section, footer, aside, nav, main, article, figure {
display: block;
}
二、为 HTML 添加新元素
你可以为 HTML 添加新的元素。
该实例向 HTML 添加的新的元素,并为该元素定义样式,元素名为 < myHero> :
实例:
DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>为 HTML 添加新元素title>
<script> //为IE添加新的元素,其它浏览器可不用。Internet Explorer 8 及更早 IE 版本的浏览器不支持该方式。
document.createElement("myHero")
script>
<style>
myHero {
display: block;
background-color: #ddd;
padding: 50px;
font-size: 30px;
}
style>
head>
<body>
<h1>我的第一个标题h1>
<p>我的第一个段落。p>
<myHero>我的第一个新元素myHero>
body>
html>
拖放是一种常见的特性,即抓取对象以后拖到另一个位置,在 HTML5 中,拖放是标准的一部分,任何元素都能够拖放。
实例:
DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>菜鸟教程(runoob.com)title>
<style type="text/css">
#div1 {width:350px;height:70px;padding:10px;border:1px solid #aaaaaa;}
style>
<script>
function allowDrop(ev)
{
ev.preventDefault();
}
function drag(ev)
{
ev.dataTransfer.setData("Text",ev.target.id);
}
function drop(ev)
{
ev.preventDefault();
var data=ev.dataTransfer.getData("Text");
ev.target.appendChild(document.getElementById(data));
}
script>
head>
<body>
<p>拖动 RUNOOB.COM 图片到矩形框中:p>
<div id="div1" ondrop="drop(event)" ondragover="allowDrop(event)">div>
<br>
<img id="drag1" src="/images/logo.png" ondragstart="drag(event)" width="336" height="69">
body>
html>
接下来就将整个拖放,分成一小块一小块的来讲解:
首先,为了使元素可拖动,把 draggable 属性设置为 true :
<img draggable="true"> //draggable可省略
draggable 属性规定元素是否可拖动。
提示:
规定当元素被拖动时,会发生什么?
dataTransfer.setData() 方法设置被拖数据的数据类型和值:
function drag(ev)
{
ev.dataTransfer.setData("Text",ev.target.id);
}
Text 是一个 DOMString 表示要添加到 drag object 的拖动数据的类型,值是可拖动元素的 id (“drag1”)。
DataTransfer.setData() 方法用来设置拖放操作的 内容 到指定的数据和类型。
如果给定类型的数据不存在,则将其添加到拖动数据存储的末尾,使得 类型列表(types 列表) 中的最后一个项目将是新类型。
如果给定类型的数据已经存在,现有数据将被替换为相同的位置,也就是说,替换相同类型的数据时 类型列表(types 列表) 的顺序不会更改。
format:
一个 DOMString 表示要添加到 drag object的拖动数据的类型。
data:
一个 DOMString表示要添加到 drag object的数据。
target 事件属性可返回事件的目标节点(触发该事件的节点),如生成事件的元素、文档或窗口。
在处理拖放操作时,我们需要用到 DataTransfer 对象来保存被拖动的数据, DataTransfer 可以保存一项或多项数据、一种或者多种数据类型。
属性:
方法:
(好多天来,总算学习了,不想放手,可是得去洗了,呜呜呜,明明可以写得更好,算了,明天再来!!!(ㄒoㄒ)~~)
ondragstart 事件在用户开始拖动元素或选择的文本时触发。在上面的例子中,ondragstart 属性调用了一个函数drag(event),它规定了被拖动的数据。
在拖放的过程中会触发以下事件:
一、在拖动目标上触发事件 (源元素):
二、释放目标时触发的事件:
当一个对象处于拖动时,其绑定在window上,而非父元素上,通过console.log(this); 可以看出
实例:function ondragstart(event){ console.log(this); event.dataTransfer.setData("Text", event.target.id); }
打印出来的结果就是widow!
ondragover 事件规定在何处放置被拖动的数据,默认地,无法将 数据/元素 放置到其他元素中,如果需要设置允许放置,我们必须阻止对元素的默认处理方式。
这要通过调用 event.preventDefault() 方法。
如果事件可以被取消,就取消事件(即取消事件的预设行为),但不会影响事件的传递,事件仍会继续传递。
这里Firefox会产生依旧打开新标签,但没有东西的bug,需要加上ev.stopPropagation(); (在我的 成品 里可以看见)
当放置被拖数据时,会发生 ondrop 事件。
在上面的例子中,ondrop 属性调用了一个函数,drop(event):
function drop(ev)
{
ev.preventDefault();
var data=ev.dataTransfer.getData("Text");
ev.target.appendChild(document.getElementById(data));
}
代码解释:
调用 preventDefault() 来避免浏览器对数据的默认处理(drop 事件的默认行为是以链接形式打开)
通过 dataTransfer.getData(“Text”) 方法获得被拖的数据,该方法将返回在 setData() 方法中设置为相同类型的任何数据。
被拖数据是被拖元素的 id (“drag1”)
把被拖元素追加到放置元素(目标元素)中
注意:
在追加元素的的时候,经常会报错:Uncaught TypeError: Failed to execute ‘appendChild’ on ‘Node’: parameter 1 is not of type ‘Node’
这其实是一个很好解决的问题,其实就是 appendChild()需要传入的是一个dom的对象,而不是dom的字符串,这里菜鸟试了一下,通过 document.xxxxx 得到的都是对象!(如果有误,望读者指出)
注意:
这里使用 ev.target 会产生看不懂的情况,就是拖动多个进同一个容器,结果不会出现上面如下的情况:
如果给定类型的数据不存在,则将其添加到拖动数据存储的末尾,使得 类型列表(types 列表) 中的最后一个项目将是新类型。
如果给定类型的数据已经存在,现有数据将被替换为相同的位置,也就是说,替换相同类型的数据时 类型列表(types 列表) 的顺序不会更改。
这是为什么呢?
因为 ev.target 会把先移入的img,当作目标节点,所以把再次移入的内容加入到img里面,而不是其父元素中;当然如果父元素比较大,你没有移动到先移入的元素上,也不会产生bug。
这里最好的解决办法就是将ondrop事件绑定到元素上,eg:οndrοp=“drop(event,this)” ,然后js就可以直接
function drop(ev,element) {
ev.preventDefault();
ev.stopPropagation();
// 阻止浏览器对拖动的默认处理,但是firefox有点小bug
// 加上ev.stopPropagation();已解决firefox的bug
var data = ev.dataTransfer.getData("Text");
element.appendChild(document.getElementById(data));
}