有人可以向我解释在 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/