zoukankan      html  css  js  c++  java
  • HTML DOM元素的Dragdrop

    在前端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所在列的元素可拖拽。当其被拖拽到其它其它行的时候,以行为单位进行整体交换。

    看一下行的元素布局

    1 <div id="div0" class="containerDiv" ondrop="drop(event)" data-dropable="true" ondragover="dragOver(event)" data-dropEl='drag0' >
    2                     <span class="headerCellStyle"> 1</span>
    3                      <span id="drag0" ondragstart="drag(event)" data-dragable="true" data-dropElHost='div0' data-sequence='1361' data-key='1361' data-orginalSequence='1361'>
    4                         <span style="4.3vw;" class="bodyCellStyle" >100</span>
    5                         <span  style="8.9vw;" class="bodyCellStyle" >Rake</span>
    6                         <span id="testitem0" style="vertical-align:middle; display:inline-block;21vw;overflow:hidden;white-space:nowrap" class=" dropElCSS" onmouseover="OnMouseEnterEvent(event)" onmouseout="OnMouseLeaveEvent(event)">Max_Load_Clamp </span>
    7                         <span style="display:inline-block; 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>
    8                     </span>
    9                 </div>
    View Code

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

    1 if(targetContainer.id.indexOf("testitem")>=0) {
    2                 targetContainer = ev.target.parentNode || ev.target.parentElement;
    3                 targetContainer = targetContainer.parentNode || targetContainer.parentElement;
    4             }
    View Code

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

     1 function SetItemDragable(dragable, dragEl){
     2             var gloableStatus = true;
     3             if(dragEl)
     4                 dragEl.setAttribute("draggable", gloableStatus&&dragable);
     5         }
     6 
     7         function OnMouseEnterEvent(ev){
     8             var elID = ev.target.id;
     9             var parentEl = ev.target.parentNode || ev.target.parentElement;
    10             if(parentEl) SetItemDragable(true, parentEl);
    11         }
    12 
    13         function OnMouseLeaveEvent(ev){
    14             var elID = ev.target.id;
    15             var parentEl = ev.target.parentNode || ev.target.parentElement;
    16             if(parentEl) SetItemDragable(false, parentEl);
    17         }
    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代码为:

     1 function dragOver(ev) {
     2             ev.preventDefault();
     3 
     4         }
     5 
     6         function drag(ev) {
     7             if(ev.target.getAttribute("data-dragable")!="true") return;
     8             ev.dataTransfer.setData("text", ev.target.id);
     9         }
    10 
    11         function drop(ev) {
    12             ev.preventDefault();
    13             var targetContainer = ev.target;
    14          
    15             if(targetContainer.id.indexOf("testitem")>=0) {
    16                 targetContainer = ev.target.parentNode || ev.target.parentElement;
    17                 targetContainer = targetContainer.parentNode || targetContainer.parentElement;
    18             }
    19 
    20             if(targetContainer.getAttribute("data-dropable")!="true") return;
    21 
    22             var data = ev.dataTransfer.getData("text");
    23             var dropEl = document.getElementById(data);
    24             targetContainer.appendChild(dropEl);
    25 
    26             var dropElHost = document.getElementById(dropEl.getAttribute("data-dropElHost"));
    27             var hostOrginalEl = document.getElementById(targetContainer.getAttribute("data-dropEl"));
    28             targetContainer.removeChild(hostOrginalEl);
    29             dropElHost.appendChild(hostOrginalEl);
    30 
    31             //swap host id of each element
    32             hostOrginalEl.setAttribute("data-dropElHost", dropEl.getAttribute("data-dropElHost"));
    33             dropEl.setAttribute("data-dropElHost", targetContainer.id);
    34 
    35             //swap drop element id of its container div
    36             targetContainer.setAttribute("data-dropEl", data);
    37             dropElHost.setAttribute("data-dropEl", hostOrginalEl.id);
    38 
    39             //swap sequence of drop element
    40             var hostOrginalElSequence = hostOrginalEl.getAttribute("data-sequence");
    41             hostOrginalEl.setAttribute("data-sequence", dropEl.getAttribute("data-sequence"));
    42             dropEl.setAttribute("data-sequence", hostOrginalElSequence);
    43 
    44             
    45             SetSaveBtnStatus(true);
    46             
    47         }
    48 
    49         function ShowSequence() {
    50             var idPrefix = "drag";
    51             var result = "";
    52 
    53             var data="";
    54             var dragElementLength = 504; //there're not so many elements now. 
    55             for (var i = 0; i < dragElementLength; i++) {
    56                 var id = idPrefix + i;
    57                 var el = document.getElementById(id);
    58                 if(el==null) continue;
    59                 var currentSequence = el.getAttribute("data-sequence");
    60                 var orginalSequence = el.getAttribute("data-orginalSequence"); 
    61 
    62                 if(currentSequence == orginalSequence) continue;
    63 
    64                 data += "("+el.getAttribute("data-key") +"," +currentSequence+")";
    65             }
    66 
    67             if(data.length==0){
    68                 MessageBox("ERROR: There's no item for order change!");
    69                 return;
    70             }
    71 
    72             document.getElementById("resultInput").value = escape( data); 
    73 
    74             //document.getElementById("form1").submit();
    75             document.getElementById("resultDiv").innerHTML = "The updated items are(data-key, data-sequence):" + data;
    76         }
    77 
    78         function SetSaveBtnStatus(activity){
    79             document.getElementById("saveBtn").disabled = !activity;
    80         }
    81 
    82         function SetItemDragable(dragable, dragEl){
    83             var gloableStatus = true;
    84             if(dragEl)
    85                 dragEl.setAttribute("draggable", gloableStatus&&dragable);
    86         }
    87 
    88         function OnMouseEnterEvent(ev){
    89             var elID = ev.target.id;
    90             var parentEl = ev.target.parentNode || ev.target.parentElement;
    91             if(parentEl) SetItemDragable(true, parentEl);
    92         }
    93 
    94         function OnMouseLeaveEvent(ev){
    95             var elID = ev.target.id;
    96             var parentEl = ev.target.parentNode || ev.target.parentElement;
    97             if(parentEl) SetItemDragable(false, parentEl);
    98         }
    JavaScript

    样式表为:

    1 .containerDiv {min-width:350px;width:auto;border:0.1vw solid #aaaaaa;float:none;border-top:0px;}
    2 .dateTip{font-style:italic;}
    3 .userManual{min-width:350px;width:auto;/*border:0.1vw solid #aaaaaa;*/}
    4 .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;}
    5 .bodyCellStyle{display:inline-block;margin-left:0.4vw;padding:0.2vw 0px;border-right:0.1vw solid #aaaaaa;white-space:nowrap;}
    6    .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

  • 相关阅读:
    家庭作业有益吗?
    视图、触发器、事务、存储过程、函数
    Navicat使用和pymysql
    表查询
    外键
    MySQL表操作
    进程池线程池、协程
    全局解释器锁及其他用法
    线程
    进程
  • 原文地址:https://www.cnblogs.com/huankfy/p/HTML_Dragdrop.html
Copyright © 2011-2022 走看看