gpt4 book ai didi

angularjs - AngularJS 加载完成时发送事件

转载 作者:行者123 更新时间:2023-12-03 04:39:40 26 4
gpt4 key购买 nike

想知道当所有指令都完成编译/链接时,检测页面加载/引导完成的最佳方法是什么。

有什么事件吗?我应该重载引导函数吗?

最佳答案

只是一个预感:为什么不看看 ngCloak 指令是如何做到的?很明显,ngCloak 指令设法在内容加载后显示内容。我打赌看 ngCloak 会得到确切的答案......

1 小时后编辑:
好吧,我看了ngCloak而且真的很短。这显然意味着编译函数不会被执行,直到 {{template}} 表达式被评估(即它加载的模板),因此 ngCloak 指令的功能很好。

我有根据的猜测是只制作一个与 ngCloak 一样简单的指令,然后在你的编译函数中做你想做的任何事情。 :) 将指令放在应用程序的根元素上。您可以调用类似 myOnload 的指令并将其用作属性 my-onload。一旦模板被编译(计算表达式和加载子模板),compile 函数就会执行。

编辑,23 小时后:
好的,所以我做了一些研究,我也asked my own question .我问的这个问题和这个问题有间接的关系,但巧合的是我找到了解决这个问题的答案。

答案是您可以创建一个简单的指令并将您的代码放在指令的链接函数中,该函数(对于大多数用例,如下所述)将在您的元素准备好/加载时运行。基于 Josh's description of the order in which compile and link functions are executed ,

if you have this markup:

<div directive1>
<div directive2>
<!-- ... -->
</div>
</div>

Then AngularJS will create the directives by running directive functions in a certain order:

directive1: compile
directive2: compile
directive1: controller
directive1: pre-link
directive2: controller
directive2: pre-link
directive2: post-link
directive1: post-link

By default a straight "link" function is a post-link, so your outer directive1's link function will not run until after the inner directive2's link function has ran. That's why we say that it's only safe to do DOM manipulation in the post-link. So toward the original question, there should be no issue accessing the child directive's inner html from the outer directive's link function, though dynamically inserted contents must be compiled, as said above.



由此我们可以得出结论,当一切准备就绪/编译/链接/加载时,我们可以简单地创建一个指令来执行我们的代码:
    app.directive('ngElementReady', [function() {
return {
priority: -1000, // a low number so this directive loads after all other directives have loaded.
restrict: "A", // attribute only
link: function($scope, $element, $attributes) {
console.log(" -- Element ready!");
// do what you want here.
}
};
}]);

现在你可以做的是把 ngElementReady 指令放到应用程序的根元素上,然后 console.log加载时会触发:
<body data-ng-app="MyApp" data-ng-element-ready="">
...
...
</body>

就是这么简单!只需制定一个简单的指令并使用它。 ;)

您可以进一步自定义它,以便它可以通过添加 $scope.$eval($attributes.ngElementReady); 来执行表达式(即函数)。给它:
    app.directive('ngElementReady', [function() {
return {
priority: Number.MIN_SAFE_INTEGER, // execute last, after all other directives if any.
restrict: "A",
link: function($scope, $element, $attributes) {
$scope.$eval($attributes.ngElementReady); // execute the expression in the attribute.
}
};
}]);

然后你可以在任何元素上使用它:
<body data-ng-app="MyApp" data-ng-controller="BodyCtrl" data-ng-element-ready="bodyIsReady()">
...
<div data-ng-element-ready="divIsReady()">...<div>
</body>

只需确保在元素所在的范围(在 Controller 中)中定义了函数(例如 bodyIsReady 和 divIsReady)。

注意事项:我说过这适用于大多数情况。使用某些指令时要小心,比如 ngRepeat 和 ngIf。他们创建自己的范围,您的指令可能不会触发。例如,如果您将我们的新 ngElementReady 指令放在一个也有 ngIf 的元素上,并且 ngIf 的条件评估为 false,那么我们的 ngElementReady 指令将不会被加载。或者,例如,如果您将我们的新 ngElementReady 指令放在一个也有 ngInclude 指令的元素上,如果 ngInclude 的模板不存在,我们的指令将不会被加载。您可以通过确保嵌套指令而不是将它们全部放在同一个元素上来解决其中的一些问题。例如,通过这样做:
<div data-ng-element-ready="divIsReady()">
<div data-ng-include="non-existent-template.html"></div>
<div>

而不是这个:
<div data-ng-element-ready="divIsReady()" data-ng-include="non-existent-template.html"></div>

ngElementReady 指令将在后面的例子中被编译,但它的链接函数不会被执行。注意:指令总是被编译,但它们的链接函数并不总是根据上述特定场景执行。

几分钟后编辑:

哦,要完全回答这个问题,您现在可以 $emit$broadcast您的事件来自 ng-element-ready 中执行的表达式或函数属性。 :) 例如:
<div data-ng-element-ready="$emit('someEvent')">
...
<div>

编辑,甚至几分钟后:

@satchmorun 的答案也有效,但仅适用于初始负载。这是一个 very useful SO question描述事物执行的顺序,包括链接函数, app.run , 和其他人。因此,根据您的用例, app.run可能不错,但不适用于特定元素,在这种情况下,链接功能会更好。

编辑,五个月后,太平洋标准时间 10 月 17 日 8:11:

这不适用于异步加载的部分。您需要将簿记添加到您的部分中(例如,一种方法是让每个部分跟踪其内容何时完成加载然后发出一个事件,以便父作用域可以计算加载了多少部分并最终执行它需要的操作在加载所有部分后执行)。

编辑,太平洋标准时间 10 月 23 日晚上 10:52:

我做了一个简单的指令,用于在加载图像时触发一些代码:
/*
* This img directive makes it so that if you put a loaded="" attribute on any
* img element in your app, the expression of that attribute will be evaluated
* after the images has finished loading. Use this to, for example, remove
* loading animations after images have finished loading.
*/
app.directive('img', function() {
return {
restrict: 'E',
link: function($scope, $element, $attributes) {
$element.bind('load', function() {
if ($attributes.loaded) {
$scope.$eval($attributes.loaded);
}
});
}
};
});

编辑,太平洋标准时间 10 月 24 日上午 12:48:

我改进了我原来的 ngElementReady指令并将其重命名为 whenReady .
/*
* The whenReady directive allows you to execute the content of a when-ready
* attribute after the element is ready (i.e. done loading all sub directives and DOM
* content except for things that load asynchronously like partials and images).
*
* Execute multiple expressions by delimiting them with a semi-colon. If there
* is more than one expression, and the last expression evaluates to true, then
* all expressions prior will be evaluated after all text nodes in the element
* have been interpolated (i.e. {{placeholders}} replaced with actual values).
*
* Caveats: if other directives exists on the same element as this directive
* and destroy the element thus preventing other directives from loading, using
* this directive won't work. The optimal way to use this is to put this
* directive on an outer element.
*/
app.directive('whenReady', ['$interpolate', function($interpolate) {
return {
restrict: 'A',
priority: Number.MIN_SAFE_INTEGER, // execute last, after all other directives if any.
link: function($scope, $element, $attributes) {
var expressions = $attributes.whenReady.split(';');
var waitForInterpolation = false;

function evalExpressions(expressions) {
expressions.forEach(function(expression) {
$scope.$eval(expression);
});
}

if ($attributes.whenReady.trim().length == 0) { return; }

if (expressions.length > 1) {
if ($scope.$eval(expressions.pop())) {
waitForInterpolation = true;
}
}

if (waitForInterpolation) {
requestAnimationFrame(function checkIfInterpolated() {
if ($element.text().indexOf($interpolate.startSymbol()) >= 0) { // if the text still has {{placeholders}}
requestAnimationFrame(checkIfInterpolated);
}
else {
evalExpressions(expressions);
}
});
}
else {
evalExpressions(expressions);
}
}
}
}]);

例如,像这样使用它来触发 someFunction当一个元素被加载和 {{placeholders}}尚未更换:
<div when-ready="someFunction()">
<span ng-repeat="item in items">{{item.property}}</span>
</div>
someFunction将在所有 item.property 之前调用占位符被替换。

根据需要计算尽可能多的表达式,并制作最后一个表达式 true等待 {{placeholders}}要这样评价:
<div when-ready="someFunction(); anotherFunction(); true">
<span ng-repeat="item in items">{{item.property}}</span>
</div>
someFunctionanotherFunction将在 {{placeholders}} 之后被解雇已被替换。

这仅适用于第一次加载元素时,而不适用于 future 的更改。如果 $digest,它可能无法按预期工作在最初替换占位符后继续发生($digest 最多可以发生 10 次,直到数据停止更改)。它将适用于绝大多数用例。

编辑,太平洋标准时间 10 月 31 日晚上 7:26:

好吧,这可能是我最后一次也是最后一次更新了。这可能适用于 99.999 个用例:
/*
* The whenReady directive allows you to execute the content of a when-ready
* attribute after the element is ready (i.e. when it's done loading all sub directives and DOM
* content). See: https://stackoverflow.com/questions/14968690/sending-event-when-angular-js-finished-loading
*
* Execute multiple expressions in the when-ready attribute by delimiting them
* with a semi-colon. when-ready="doThis(); doThat()"
*
* Optional: If the value of a wait-for-interpolation attribute on the
* element evaluates to true, then the expressions in when-ready will be
* evaluated after all text nodes in the element have been interpolated (i.e.
* {{placeholders}} have been replaced with actual values).
*
* Optional: Use a ready-check attribute to write an expression that
* specifies what condition is true at any given moment in time when the
* element is ready. The expression will be evaluated repeatedly until the
* condition is finally true. The expression is executed with
* requestAnimationFrame so that it fires at a moment when it is least likely
* to block rendering of the page.
*
* If wait-for-interpolation and ready-check are both supplied, then the
* when-ready expressions will fire after interpolation is done *and* after
* the ready-check condition evaluates to true.
*
* Caveats: if other directives exists on the same element as this directive
* and destroy the element thus preventing other directives from loading, using
* this directive won't work. The optimal way to use this is to put this
* directive on an outer element.
*/
app.directive('whenReady', ['$interpolate', function($interpolate) {
return {
restrict: 'A',
priority: Number.MIN_SAFE_INTEGER, // execute last, after all other directives if any.
link: function($scope, $element, $attributes) {
var expressions = $attributes.whenReady.split(';');
var waitForInterpolation = false;
var hasReadyCheckExpression = false;

function evalExpressions(expressions) {
expressions.forEach(function(expression) {
$scope.$eval(expression);
});
}

if ($attributes.whenReady.trim().length === 0) { return; }

if ($attributes.waitForInterpolation && $scope.$eval($attributes.waitForInterpolation)) {
waitForInterpolation = true;
}

if ($attributes.readyCheck) {
hasReadyCheckExpression = true;
}

if (waitForInterpolation || hasReadyCheckExpression) {
requestAnimationFrame(function checkIfReady() {
var isInterpolated = false;
var isReadyCheckTrue = false;

if (waitForInterpolation && $element.text().indexOf($interpolate.startSymbol()) >= 0) { // if the text still has {{placeholders}}
isInterpolated = false;
}
else {
isInterpolated = true;
}

if (hasReadyCheckExpression && !$scope.$eval($attributes.readyCheck)) { // if the ready check expression returns false
isReadyCheckTrue = false;
}
else {
isReadyCheckTrue = true;
}

if (isInterpolated && isReadyCheckTrue) { evalExpressions(expressions); }
else { requestAnimationFrame(checkIfReady); }

});
}
else {
evalExpressions(expressions);
}
}
};
}]);

像这样使用它
<div when-ready="isReady()" ready-check="checkIfReady()" wait-for-interpolation="true">
isReady will fire when this {{placeholder}} has been evaluated
and when checkIfReady finally returns true. checkIfReady might
contain code like `$('.some-element').length`.
</div>

当然,它可能会被优化,但我会就此搁笔。 requestAnimationFrame很好。

关于angularjs - AngularJS 加载完成时发送事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14968690/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com