Dart学习笔记(14):拖放技术(Drag and Drop)

发表于2018-07-04 18:02 阅读(29)

拖放 Drag and Drop,有时又被称为 DnD
是现代软件开发中必不可少的一项技术

本文地址:http://www.cndartlang.com/761.html

它提供了一种能够在应用程序内部甚至是应用程序之间进行信息交换的机制
并且,操作系统与应用程序之间进行剪贴板的内容交换
也可以被认为是 DnD的一部分

1、可拖动的名片

basics.css

body {
  background-color: #F8F8F8;
  font-family: '黑体';
  font-size: 14px;
  line-height: 1.2em;
}

/* 可拖动元素的文本设置为不能选择 */
[draggable] {
  user-select: none;
}

.column {
  background-color: #ccc;
  border: 2px solid #666;
  border-radius: 5px;
  cursor: move;
  
  /*设置多行文本水平和垂直居中显示*/
  width: 150px;
  text-align: center;
  padding-top:50px;
  padding-bottom:50px;
  
  float: left;
  margin-right: 5px;
  
  /*设置变换的特效*/
  transition: transform 0.2s ease-out;
}

/*拖动到元素上方时,显示为虚线边框*/
.column.over {
  border: 2px dashed #000;
}

/*拖动的时候,原DIV透明度降低、缩小尺寸*/
.column.moving {
  opacity: 0.25;
  transform: scale(0.8);
}

index.html

<!DOCTYPE html>

<html>
  <head>
    <meta charset="utf-8">
    <title>Note14: Drag and Drop</title>
    <link rel="stylesheet" href="basics.css">
  </head>
  <body>
    <div id="columns">
      <div class="column" draggable="true">Wong Jeff<br/>ID:060806110006</div>
      <div class="column" draggable="true">Lee Lei<br/>ID:060806110018</div>
      <div class="column" draggable="true">Zhang Han<br/>ID:060806110037</div>
    </div>
    <script type="application/dart" src="basics.dart"></script>
    <script src="packages/browser/dart.js"></script>
  </body>
</html>

basics.dart

import 'dart:html';

class Basics {
  Element _dragSourceEl;

  void start() {
    var cols = document.querySelectorAll('#columns .column');
    for (var col in cols) {
      //遍历所有#columns .column元素,并添加拖动事件的监听程序
      col.onDragStart.listen(_onDragStart);
      col.onDragEnd.listen(_onDragEnd);
      col.onDragEnter.listen(_onDragEnter);
      col.onDragOver.listen(_onDragOver);
      col.onDragLeave.listen(_onDragLeave);
      col.onDrop.listen(_onDrop);
    }
  }

  void _onDragStart(MouseEvent event) {
    //开始拖动,目标元素即拖动的Element,保存到私有变量中,并添加moving样式
    Element dragTarget = event.target;
    dragTarget.classes.add('moving');
    _dragSourceEl = dragTarget;
    event.dataTransfer.effectAllowed = 'move';
    
    //设置需要移动的数据
    event.dataTransfer.setData('text/html', dragTarget.innerHtml);
  }

  void _onDragEnd(MouseEvent event) {
    //结束拖动,Element删除moving样式
    Element dragTarget = event.target;
    dragTarget.classes.remove('moving');
    
    var cols = document.querySelectorAll('#columns .column');
    //其实在Leave的时候,已经删除了over样式
    //所以cols中只有一个Element有over样式(拖放结束,最后那个Element未触发Leave事件)
    for (var col in cols) {
      col.classes.remove('over');
    }
  }

  void _onDragEnter(MouseEvent event) {
    //目标Element添加over样式
    Element dropTarget = event.target;
    dropTarget.classes.add('over');
  }

  void _onDragOver(MouseEvent event) {
    //通知 Web 浏览器不要执行与事件关联的默认动作(如果存在这样的动作)
    //如点击<a>标签会链接到某网址,这就是<a>标签的默认动作
    //如果执行preventDefault后,点击<a>标签就不会有什么动作
    event.preventDefault();
    event.dataTransfer.dropEffect = 'move';
  }

  void _onDragLeave(MouseEvent event) {
    //拖动离开Element的时候,删除over样式
    Element dropTarget = event.target;
    dropTarget.classes.remove('over');
  }

  void _onDrop(MouseEvent event) {
    //结束事件传递
    event.stopPropagation();

    // 如果拖动和放下的Element不是同一个,那么交换数据
    Element dropTarget = event.target;
    if (_dragSourceEl != dropTarget) {
      _dragSourceEl.innerHtml = dropTarget.innerHtml;
      dropTarget.innerHtml = event.dataTransfer.getData('text/html');
    }
  }
}

void main() {
  var basics = new Basics();
  basics.start();
}

拖放在HTML5中很容易做到,需注意标签的draggable设为true
然后就是监听拖放过程中的各个事件,代码很简洁

2、DataTransfer对象

如果网页只能简单的拖放而没有数据的变化,那没多大实用性
因此,为了在拖放的时候实现数据交换,引入了DataTransfer对象
并且,DataTransfer是事件event的一个属性

同时,DataTransfer并不只是用来传递数据
还能通过它来确定被拖动的元素以及作为放置目标的元素能够接受什么操作
为此需要访问DataTransfer的两个属性,effectAllowed和dropEffect

必须在onDragStart事件处理程序中设置effectAllowed属性
并且,dropEffect属性只有搭配effectAllowed属性才有用

effectAllowed属性表示允许拖放元素的哪种dropEffect,effectAllowed可能的值如下:

  • uninitialized:没有该被拖动元素放置行为。
  • none:被拖动的元素不能有任何行为。
  • copy:只允许值为“copy”的dropEffect。
  • link:只允许值为“link”的dropEffect。
  • move:只允许值为“move”的dropEffect。
  • copyLink:允许值为“copy”和“link”的dropEffect。
  • copyMove:允许值为“copy”和”link”的dropEffect。
  • linkMove:允许值为“link”和”move”的dropEffect。
  • all:允许任意dropEffect。

通过dropEffect属性可以知道被拖动的元素能够执行哪种放置行为这个属性有下列4个可能的值:

  • none:不能把拖动的元素放在这里。这是除文本框之外所有元素的默认值。
  • move:可以把拖动的元素移动到放置目标。
  • copy:可以把拖动的元素复制到放置目标。
  • link:表示放置目标会打开拖动的元素(但拖动的元素必须是一个链接,有URL)。

然后,现在再回去看代码
有没有豁然开朗的感觉?!

本文地址:http://www.cndartlang.com/761.html