通过在Dart中拖动来移动元素

时间:2015-10-27 04:48:38

标签: dart dart-html

我正在尝试使用拖放移动元素。我希望能够将元素拖动到另一个位置,当我放下它时,元素移动到删除的位置。超级基本,没什么特别的。这就是我到目前为止所做的:

HTML:

<input type='button' id='drag' class='draggable' value='drag me' draggable='true'>

飞镖码:

Element drag = querySelector('.draggable');
drag.onDragEnd.listen((MouseEvent e) {
  drag.style.left = '${e.client.x}px';
  drag.style.top = '${e.client.y}px';
});

这并不是我想做的事情。该元素略微偏离我放下的位置。我在javascript中看到了带有appendChild,clone(),parentNode的示例,但我见过的所有示例都不能在Dart中重现。完成此任务的最佳方法是什么?我不想使用免打扰套餐,因为我真的想亲自理解这些概念。

3 个答案:

答案 0 :(得分:1)

<强>的index.html

<!doctype html>
<html>
  <head>
    <style>
      #dropzone {
        position: absolute;
        top: 50px;
        left: 50px;
        width: 300px;
        height: 150px;
        border: solid 1px lightgreen;
      }
      #dropzone.droptarget {
        background-color: lime;
      }
    </style>
  </head>
  <body>
    <input type='button' id='drag' class='draggable' value='drag me'
           draggable='true'>

    <div id="dropzone"></div>
    <script type="application/dart" src="index.dart"></script>
    <script src="packages/browser/dart.js"></script>
  </body>
</html>

<强> index.dart

library _template.web;

import 'dart:html' as dom;
import 'dart:convert' show JSON;

main() async {
  dom.Element drag = dom.querySelector('.draggable');
  drag.onDragStart.listen((event) {
    final startPos = (event.target as dom.Element).getBoundingClientRect();
    final data = JSON.encode({
      'id': (event.target as dom.Element).id,
      'x': event.client.x - startPos.left,
      'y': event.client.y - startPos.top
    });
    event.dataTransfer.setData('text', data);
  });

  dom.Element dropTarget = dom.querySelector('#dropzone');
  dropTarget.onDragOver.listen((event) {
    event.preventDefault();
    dropTarget.classes.add('droptarget');
  });

  dropTarget.onDragLeave.listen((event) {
    event.preventDefault();
    dropTarget.classes.remove('droptarget');
  });

  dropTarget.onDrop.listen((event) {
    event.preventDefault();
    final data = JSON.decode(event.dataTransfer.getData('text'));
    final drag = dom.document.getElementById(data['id']);
    event.target.append(drag);
    drag.style
      ..position = 'absolute'
      ..left = '${event.offset.x - data['x']}px'
      ..top = '${event.offset.y - data['y']}px';
    dropTarget.classes.remove('droptarget');
  });
}

答案 1 :(得分:1)

上面的答案是正确的,我不想因为这个原因而编辑它。但是,我想提供另一个我从上面得到的答案。与上述相比,它更加基础,因此更容易遵循初学者的基本概念。如下所述,我不认为你可以移动元素,除非它们在一个可放置的区域内。

的index.html:

<!DOCTYPE html>
<html>
<head>
  <style>
  #dropzone {
    position: absolute;
    top: 100px;
    left: 50px;
    width: 300px;
    height: 150px;
    border: solid 1px;
    color: lightgreen;
  }</style>
</head>
<body>
  <div  id="dropzone">
    <input type='button' id='drag' class='draggable' value='drag me'
     draggable='true'>
  </div>
  <script type="application/dart" src="main.dart"></script>
</body>
</html>

main.dart:

import 'dart:html';
main() {
  Element drag = querySelector('.draggable');
  Element drop = querySelector('#dropzone');
  drag.onDragStart.listen((MouseEvent e) {
    var startPos = (e.target as Element).getBoundingClientRect();
    String xPos = "${e.client.x - startPos.left}";
    String yPos = "${e.client.y - startPos.top}";
    e.dataTransfer.setData('x', xPos);
    e.dataTransfer.setData('y', yPos);
  });
  drop.onDragOver.listen((MouseEvent e) {
    e.preventDefault();
  });
  drop.onDrop.listen((MouseEvent e) {
    e.stopPropagation();
    String xPos = e.dataTransfer.getData('x');
    String yPos = e.dataTransfer.getData('y');
    int x = num.parse(xPos);
    int y = num.parse(yPos);
    drag.style.position = 'absolute';
    drag.style
      ..left = '${e.offset.x - x}px'
      ..top = '${e.offset.y - y}px';
  });
}

答案 2 :(得分:0)

我有同样的问题,因为上面的答案不能满足我的需求:

  1. 元素拖拽本身(无掉落区)
  2. 可重复使用
  3. 对于基于包装器的解决方案,此包可以是答案:https://pub.dartlang.org/packages/dnd

    基于自定义元素的方法(当前光标样式不起作用):

      main(){
      document.registerElement('draggable-element',
        DraggableElement);
      querySelector('body').append(new DraggableElement()..text='draggable');
      }
      class DraggableElement extends HtmlElement with Draggability{
      DraggableElement.created():super.created(){
        learn_custom_draggability();
      }
      factory DraggableElement(){
        return new Element.tag('draggable-element');
      }
    }
    class Draggability{
      bool __custom_mouseDown = false;
    
      //The Coordinates of the mouse click
      //relative to the left top of the
      //element.
      Point<int> __custom_relative_mouse_position;
      void learn_custom_draggability(){
        if(this is! HtmlElement ){
          throw ("Draggability mixin "
              "is not compatible with"
              ' non-HtmlElement.');
        }
        var self = (this as HtmlElement);
        self.onMouseDown.listen(mouseDownEventHandler);
        self.onMouseUp.listen(mouseUpEventHandler);
        //styling
        self.style.position = 'absolute';
    
        window.onMouseMove
            .listen(mouseMoveEventHandler);
      }
    
      void mouseMoveEventHandler(MouseEvent e){
        if(!__custom_mouseDown) return;
        int xoffset = __custom_relative_mouse_position.x,
          yoffset = __custom_relative_mouse_position.y;
    
        var self = (this as HtmlElement);
        int x = e.client.x-xoffset,
            y = e.client.y-yoffset;
        print(x);
        if(y == 0) return;
        self.style
          ..top = y.toString() +'px'
          ..left = x.toString()+'px';
      }
    
      void mouseDownEventHandler(MouseEvent e){
        print('mouse down');
        __custom_mouseDown = true;
        var self = (this as HtmlElement);
        self.style.cursor = 'grabbing';
    
        __custom_relative_mouse_position =
          e.offset;
      }
    
      void mouseUpEventHandler(MouseEvent e){
        print('mouse up');
        __custom_mouseDown = false;
        var self = (this as HtmlElement);
        self.style.cursor = 'default';
      }
    }
    

    编辑:

    是的,谢谢GünterZöchbauer告诉我有关可反映的信息。它太小而且编译速度快 稍微偏离主题,但是因为mixins和以下模式的发布是齐头并进的。

    import 'package:reflectable/reflectable.dart';
    class Reflector extends Reflectable{
      const Reflector():
            super(
              instanceInvokeCapability,
              declarationsCapability
          );
    }
    const reflector = const Reflector();
    @reflector
    class CustomBase extends HtmlElement{
      CustomBase.created():super.created(){
        learn();
      }
      learn(){
        InstanceMirror selfMirror = reflector.reflect(this);
        var methods = selfMirror.type.instanceMembers;
        RegExp pattern = new RegExp('^learn_custom_.*bility\$');
        for(var k in methods.keys){
          if(pattern.firstMatch(k.toString()) != null){
            selfMirror.invoke(k,[]);
          }
        }
      }
    }
    

    包括:依赖项下的“reflectable:^ 0.5.0”和变形金刚下的“ - reflectable:entry_points:web / index.dart”等 在pubspec.yaml中并扩展一个自定义类,如上所述,而不是HtmlElement和selfMirror.invoke,只要它们的名称与给定模式匹配,就会神奇地调用初始化程序。当你的课程能力很强时很有用。