Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/444.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 在DOM元素d3之间交换事件处理程序_Javascript_D3.js - Fatal编程技术网

Javascript 在DOM元素d3之间交换事件处理程序

Javascript 在DOM元素d3之间交换事件处理程序,javascript,d3.js,Javascript,D3.js,我所拥有的代码意味着获取控件的事件处理程序,并将这些处理程序移动到另一个元素,并删除以前控件的事件处理程序 \u drag.element函数应该从slider1中删除事件处理程序,并将它们放在slider2上。目前,这两个元素都在触发事件处理程序 //拖动功能 var Drag = (function(){ var _opts, _drag = d3.behavior.drag(); var eventList = ['drag','dragstart','dr

我所拥有的代码意味着获取控件的事件处理程序,并将这些处理程序移动到另一个元素,并删除以前控件的事件处理程序

\u drag.element
函数应该从slider1中删除事件处理程序,并将它们放在slider2上。目前,这两个元素都在触发事件处理程序

//拖动功能

var Drag = (function(){
    var _opts,
        _drag = d3.behavior.drag();
    var eventList = ['drag','dragstart','dragend'];
    function attachEvents(opts){
        eventList.forEach(function(e,i){
            if(opts[e]){
                _drag.on(e,this[e]);
            }
            else{
                _drag.on(e,null);
            }
        }.bind(this));
    };
    function detachEvents(){
        eventList.forEach(function(e,i){
            if(_opts[e]){
                _drag.on(e,null);
            }
        }.bind(this));
    }
    function Drag(opts){
        _opts = opts;
        attachEvents.call(this,opts);
        _opts.element = opts.element.call(_drag);
        _opts.element.attr('isDraggable',true);
    }
  Drag.prototype.drag = function(args){
      _opts.drag(args);
  };
  Drag.prototype.dragstart = function(args){
      _opts.dragstart(args);
  }

  Drag.prototype.dragend = function(args){
      _opts.dragend(args);
  }
  Drag.prototype.element = function(el){
      if(el){
          detachEvents.call(this)
          _opts.element = el;
          attachEvents.call(this,_opts);
          _opts.element.call(_drag);
      }
  }
  Drag.prototype.config = function(opts){
      _opts = opts;
      attachEvents.call(this,_opts);

  }
    return Drag;
})();

detachEvents
没有从上一个元素中删除事件侦听器有什么问题?

以下是拖动行为的工作原理

首先创建如下行为:

var _drag = d3.behavior.drag();
然后将事件处理程序附加到它:

_drag
    .on('dragstart', function() { ... })
    .on('drag', function() { ... })
    .on('dragend', function() { ... });
然后将此行为附加到元素:

d3.select('#slider1').call(_drag);
它有效地将上面定义的处理程序附加到该元素(实际事件的名称不同)

将事件处理程序从行为中分离如下:

 _drag.on('dragstart', null);
d3.select('#slider1').on('.drag', null);
它工作正常

但是

不幸的是,将此行为与禁用的事件处理程序一起应用于具有绑定(启用)事件处理程序的元素不会禁用该元素的处理程序。即

_drag.on('dragstart', null);
d3.select('#slider1').call(_drag);
不会阻止
#slider1
像以前一样处理
dragstart

这就是我的实验所显示的。不知道这是不是一个错误

无论如何,有一种直接的方法可以将拖动处理程序与元素分离。
由于所有与拖动相关的事件都位于
.drag
名称空间内,因此可以一次禁用它们,如下所示:

 _drag.on('dragstart', null);
d3.select('#slider1').on('.drag', null);

检查此项

需要了解的重要一点是,拖动行为(由
d3.behavior.drag()返回的函数)可以应用于任意数量的选择,并且不知道它绑定的DOM元素

在内部,该行为有一个自定义的分派对象,它抽象了人工事件。这些事件——“drag”、“dragstart”和“dragend”——从任何源于DOM的本机事件中完全删除。内部分派对象只是一个用于

  • 认识到这些抽象事件
  • 管理听众对他们的依恋和疏离
  • 提供用于触发抽象事件和
  • 触发已注册侦听器后通知它们
  • 这就是你从这个代码中得到的结果

    var _drag = d3.behavior.drag();
    
    _drag
        .on('dragstart', function() { ... })
        .on('drag', function() { ... })
        .on('dragend', function() { ... });
    
    请注意,上面的任何一个都没有对任何DOM元素或它们的事件的引用,并且它们本身不能启动任何东西。在通过
    selection.call(behavior)
    连接到DOM UI之前,该行为实际上无法执行任何操作。这是行为连接到domui的地方。不知何故,它需要找出是否发生了dragstart事件,它需要从UI事件中提取该事件,并且它或多或少是这样做的:
    selection.on({“mousedown.drag”:mousedown,“touchtstart.drag”:touchtstart})

    因此,这里有两个完全独立的本机事件——“mousedown”和“touchstart”——源自选择中的DOM元素——通过拖动行为“在引擎盖下”应用

    (正如@dekkard所提到的,它们的名称空间是通过将“.drag”添加到 它们的标准名称。d3管理这些名称,并在 订阅。)

    侦听器-
    mousedown
    touchstart
    是由
    d3.behavior.drag
    对象生成并在其内部关闭的对象,它们都会回调启动拖动过程的behavior对象内的进程。只要行为实例继续存在,它就会继续侦听这些DOM UI事件

    因此有两个完全独立的接口:一个用于调用和管理抽象的“drag”、“dragstart”和“dragend”事件,另一个用于连接到DOM UI事件“mousedown”和“touchstart”

    因此,此代码的净效果

      detachEvents.call(this)
      _opts.element = el;
      attachEvents.call(this,_opts);
      _opts.element.call(_drag);
    
    将侦听器分离并重新附加到行为的内部分派对象,并将该行为添加到第二个选择中。所以现在,来自任一选择的“mousedown”和“touchstart”将导致相同的拖动行为

    根据,@dekkard-
    .on('.drag',null)
    -提供的方法是将行为与选择断开连接的唯一方法,因此它毕竟不是一个bug。我想这只是一个缺失的功能

    注意:在d3中通过替换此代码来实现这一点是非常容易的

    function drag() { 
        this.on("mousedown.drag", mousedown).on("touchstart.drag", touchstart);
    }  
    
    用这个

    function drag(selection, remove) {
        [{e:"mousedown.drag", l: mousedown},{e: "touchstart.drag", l: touchstart}]
        .reduce(function (s, b) {return s = s.on(b.e, remove ? null : b.l)}, this)
    }
    
    在d3.behavior.drag中 然后我们可以这样做

    _opts.element.call(_drag, "remove")  
    

    断开这种行为。

    请您“重新考虑”这句话好吗?“不幸的是,将禁用事件处理程序的此行为应用于具有绑定(启用)事件处理程序的元素不会禁用元素的处理程序。”我对您的答案非常感兴趣,但我不理解您的意思。e、 g.能否定义“禁用的事件处理程序”;“绑定(已启用)事件处理程序”。。。也许这会有帮助。很抱歉不清楚。我的意思是:定义一个行为,然后将一个事件处理程序绑定到该行为,然后将该行为应用到一个对象=>该对象现在已附加了一个事件处理程序。现在您为该行为禁用该事件处理程序(
    .on('event',null)
    ),并将该行为应用于同一个对象=>该对象仍然具有以前附加的处理程序。啊,好的,我想我终于明白您的意思了。事件已从“行为”中关闭的调度程序中删除,但存储在节点上的回调仍在侦听。我认为这肯定是一个bug。这个过程的代码(在我看来)非常复杂,我很想理解它,但是我认为应该对监听器进行适当的清理。顺便说一下,对名称空间的了解很好。有趣的是,尽管可以删除名称空间中的所有侦听器,但并没有实现侦听名称空间中的所有事件。不过,在分支中有一个用于此选项的占位符prima fa