在前端web页面中,为了提高用户体验,通常会希望将页面中的元素设计成可dragdop的,简化用户操作。这一设计特性在缺少鼠标的触摸屏设备上,显得更为重要。

在早期的应用中,我们通常需要借助第三方的javascript库(Jquery插件等)。在HTML5已经将这一特性引入,提供原生的支持,不用再借助第三方的javascript库。现代化的程序设计中,各种前端库的引入(Jquery, nodejs, ract, angularjs),提高了开发效率,而各自的库也有相应的插件来处理dragdrop,使得开发更为便捷。那HTML5原生的支持,到底是怎么样的?

关键就在DOM元素的 draggable 属性,如果是 draggable = “true” ,表示该元素可被拖拽。 draggable = “false” 或其它值则不可拖拽。

看一个例子:

本样例以table形式呈现,本质是div+css布局(从业务的角度,每一个是一个业务单位,而非单独的列。但只有test item列中的元素是可拖拽的)。每一行作为一个业务单元,但只有test item所在列的元素可拖拽。当其被拖拽到其它其它行的时候,以行为单位进行整体交换。

看一下行的元素布局

 <div id="div0" class="containerDiv" ondrop="drop(event)" data-dropable="true" ondragover="dragOver(event)" data-dropEl='drag0' >
<span class="headerCellStyle"> 1</span>
<span id="drag0" ondragstart="drag(event)" data-dragable="true" data-dropElHost='div0' data-sequence='1361' data-key='1361' data-orginalSequence='1361'>
<span style="width:4.3vw;" class="bodyCellStyle" >100</span>
<span style="width:8.9vw;" class="bodyCellStyle" >Rake</span>
<span id="testitem0" style="vertical-align:middle; display:inline-block;width:21vw;overflow:hidden;white-space:nowrap" class=" dropElCSS" onmouseover="OnMouseEnterEvent(event)" onmouseout="OnMouseLeaveEvent(event)">Max_Load_Clamp </span>
<span style="display:inline-block; width:8.9vw;border-left:0.1vw solid #aaaaaa;border-right:0px;padding:0.2vw 0.2vw;white-space:nowrap" >2016-09-25 11:07:39</span>
</span>
</div>

可拖拽DOM元素 id="testitem0" 需要特别注意,以testitem作为前缀,在拖拽判断的时候会使用到:

 if(targetContainer.id.indexOf("testitem")>=0) {
targetContainer = ev.target.parentNode || ev.target.parentElement;
targetContainer = targetContainer.parentNode || targetContainer.parentElement;
}

因为span的限制,drapdrop的属性会冒泡到第一个block元素上,影响到parent容器DIV,形成拖拽错乱:drag的元素被pending到drop的容器中,本应该是需要交换的两个元素被合并到一个DIV容器中。通过设定鼠标进入离开事件onmouseover="OnMouseEnterEvent(event)" onmouseout="OnMouseLeaveEvent(event)" ,设定属性dragdrop为true或者false.

 function SetItemDragable(dragable, dragEl){
var gloableStatus = true;
if(dragEl)
dragEl.setAttribute("draggable", gloableStatus&&dragable);
} function OnMouseEnterEvent(ev){
var elID = ev.target.id;
var parentEl = ev.target.parentNode || ev.target.parentElement;
if(parentEl) SetItemDragable(true, parentEl);
} function OnMouseLeaveEvent(ev){
var elID = ev.target.id;
var parentEl = ev.target.parentNode || ev.target.parentElement;
if(parentEl) SetItemDragable(false, parentEl);
}

MouseEvent

你会注意到在dragdrop元素的parent元素上,会有 data- 开头的这种自定义属性:

data-dragable="true" data-dropElHost='div0' data-sequence='1361' data-key='1361' data-orginalSequence='1361'

这些属性是被用来存储业务数据或其它自定义用途的数据。其中,最重要的data-dropElHost指向级元素的DOM(拖拽最终的效果中的整体元素)。 data-dragable="true" 标记该元素从业务角度是否可拖拽,有别于HTML5的自定义属性 dragdrop = "true/false" ,它们唯一的区别就是业务上和技术角度是否可拖拽。

页面上的Save按钮,点击后显示拖拽后变动的元素,将 data-key, data-sequence 中的值作为一个二元组(data-key, data-sequence)表示一个元素的最终值,以字符‘;’作为多个元素值的分隔符。

完整的javascript代码为:

 function dragOver(ev) {
ev.preventDefault(); } function drag(ev) {
if(ev.target.getAttribute("data-dragable")!="true") return;
ev.dataTransfer.setData("text", ev.target.id);
} function drop(ev) {
ev.preventDefault();
var targetContainer = ev.target; if(targetContainer.id.indexOf("testitem")>=0) {
targetContainer = ev.target.parentNode || ev.target.parentElement;
targetContainer = targetContainer.parentNode || targetContainer.parentElement;
} if(targetContainer.getAttribute("data-dropable")!="true") return; var data = ev.dataTransfer.getData("text");
var dropEl = document.getElementById(data);
targetContainer.appendChild(dropEl); var dropElHost = document.getElementById(dropEl.getAttribute("data-dropElHost"));
var hostOrginalEl = document.getElementById(targetContainer.getAttribute("data-dropEl"));
targetContainer.removeChild(hostOrginalEl);
dropElHost.appendChild(hostOrginalEl); //swap host id of each element
hostOrginalEl.setAttribute("data-dropElHost", dropEl.getAttribute("data-dropElHost"));
dropEl.setAttribute("data-dropElHost", targetContainer.id); //swap drop element id of its container div
targetContainer.setAttribute("data-dropEl", data);
dropElHost.setAttribute("data-dropEl", hostOrginalEl.id); //swap sequence of drop element
var hostOrginalElSequence = hostOrginalEl.getAttribute("data-sequence");
hostOrginalEl.setAttribute("data-sequence", dropEl.getAttribute("data-sequence"));
dropEl.setAttribute("data-sequence", hostOrginalElSequence); SetSaveBtnStatus(true); } function ShowSequence() {
var idPrefix = "drag";
var result = ""; var data="";
var dragElementLength = 504; //there're not so many elements now.
for (var i = 0; i < dragElementLength; i++) {
var id = idPrefix + i;
var el = document.getElementById(id);
if(el==null) continue;
var currentSequence = el.getAttribute("data-sequence");
var orginalSequence = el.getAttribute("data-orginalSequence"); if(currentSequence == orginalSequence) continue; data += "("+el.getAttribute("data-key") +"," +currentSequence+")";
} if(data.length==0){
MessageBox("ERROR: There's no item for order change!");
return;
} document.getElementById("resultInput").value = escape( data); //document.getElementById("form1").submit();
document.getElementById("resultDiv").innerHTML = "The updated items are(data-key, data-sequence):" + data;
} function SetSaveBtnStatus(activity){
document.getElementById("saveBtn").disabled = !activity;
} function SetItemDragable(dragable, dragEl){
var gloableStatus = true;
if(dragEl)
dragEl.setAttribute("draggable", gloableStatus&&dragable);
} function OnMouseEnterEvent(ev){
var elID = ev.target.id;
var parentEl = ev.target.parentNode || ev.target.parentElement;
if(parentEl) SetItemDragable(true, parentEl);
} function OnMouseLeaveEvent(ev){
var elID = ev.target.id;
var parentEl = ev.target.parentNode || ev.target.parentElement;
if(parentEl) SetItemDragable(false, parentEl);
}

JavaScript

样式表为:

 .containerDiv {min-width:350px;width:auto;border:0.1vw solid #aaaaaa;float:none;border-top:0px;}
.dateTip{font-style:italic;}
.userManual{min-width:350px;width:auto;/*border:0.1vw solid #aaaaaa;*/}
.headerCellStyle{font-weight:bold;width:3vw;display:inline-block;margin-left:0.4vw;padding:0.2vw 0px;border-right:0.1vw solid #aaaaaa;white-space:nowrap;}
.bodyCellStyle{display:inline-block;margin-left:0.4vw;padding:0.2vw 0px;border-right:0.1vw solid #aaaaaa;white-space:nowrap;}
.dropElCSS { width:90%; cursor: pointer;border-radius: 1vw;background-color:white; box-shadow: 0.1vw 0.3vw 0.3px #888888;border:0px dashed black ; }

CSS

附上完整的DEMO

HTML DOM元素的Dragdrop的更多相关文章

  1. jQuery操作DOM元素

    作为一个后端程序员,也是要和前端页面打交道的.最常见的场景莫过DOM元素操作和前端页面使用AJAX向服务器发送请求.实现上述两个功能当然可以使用原生js来完成,但在实际开发过程中很少这样做,通常会使用 ...

  2. JQuery利用sort对DOM元素进行排序

    前言 排序对于我们是再熟悉不过了,在绝大数应用程序中都会有这样一个场景:当我们从服务器端获取一个列表时,在界面上进行渲染,我们可以会依赖于某一个规则来进行排序,当然此时绝大多数会再次与服务器进行交互来 ...

  3. html标签属性(attribute)和dom元素的属性(property)

    简介 attribute和property都有属性之意,但对于attribute和property的区分其实并不难.从对象来说,attribute是html文档上标签属性, 而property则是对应 ...

  4. jQuery操纵DOM元素属性 attr()和removeAtrr()方法使用详解

    jQuery操纵DOM元素属性 attr()和removeAtrr()方法使用详解 jQuery中操纵元素属性的方法: attr(): 读或者写匹配元素的属性值. removeAttr(): 从匹配的 ...

  5. 如何隐藏DOM元素

    在CSS中,要隐藏DOM元素常见的方法有: 设置元素的opacity值为0 设置元素的visibility值为hidden 设置元素的display值为none 设置元素的position值为abso ...

  6. DOM元素querySelectorAll可能让你意外的特性表现

    一.时间紧急,废话少说 本文所在的页面藏匿了下面这些代码: <img id="outside"> <div id="my-id"> &l ...

  7. 使用dom元素和jquery元素实现简单增删改的练习

    软件开发实际就是数据的增删改查,javascript前端开发也不例外.今天学了jquery框架的简单使用.于是用它实现简单的增删改,接着也用原始的javascript实现同样的功能,以便看出jquer ...

  8. 返本求源——DOM元素的特性与属性

    抛砖引玉 很多前端类库(比如dojo与JQuery)在涉及dom操作时都会见到两个模块:attr.prop.某天代码复查时,见到一段为某节点设置文本的代码: attr.set(node, 'inner ...

  9. 【面试必备】javascript操作DOM元素

    前言 时间过的真快,不知不觉就到年底了.问问自己,这一年你对自己的工作满意吗? 评价标准是什么呢?当然是马云的那两条准则了:钱给到了吗?干的爽吗?如果答案都是no,那么,你准备好跳槽了吗? 为了应对年 ...

随机推荐

  1. softwareTesting_work1

    1.12306手机APP软件测评 首先是软件界面,iPhone版本和android版本长得是一模一样,虽然是注重功能的软件,但是一样样的界面让人完全感受不到软件设计者的诚意啊. 还有就是软件图片和图标 ...

  2. 让dedecms autoindex,itemindex 从0到1开始的办法! 多重样式输出(借鉴)

    原网址:http://my.oschina.net/lyx2012/blog/55888 [field:global name=autoindex runphp="yes"]@me ...

  3. Linux下select&poll&epoll的实现原理(一)

    最近简单看了一把 linux-3.10.25 kernel中select/poll/epoll这个几个IO事件检测API的实现.此处做一些记录.其基本的原理是相同的,流程如下 先依次调用fd对应的st ...

  4. java 中List.subList 总结

    今天,维护以前的代码,看到了List.subList这个方法,以前没接触过,对这个就是个小白,今天学习下: java.util.List中有一个subList方法,用来返回一个list的一部分的视图. ...

  5. js写的5秒钟倒计时跳转

    使用js实现几秒以后倒计时跳转,这个在某些特殊情况下还是比较实用的,下面为大家介绍下具体的实现步骤,感兴趣的朋友不要错过  代码如下: <html>  <head>  < ...

  6. jquery div 下拉框焦点事件

    这章与上一张<jquery input 下拉框(模拟select控件)焦点事件>类似 这章讲述div的焦点事件如何使用 div的焦点事件与input的焦点事件区别在于 需要多添加一个属性: ...

  7. 【Cocos2d-x 3.x】 场景切换生命周期、背景音乐播放和场景切换原理与源码分析

    大部分游戏里有很多个场景,场景之间需要切换,有时候切换的时候会进行背景音乐的播放和停止,因此对这块内容进行了总结. 场景切换生命周期 场景切换用到的函数: bool Setting::init() { ...

  8. Lua 自定义函数string.split

    function string.split(str, delimiter)    if str==nil or str=='' or delimiter==nil then        return ...

  9. js或jquery如何获取父级、子级、兄弟元素(包括祖级、孙级等)

    原生javascript方法: var a = document.getElementById("dom"); del_space(a); //清理空格 var b = a.chi ...

  10. ie6对hover兼容性问题的解决:

    ie6对hover兼容性问题的解决: 1,在body里添加以下样式: behavior:url(../scripts/csshover.htc); csshover.htc可直接在网上下载 2,js解 ...