使用 jQuery 加载 Angular 会导致无法调用脚本 onload 回调
Loading Angular with jQuery causes a failure to invoke script onload callback
我想动态加载 JavaScript 库,例如 D3.js,使用 Angular 服务,例如:
function factoryD3Loading ($q, $document, $rootScope, $window) {
var d = $q.defer();
var script = $document[0].createElement('script');
script.type = 'text/javascript';
script.async = 'async';
script.src = 'https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js';
script.onload = function () {
$rootScope.$apply(function () {
d.resolve($window.d3);
});
};
$document.find('body').append(script);
return d.promise;
}
效果很好除非我用jQuery加载Angular而不是让它默认使用内置的jqLite。据我所知,当 Angular 使用 jQuery 时,根本不会调用 onload
回调。当 Angular 仅使用 jqLite 时肯定会调用它。
这是一个 non-working fiddle using jQuery, and here's a working fiddle without jQuery。请注意,除了是否加载 jQuery 之外,它们是相同的。
所以,一个分为两部分的问题:
为什么使用 jQuery 会导致这种行为差异?
如何纠正或解决这种 with-jQuery 行为?
至于为什么,我的猜测是 jqLite 以某种方式配置了摘要周期,而 Angular 没有(或不能?)为 jQuery 配置。如果这个猜测是准确的,那么这种行为似乎不一致且奇怪到成为错误的程度(在 Angular 中)。
至于如何,我认为(但尚未测试)我可以在 Angular 之后加载 jQuery 并做一些丑陋的 unwrap/rewrap 到 "convert" jqLite对象在我需要时拥有 jQuery 的完整 API。如果存在的话,我更喜欢一种更简洁的方法。
这不是 Angular 中的错误...这是因为 jQuery.append 以特殊方式处理脚本元素,基本上是在脚本上加载任何 src
URL元素分别通过 jQuery Ajax。 load
然后在 window
上触发,而不是在脚本元素上触发。 jqLite.append 没有模仿 jQuery.append 的这一方面。
解决方案是使用 DOM 而不是 angular.element 附加:
function factoryD3Loading ($q, $document, $rootScope, $window) {
var d = $q.defer();
var script = $document[0].createElement('script');
script.type = 'text/javascript';
script.async = 'async';
script.src = 'https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js';
script.onload = function () {
$rootScope.$apply(function () {
d.resolve($window.d3);
});
};
$document[0].body.appendChild(script); // DOM, not angular.element
return d.promise;
}
通过此更改,jqLite-Angular 和 jQuery-Angular 之间的行为是一致的。
我想动态加载 JavaScript 库,例如 D3.js,使用 Angular 服务,例如:
function factoryD3Loading ($q, $document, $rootScope, $window) {
var d = $q.defer();
var script = $document[0].createElement('script');
script.type = 'text/javascript';
script.async = 'async';
script.src = 'https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js';
script.onload = function () {
$rootScope.$apply(function () {
d.resolve($window.d3);
});
};
$document.find('body').append(script);
return d.promise;
}
效果很好除非我用jQuery加载Angular而不是让它默认使用内置的jqLite。据我所知,当 Angular 使用 jQuery 时,根本不会调用 onload
回调。当 Angular 仅使用 jqLite 时肯定会调用它。
这是一个 non-working fiddle using jQuery, and here's a working fiddle without jQuery。请注意,除了是否加载 jQuery 之外,它们是相同的。
所以,一个分为两部分的问题:
为什么使用 jQuery 会导致这种行为差异?
如何纠正或解决这种 with-jQuery 行为?
至于为什么,我的猜测是 jqLite 以某种方式配置了摘要周期,而 Angular 没有(或不能?)为 jQuery 配置。如果这个猜测是准确的,那么这种行为似乎不一致且奇怪到成为错误的程度(在 Angular 中)。
至于如何,我认为(但尚未测试)我可以在 Angular 之后加载 jQuery 并做一些丑陋的 unwrap/rewrap 到 "convert" jqLite对象在我需要时拥有 jQuery 的完整 API。如果存在的话,我更喜欢一种更简洁的方法。
这不是 Angular 中的错误...这是因为 jQuery.append 以特殊方式处理脚本元素,基本上是在脚本上加载任何 src
URL元素分别通过 jQuery Ajax。 load
然后在 window
上触发,而不是在脚本元素上触发。 jqLite.append 没有模仿 jQuery.append 的这一方面。
解决方案是使用 DOM 而不是 angular.element 附加:
function factoryD3Loading ($q, $document, $rootScope, $window) {
var d = $q.defer();
var script = $document[0].createElement('script');
script.type = 'text/javascript';
script.async = 'async';
script.src = 'https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js';
script.onload = function () {
$rootScope.$apply(function () {
d.resolve($window.d3);
});
};
$document[0].body.appendChild(script); // DOM, not angular.element
return d.promise;
}
通过此更改,jqLite-Angular 和 jQuery-Angular 之间的行为是一致的。