Angularjs Drag and Drop

官网tab directive http://docs.angularjs.org/guide/directive

官网的module

http://docs.angularjs.org/guide/directive

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
angular.module('dragModule', []).
  directive('myDraggable', function($document) {
    return function(scope, element, attr) {
      var startX = 0, startY = 0, x = 0, y = 0;
 
      element.css({
       position: 'relative',
       border: '1px solid red',
       backgroundColor: 'lightgrey',
       cursor: 'pointer'
      });
 
      element.on('mousedown', function(event) {
        // Prevent default dragging of selected content
        event.preventDefault();
        startX = event.pageX - x;
        startY = event.pageY - y;
        $document.on('mousemove', mousemove);
        $document.on('mouseup', mouseup);
      });
 
      function mousemove(event) {
        y = event.pageY - startY;
        x = event.pageX - startX;
        element.css({
          top: y + 'px',
          left:  x + 'px'
        });
      }
 
      function mouseup() {
        $document.unbind('mousemove', mousemove);
        $document.unbind('mouseup', mouseup);
      }
    }
  });

使用jquery-ui的drag and drop

https://github.com/codef0rmer/angular-dragdrop

太重

另外一个不错的实现 http://logicbomb.github.io/ng-directives/drag-drop.html

有很多angularjs的directive http://www.directiv.es/

native drag-and-drop

http://blog.parkji.co.uk/2013/08/11/native-drag-and-drop-in-angularjs.html

对应的实现 http://ganarajpr.github.io/angular-dragdrop/

在onDrop中要記得不要刪除drag的element, 否則element的dragend就不會被調用,一些binding就不能得到清除, 如果要刪除元素,請在on-drop-success中操作, drag和drop操作獨立有好處,但也增加了維護的複雜度

上述的實現,在判斷是否成功drop的時候,是在drag的元素的 dragend事件中判斷 e.dataTransfer.dropEffect是否為none, 因為設置ui-on-drop的元素,會綁定dragover等事件,並且在 dragover的時候將e.dataTransfer.dropEffect設置為”move” 所以在dragend中如果為move,則認為element drop sucess. 但這個帶來的問題就是, 沒有辦法和plupload的drop上傳和平共處, 通過dropEffect判斷是否成功也不夠獨立, 覺得應該需要設置獨立的標誌

嘗試直接在onDrop事件中調用dataTranfer.setData, 但是失敗了 因為出於安全考慮 在dragstart事件中,可以調用e.dataTransfer.setData設置任何的值, 在onDrop中通過e.dataTransfer.getData獲取 但是dragenter等中間事件沒有權限訪問這些值,擔心dragover的一些中間元素會設置listener從而獲取這些值 這裡有一些解釋http://stackoverflow.com/questions/8762635/getting-the-filename-during-the-dragenter-event

經測試, 在onDrop中e.dataTransfer.setData不能成功

想參考ANGULAR_DRAG_START, 利用 angular的事件機制,在原有的ANGULAR_DRAG_START,ANGULAR_DRAG_END的基礎上再增加ANGULAR_DROP_SUCCESS 經過測試發現,如果在draggable的item上綁定ANGULAR_DROP_SUCCESS, 因為有多少個item就會綁定多少次, 而且觸發ANGULAR_DROP_SUCCESS的時候,所有都會響應,不成功

最後還是使用了callback, 在uiDraggable內部定義了callback, 然後通過$rootScope.$broadcast傳遞給drop element, 最後在onDrop中囘調

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var dropped = false
function onDrop(e){
    console.log('hello drop success')
    dropped = true
    
}
element.bind("dragend", function (e) {
    if(dropped)
    {
        if (attrs.onDropSuccess) {
            var fn = $parse(attrs.onDropSuccess);
            scope.$apply(function () {
                fn(scope, {$event: e});
            });
        }    
    }
    dropped = false
});

ondrop先觸發dragend后觸發,但不能保證對應囘調函數的執行順序也是ondrop在前, 但為了簡化操作,還是認為drop在dragend之前執行

通過囘調設置flag, 再由dragend判斷flag執行刪除element操作基本符合了預期,之所以不在囘調就刪除元素,是因為dragend需要被調用來做一些清理去綁定的操作,否則後續的drag操作中會出現重複調用的問題, 如果在onDrop囘調中就刪除element, dragend就不會被調用 之所以要動態綁定和解綁,和channel的引入都是爲了提高靈活性,與其他可能的drag&drop操作區分開,否則比如一直綁定,從頁面外拖入文件也會得到響應,但就會出現問題

現在單個的drag&drop沒有問題 開始考慮multi-drag&drop 首先multi drop的時候就需要隱藏沒有被drag的選中items, 所以要先新增一個callback, on-drag-start

開始考慮拖動的效果問題

http://threedubmedia.com/demo/drag/ 這裡的效果需要額外的jquery.event.drag插件輔助

http://www.kryogenix.org/code/browser/custom-drag-image.html

http://www.html5rocks.com/en/tutorials/dnd/basics/

官方文檔 http://www.w3.org/TR/2011/WD-html5-20110405/dnd.html

Written with StackEdit.

  1. fancybox 和div drag IE有冲突, 通过限制a href长度解决
  2. 在upload之后select失效
  3. 将orderBy直接移到common
  4. IE drag 无法调用onDropSuccess, 原来是是IE无法修改 e.dataTransfer.dropEffect的值