Javascript AngularJS:在指令中绑定全局事件的最佳方式是什么
想象一下AngularJS中的情况,您希望创建一个需要响应全局事件的指令。在这种情况下,比如说,窗口调整大小事件 最好的方法是什么?在我看来,我们有两个选择: 1.让每个指令都绑定到事件,并在当前元素上发挥神奇的作用 2.创建一个全局事件侦听器,该侦听器执行DOM选择器,以获取应用逻辑的每个元素 选项1的优点是您已经可以访问要对其执行某些操作的元素。但是…选项2的优点是,您不必在同一事件上绑定多次(对于每个指令),这可能会提高性能 让我们来说明这两种选择: 选项1:Javascript AngularJS:在指令中绑定全局事件的最佳方式是什么,javascript,angularjs,events,resize,directive,Javascript,Angularjs,Events,Resize,Directive,想象一下AngularJS中的情况,您希望创建一个需要响应全局事件的指令。在这种情况下,比如说,窗口调整大小事件 最好的方法是什么?在我看来,我们有两个选择: 1.让每个指令都绑定到事件,并在当前元素上发挥神奇的作用 2.创建一个全局事件侦听器,该侦听器执行DOM选择器,以获取应用逻辑的每个元素 选项1的优点是您已经可以访问要对其执行某些操作的元素。但是…选项2的优点是,您不必在同一事件上绑定多次(对于每个指令),这可能会提高性能 让我们来说明这两种选择: 选项1: angular.module
angular.module('app').directive('myDirective', function(){
function doSomethingFancy(el){
// In here we have our operations on the element
}
return {
link: function(scope, element){
// Bind to the window resize event for each directive instance.
angular.element(window).on('resize', function(){
doSomethingFancy(element);
});
}
};
});
angular.module('app').directive('myDirective', function(){
function doSomethingFancy(){
var elements = document.querySelectorAll('[my-directive]');
angular.forEach(elements, function(el){
// In here we have our operations on the element
});
}
return {
link: function(scope, element){
// Maybe we have to do something in here, maybe not.
}
};
// Bind to the window resize event only once.
angular.element(window).on('resize', doSomethingFancy);
});
选项2:
angular.module('app').directive('myDirective', function(){
function doSomethingFancy(el){
// In here we have our operations on the element
}
return {
link: function(scope, element){
// Bind to the window resize event for each directive instance.
angular.element(window).on('resize', function(){
doSomethingFancy(element);
});
}
};
});
angular.module('app').directive('myDirective', function(){
function doSomethingFancy(){
var elements = document.querySelectorAll('[my-directive]');
angular.forEach(elements, function(el){
// In here we have our operations on the element
});
}
return {
link: function(scope, element){
// Maybe we have to do something in here, maybe not.
}
};
// Bind to the window resize event only once.
angular.element(window).on('resize', doSomethingFancy);
});
这两种方法都很好,但我觉得选项二并不是真正的“角度主义”
有什么想法吗?在我看来,我会选择方法1,并稍微调整一下$window服务的使用
angular.module('app').directive('myDirective', function($window){
function doSomethingFancy(el){
// In here we have our operations on the element
}
return {
link: function(scope, element){
// Bind to the window resize event for each directive instance.
anguar.element($window).bind('resize', function(){
doSomethingFancy(element);
});
}
};
});
#2
参考这种方法和这里思想的一个微小变化——你可以把这个事件监听器放在更高的位置,比如app.run——当事件发生时,你可以广播另一个事件,指令会拾取该事件,并在该事件发生时做一些有趣的事情
编辑:我越想这个方法,就越喜欢它,而不是第一个方法。。。收听window resize(调整窗口大小)事件的强大方式-可能将来还需要其他人“了解”此信息,除非您执行类似操作,否则您将被迫为window.resize(调整窗口大小)事件设置另一个事件侦听器
应用程序运行
app.run(function($window, $rootScope) {
angular.element($window).bind('resize', function(){
$rootScope.$broadcast('window-resize');
});
}
指令
角度.module('app')。指令('myDirective',函数($rootScope){
最后
如何做东西的一个很棒的来源是跟随angular用户界面的家伙,例如。我从这些家伙那里学到了很多如何做东西,例如学习angular单元测试的乐趣。他们提供了一个很好的干净的代码库来进行签出。第二种方法感觉更脆弱,因为angular提供了许多方法来引用direc在模板(
my directive
,my_directive
,my:directive
,x-my-directive
,data my directive
,等等)中添加一个变量,因此覆盖所有这些变量的CSS选择器可能会变得非常复杂
如果您只在内部使用指令或指令由单个单词组成,这可能不是什么大问题。但是如果其他开发人员(具有不同的编码约定)可能正在使用您的指令,您可能希望避免第二种方法
但我会很务实。如果你处理的是少数实例,请使用#1。如果你有数百个实例,我会使用#2。我选择了另一种方法,有效地定位全局事件,比如调整窗口大小。它通过另一个指令将Javascript事件转换为角度范围事件
app.directive('resize', function($window) {
return {
link: function(scope) {
function onResize(e) {
// Namespacing events with name of directive + event to avoid collisions
scope.$broadcast('resize::resize');
}
function cleanUp() {
angular.element($window).off('resize', onResize);
}
angular.element($window).on('resize', onResize);
scope.$on('$destroy', cleanUp);
}
}
});
在基本情况下,可以在应用程序的根元素上使用
<body ng-app="myApp" resize>...
与其他方法相比,这有许多好处:
- 对于指令使用的确切形式而言,不容易理解。如果angular将以下内容视为等效内容,
,my:directive
,data my directive
,x-my-directive
,如图所示my\u directive
- 您只有一个位置可以准确地影响Javascript事件转换为角度事件的方式,这将影响所有侦听器。假设您稍后要使用取消Javascript
事件的影响。您可以将resize
指令修改为:resize
angular.element($window).on('resize', $window._.debounce(function() { scope.$broadcast('resize::resize'); },500));
- 因为它不一定会在
上触发事件,所以只需移动$rootScope
指令的位置,就可以将事件限制在应用程序的一部分resize
用作:<body ng-app="myApp"> <div> <!-- No 'resize' events here --> </div> <div resize> <!-- 'resize' events are $broadcast here --> </div>
这为您以后添加数据提供了一个单独的位置。例如,假设您希望发送自上次取消公告事件以来的维度差异?您可能可以添加一些代码来记住旧的大小并发送差异<div resize> <!-- Undebounced 'resize' Angular events here --> </div> <div resize="500"> <!-- 'resize' is debounced by 500 milliseconds --> </div>
本质上,这种设计提供了一种方法,可以以可配置的方式将全局Javascript事件转换为局部角度事件,并且不仅对应用程序是局部的,而且对应用程序的不同部分也是局部的,具体取决于指令的位置。在框架之上开发时,我经常发现不可知地思考问题很有帮助在设计一个惯用语之前,先回答“什么”和“为什么”,然后再回答“如何”
app.directive('resize', function($window) {
return {
link: function(scope) {
function onResize(e) {
// Namespacing events with name of directive + event to avoid collisions
scope.$broadcast('resize::resize');
}
function cleanUp() {
angular.element($window).off('resize', onResize);
}
angular.element($window).on('resize', onResize);
scope.$on('$destroy', cleanUp);
}
}
});
这里的答案实际上取决于doSomethingFancy()
的复杂性。是否存在数据、一组功能或域对象与本指令的实例相关?是否纯粹出于表象考虑,如将某些元素的宽度
或高度
属性调整为窗口大小的适当比例?确保使用正确的工具进行工作;当工作需要镊子和工具时,不要带整个瑞士军刀您可以访问一个独立的对。为了继续这样做,我将假设doSomethingFancy()
是一个纯粹的表示函数
在角度事件中包装全局浏览器事件的问题可以通过一些简单的运行阶段配置来处理:
angular.module('myApp')
.run(function ($rootScope) {
angular.element(window).on('resize', function () {
$rootScope.$broadcast('global:resize');
})
})
;
/**
* you can inject any services you want: $rootScope if you still want to $broadcast (in)
* which case, you'd have a "Publisher" instead of a "Mediator"), one or more services
* that maintain some domain objects that you want to manipulate, etc.
*/
function ResizeMediator($window) {
function doSomethingFancy() {
// whatever fancy stuff you want to do
}
angular.element($window).bind('resize', function () {
// call doSomethingFancy() or maybe some other stuff
});
}
angular.module('myApp')
.service('resizeMediator', ResizeMediator)
.run(resizeMediator)
;
现在Angular不必在每个$digest
上执行与指令相关的所有工作,
但是你得到了同样的功能
第二个问题是在触发此事件时对n
个数的元素进行操作。同样,如果您不需要指令的所有提示,还有其他方法可以实现这一点。您可以在
angular.module('myApp')
.run(function ($rootScope) {
angular.element(window).on('resize', function () {
$rootScope.$broadcast('global:resize');
})
})
;
angular.module('myApp')
.run(function () {
angular.element(window).on('resize', function () {
var elements = document.querySelectorAll('.reacts-to-resize');
})
})
;
/**
* you can inject any services you want: $rootScope if you still want to $broadcast (in)
* which case, you'd have a "Publisher" instead of a "Mediator"), one or more services
* that maintain some domain objects that you want to manipulate, etc.
*/
function ResizeMediator($window) {
function doSomethingFancy() {
// whatever fancy stuff you want to do
}
angular.element($window).bind('resize', function () {
// call doSomethingFancy() or maybe some other stuff
});
}
angular.module('myApp')
.service('resizeMediator', ResizeMediator)
.run(resizeMediator)
;
angular.module('app').directive('myDirective', function($window){
var elements = [];
$window.on('resize', function(){
elements.forEach(function(element){
// In here we have our operations on the element
});
});
return {
link: function(scope, element){
elements.push(element);
}
};
});