javascript - AngularJS DOM 修改删除事件 -> 需要可行的解决方法实现架构

标签 javascript angularjs dom d3.js event-handling

有人可以向我解释在 AngularJS 中创建自定义事件监听器以抵抗 DOM 修改的正确方法吗?

我的问题是我需要根据下拉菜单绘制 2 个不同的数据集。数据集的每个元素都必须响应一个事件(鼠标悬停/鼠标移动等...)。但是当从一个数据集切换到另一个数据集时,事件监听器会丢失。 这种行为在这里得到了很好的解释:

但我不明白给出的绕过它的答案。该帖子提到手动避免 ng-app 可以提供帮助,但这似乎是一个糟糕的解决方法。

我宁愿重新定义我自己的事件监听器,这样它们就不会在 DOM 修改期间丢失。有人能告诉我如何在指令/ Controller 模型中正确使用 addEventListener 吗?

这是一个 SSCCE html/javascript 文件,说明了我的程序是如何组织的

angular.module("testUpdate", [])

.directive("shape", function($parse) {

  return {

    restrict: "E",
    replace: false,
    scope: false,
    link: function(scope, element, attrs) {
      
      // draw dataset according to #shapeSelection choice

      d3.select("#shapeSelection")
        .on("change", scope.redraw);
      
      // change color on mouseover

      d3.selectAll("circle,rect,polygon")
        .on("mouseover", function() {
          d3.select(this).style("fill", "#0f0");
        });

    }
  };
})


.controller("testController", function($scope) {

  $scope.shape = "none";
  
  //create datasets
  
  $scope.dataset1 = [{
    cx: 10,
    cy: 20
  }, {
    cx: 30,
    cy: 20
  }];
  $scope.dataset2 = [{
    w: 20,
    h: 20
  }];


  // the triangle actually responds to the event
  
  d3.selectAll("svg")
    .append("polygon")
    .attr("points", "15,20 0,40 30,40")
    .style("fill", "#f00");
  
  // draw dataset depending on the user choice

  $scope.draw = function() {

    if ($scope.shape === "circle") {
      d3.selectAll("svg").selectAll("circle")
        .data($scope.dataset1).enter()
        .append("circle")
        .attr("cx", function(d) { return d.cx; })
        .attr("cy", function(d) { return d.cy; })
        .attr("r", 10)
        .style("fill", "#f00");
    } 
    
    else if ($scope.shape === "rect") {
      d3.selectAll("svg").selectAll("rect")
        .data($scope.dataset2).enter()
        .append("rect")
        .attr("width", function(d) { return d.w; })
        .attr("height", function(d) { return d.h; })
        .attr("x", 0)
        .attr("y", 10)
        .style("fill", "#f00");
    } 
    
    else {}
  }
  
  // once removed is called, the event listener is destroyed

  $scope.redraw = function() {
    d3.selectAll("circle,rect,polygon").remove();
    $scope.draw()
  }

});
<script src="https://code.angularjs.org/1.2.15/angular.js"></script>
<script src="http://d3js.org/d3.v3.min.js"></script>



<div ng-app="testUpdate" ng-controller="testController">
  <select name="shapeSelector" ng-model="shape" id="shapeSelection">
    <option value="none">--none--</option>
    <option value="circle">dataset1</option>
    <option value="rect">dataset2</option>
  </select>
  <shape id="shapeTag">
    <svg id="shapeSVG" display="block"></svg>
  </shape>
</div>

d3.selection.remove() 函数修改 DOM 并取消事件监听器,以便三 Angular 形正确响应,但圆形和矩形不响应。

一个肮脏的解决方法是为两个数据集创建 DOM,并将未选择的数据集的可见性设置为隐藏,但两个数据集都非常大,因此这不是一个可行的选择。

提前致谢

最佳答案

从代码来看,您似乎只想在 shape 指令内的元素上捕获 mouseover 事件。

我认为对您来说最好的解决方案是将绑定(bind)事件处理程序的代码移动到 $scope.redraw$scope.draw 函数中:

  $scope.draw = function() {

    if ($scope.shape === "circle") { 
       /* ... */ 
    } else {}


    // change color on mouseover
    d3.selectAll("circle,rect,polygon")
      .on("mouseover", function() {
        d3.select(this).style("fill", "#0f0");
      });
  }

当您在 D3 领域操作 DOM 时,您不应依赖 Angular 链接函数中定义的事件处理程序。在我编写的指令中,我只是在指令中使用了 $watch 来在数据更新时触发 redraw 函数,就像您对 change 所做的那样 函数。


替代解决方案

另一方面,如果您想处理指令中的事件(例如,如果您不必将 d3 传递给 $scope), 如果您使用的是 jQuery,则 you can use the .on method on a parent with proper selectors .注意 jQlite(Angular 的 jQuery 内部实现),does not supposed .on with selectors .

在这种情况下,即使您更改了下面的 DOM,事件处理程序也会在父级上调用。如果您想访问与事件处理程序内的节点关联的数据,您可以使用var data = d3.select(this).data()

关于javascript - AngularJS DOM 修改删除事件 -> 需要可行的解决方法实现架构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26746850/

相关文章:

javascript - 如果 URL 包含,则交换范围内容

javascript - 如何修复文本以使其显示在一行上?

angularjs - 如何使用 ng-repeat 循环遍历函数返回的项目?

javascript - 如何使用 jQuery 设计事件链接列表项的样式

java - 用于 Java 的 HTML/XML 解析器

javascript - 如何减少 Jquery 中的这一行?

javascript - Safari 中的 SVG SMIL 动画错误

angularjs - Angular - 用 html 插入字符串

javascript - Angular UI-Router - 子状态和父状态中的参数返回错误的模板

javascript - 如何使用 DOM 元素创建表单的副本