![](/img/trans.png)
[英]AngularJS : What is the best way to bind to a global event in a directive
[英]AngularJs : what is the best way to changing DOM elements when there are “global”?
我来自 JQuery,我使用 AngularJs 的第一步让我有点困惑......
我的情况 :
我有一个面板(#floatingpanel),它用 css(顶部:-50px)隐藏在视口之外。
我在我的应用程序的最深处有一个链接 (a.trigger),当您单击该链接时,面板的“顶部”属性会从“-50px”变为“0px”以使其可见(您单击切换可见性)。 面板就在我页面主容器的这一端,但它的链接在数百个其他div
。
让我们来看看 DOM 结构:
<body>
<div class="main-wrapper" ng-app="myapp">
<div class="app">
<div class="many-things">
[...]
<a href="#" class="trigger" ng-click="toggleMyPanelVisibility()">
Click here to see the panel
</a>
[...]
</div>
</div><!-- .app -->
<div id="floatingpanel">
Hey ! I was hidden !
</div>
</div> <!-- #mainwrapper -->
</body>
在 jQuery 中,它将是:
$('a.trigger').click( function(e) {
e.preventDefault();
var el = $('#floatingpanel');
var top = el.css('top');
if (top<0) el.css('top', 0);
else el.css('top', -50);
});
我怎样才能用 AngularJs 做到这一点?
我会这样做:
var app = angular.module('myapp');
app.run(["$rootScope", function($rootScope) {
// Toggle du myaccountpanel
$rootScope.floatingpanelVisibility = false;
$rootScope.toggleMyPanelVisibility = function() {
$rootScope.floatingpanelVisibility = !$rootScope.floatingpanelVisibility;
var panel = angular.element( $('#floatingpanel') );
var top = -50;
if ($rootScope.floatingpanelVisibility)
top = 0;
panel.css({'top': top });
}
});
好的,它有效,但是...我想如果我继续这种方式,我的app.run
很快就会超载,不是吗? 我也可以用我的“主包装器”上的控制器来做到这一点,但这很愚蠢,它已经是我的应用程序范围了!
我怎样才能用指令做到这一点?
解决这个烂摊子的“最佳方法”是什么?
我在 Angular 中看到的两种最常见的方法是通过 rootscope 消息传递或通过服务。 该服务是两者中更清洁/更好的。
接受的答案假设一切都在同一个控制器下,这显然不是构建 OP 所描述内容的方式。
想象一个页面由一堆小部件组成——无论是子视图还是指令,都由它们自己的独立控制器处理。 这是处理 OP 在 Angular 中描述为“所有这些东西”的正确方法。
现在,您需要一种在一个事件中触发事件的方法,该事件可由任何其他事件响应。 如果您定义了一个服务,比如“pageEventService”,它公开一个函数来启动/触发事件“togglePanel”,以及一个保存状态的属性 - “panelIsVisible”,您可以在需要触发的任何地方引用该服务事件,并在面板中引用它以响应该值。
.controller('SomeControllerThatCanTriggerEvent', function(pageEventService) {
var model = this;
model.togglePanel = pageEventService.togglePanel;
});
在此控制器控制的标记中的某处...
<a ng-click="model.togglePanel()">Toggle the Panel</a>
在面板控制器中...
.controller('PanelController', function(pageEventService) {
var model = this;
model.panelIsVisible = pageEventService.panelIsVisible;
});
并在面板标记中...
<div id="TheAlmightyPanel" ng-show="model.panelIsVisible">... cool stuff here ...</div>
这比 rootscope 消息传递更清晰,因为您可以明确说明 pageEventService 可以做什么以及谁引用它。 你可以在视图、子视图和指令中使用它 - 无论你需要它。
你正在做的事情可以在不接触 DOM 的情况下完成,使用内置的 angular 指令本身,这里我只是使用ng-show
指令,如果你想把特定的类放到它然后只使用ng-class
,以及任何动画可以仅作为 css 动画提供,并且通过包含ngAnimate
模块它变得更好,您可以使用添加的类名来提供 动画行为。
例子:-
<div class="main-wrapper" ng-app="myapp">
<div ng-controller="panelController as panel">
<a href="#" class="trigger" ng-click="panel.toggle($event)">Click here to see the panel</a>
<div ng-show="panel.show" class='panel'>
<!-- <div ng-class="{'show':panel.show}"> and define css rules for panel.show-->
Hey ! I was hidden !
</div>
</div>
</div>
在控制器panelController
控制器中
angular.module('app').controller('panelController', function($scope){
var vm = this;
vm.show = false;
this.toggle = function($event){
$event.preventDefault();
vm.show = !vm.show;
}
});
我在这里只是使用控制器作为语法,如果您愿意,您也可以使用 $scope ,您甚至可以将其转换为指令。
根据您的问题更新进行编辑:
创建控制器并在需要时使用内置的 angular 指令没有什么不好,而不是在您确实不需要时使用 jquery/手动 dom 操作。
<body>
<div class="main-wrapper" ng-app="myapp" ng-controller="mainController as main">
<div class="app">
<div class="many-things">
[...]
<a href="#" class="trigger" ng-click="main.togglePanel($event)">Click here to see the panel</a>
[...]
</div>
</div><!-- .app -->
<div id="floatingpanel" ng-show="panel.show">
Hey ! I was hidden !
</div>
</div> <!-- #mainwrapper -->
</body>
这可能是您遇到的错误答案,因为您似乎不打算创建控制器或重新设计视图。
.directive('togglePanel', function(jQuery){
return {
restrict: 'A',
link:function(scope, elm, attr){
elm.on('click', handleToggle);
scope.$on('$destroy', function(){
elm.off('click', handleToggle);
});
function handleToggle(e){
var $target = jQuery(attr.togglePanel);//Get the target
//Do what you want to do with the target
}
}
}
}).constant('jQuery', window.jQuery);
并将其用作:
<a href="#" class="trigger" toggle-panel="#floatingPanel">Click here to see the panel</a>
好的 ! 感谢@PSL,我明白如果我在我的 ng-app 元素上设置一个控制器,这不是问题。
<div class="main-wrapper" ng-app="myapp" ng-controller="mainController as main">
我认为这是一个不好的做法......
有了这个“mainController”,我可以轻松地与我的 2 个元素进行交互:通过ng-click
与链接进行交互,通过ng-class
(或ng-show
等)与面板进行交互。我看不到更好的方法。 如果我避免使用这个“mainController”,我可以制定一个指令,但要触摸我的面板,它会迫使我访问范围之外的 DOM...
我绝对必须将我的想法从 jquery 方式转变为 angular 方式( 此链接可以提供帮助)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.