我的目标是创建一个可以应用于给定元素的指令,这样当单击该元素时,就会创建一个模态。我想创建模态并附加到body节点,该节点位于我的ng-app元素之外。由于页面上有多个应用程序的要求,我无法在<html>
或<body>
标记上添加ng-app。然而,对于正确的z定位,我会尽可能地将模态元素置于体内。
我的指示如下:
var module = angular.module('Test', ['ngAnimate']);
module.directive('modal', function($compile, $animate) {
function link(scope, element, attr) {
element.on('click', function () {
var modal = $compile('<div class="modal"></div>')(scope);
scope.$apply(function () {
$animate.enter(modal, angular.element(document.body));
});
});
}
return {
link: link,
scope: {}
};
});
当我使用$animate.enter
将modal
附加到正文时,会附加它,但动画不会运行。我的HTML看起来像这样:
<body>
<div ng-app="Test">
<button modal>Open Modal</button>
</div>
</body>
如果我将ng-app
从div
移动到body
,则动画可以正常运行。但是我无法做到这一点,因为我需要选择在给定页面上放置多个ng-app
。
有可能吗?
工作(或不工作)的例子:
答案 0 :(得分:2)
简短的回答是:不,你不能 (至少Angular似乎不是为了允许它而设计的)。
更长的答案是:不,你不能。原因如下:
原因是$animate
目前的实施方式:
在你的情况下,它将elements =添加到DOM(特别是document.body
),然后检查是否应继续使用动画特定的东西(或者动画是否为#34;禁用&# 34)
。
根据源代码,检查动画是否被禁用的功能&#34;是:
function animationsDisabled(element, parentElement) {
if (rootAnimateState.disabled) return true;
if(isMatchingElement(element, $rootElement)) {
return rootAnimateState.disabled || rootAnimateState.running;
}
do {
//the element did not reach the root element which means that it
//is not apart of the DOM. Therefore there is no reason to do
//any animations on it
if(parentElement.length === 0) break;
var isRoot = isMatchingElement(parentElement, $rootElement);
var state = isRoot ? rootAnimateState : parentElement.data(NG_ANIMATE_STATE);
var result = state && (!!state.disabled || state.running || state.totalActive > 0);
if(isRoot || result) {
return result;
}
if(isRoot) return true;
}
while(parentElement = parentElement.parent());
return true;
}
正如您所看到的,由于您的模态不是$ rootElement的子项(但兄弟),isRoot
将始终为false,do-while
循环将一直运行,直到没有父项 - 元件。此时if(parentElement.length === 0) break;
将中断循环,函数将返回true
,从而取消动画。
最长的答案是:取决于(你需要它多么糟糕)。
可用选项(我能想到)是:
接受你的命运并找到其他方式(除了$animate
)来执行你的动画。
创建自己的angular-animate分支并更改一行代码,这样即使target-element不是$ rootElement的子代,动画也不会被取消。
如果您喜欢危险地生活:如果我们暂时换掉$ rootElement&#34;该怎么办? ?
我尝试了各种方法(在本答案的范围之外)和我唯一可以工作的方法(?),交换了与jqLite对象相关联的HTML元素(即$rootElement[0]
)。
我将功能包装在服务中(以及一些便利功能,例如在一段时间后恢复原始元素):
module.factory('myRootElement', function ($rootElement, $timeout) {
/* Save the original element for reference */
var original = $rootElement[0];
/* Fake the $rootElement for the specified
* period of time (in milliseconds) */
function fakeForMillis(millis) {
$rootElement[0] = document.body;
$timeout(function () {
$rootElement[0] = original;
}, millis || 0);
}
/* Return the Service object */
return {
fakeForMillis: fakeForMillis
};
});
最后,您只需要临时交换动画的$rootElement
即可。 (不幸的是,你必须指定动画所需的时间,但我敢打赌,有更好的方法可以通过编程方式找到它 - 再次超出了这个答案的范围。)
myRootElement.fakeForMillis(1000);
$animate.enter(modal, angular.element(document.body));
另请参阅此 short demo 。
<子> 我不知道我在说什么,我决不会调查这种方法的后果,所以请自行承担风险,如果出现奇怪的事情,请不要感到惊讶。 子>