【问题标题】:Download script with dynamic src using Angular使用 Angular 下载带有动态 src 的脚本
【发布时间】:2014-04-26 15:56:57
【问题描述】:

Angular 提供了通过ng-include 动态加载具有动态名称的模板的方法。该部分中的内联 JS 和 CSS 可以正常加载,但是没有一个好的方法来下载带有动态 url 的脚本。我们需要下载脚本,相对于 .html 部分调用它们的路径。 (即,我们有一个包含文件的目录,并希望 .html 文件声明脚本等它需要自己)。

AngularJS: How to make angular load script inside ng-include? 不同,后者在动态包含的部分中加载带有静态 src 的脚本,我想在动态包含的部分中包含动态创建脚本的 src,使用插值或运行它角函数。

例如,我可能会从一个目录动态地将部分加载到我的应用程序中,该目录中还有几个部分依赖的其他资源。我不想单独下载所有文件,而是想将该逻辑保留在部分中。我意识到浏览器无法做到这一点,所以我将使用ng-src 并允许 Angular 在这里完成繁重的工作。而不是解析相对于部分的每个脚本 src 标记,所以我将使用一个函数来生成 url,如下所示:

<script type="application/javascript" ng-src="prefixUrl('myUrl.js')"></script>

我该怎么做?

【问题讨论】:

    标签: javascript angularjs lazy-loading


    【解决方案1】:

    Here is a gist

    请注意,这将覆盖 angular 中的本机脚本指令(检查脚本标签中的模板)。您可以重命名指令,但我们不需要该功能(无论如何,我们将这些服务/指令注入到页面上新启动的应用程序中)。

    这假设您有某种方式可以动态下载脚本。我们正在使用 $script,但 jquery 或其他也可以使用,只需相应地更新服务即可。

    您可以轻松地重写脚本指令来为 url 本身添加前缀(通过 attrs.ngSrc),而不是使用下面使用函数 prefixUrl 的内容。

    我添加了一个事件“WidgetContentLoaded”(易于更改),一旦下载了所有脚本,就会触发该事件。

    Javascript

    angular.module('myApp')
    .run(function ($rootScope) {
        $rootScope.mixin = function(urls) {
    
            if (angular.isUndefined(urls) || urls == '') {
                return $q.when('no mixin url');
            }
    
            var deferred = $q.defer();
    
            //timeout our requests at 5 seconds
            var timeoutPromise = $timeout(function() { deferred.reject(null) }, 5000);
    
            //assume that $script or some other way of downloading scripts is present
            $script(urls, function() {
                $timeout.cancel(timeoutPromise);
                $rootScope.$safeApply(deferred.resolve(urls));
            });
    
            return deferred.promise;
        };
    
        $document.on('WidgetContentLoaded', function () {
            //put more interesting logic here... this is like $(document).ready() but for your included partial
            console.log('yay we loaded your scripts');
        });
    
    })
    .service('lazyScripts', ['$q', '$timeout', '$document', function ($q, $timeout, $document) {
    
        var promises = [];
    
        this.register = function (url) {
            promises.push($clotho.extensions.mixin(url));
        };
    
        $timeout(function() {
            $q.all(promises).then(function() {
                //broadcast event
                $document.triggerHandler('WidgetContentLoaded');
            })
        });
    }])
    .directive('script', function($parse, $rootScope) {
        return {
            restrict: 'E',
            terminal: true,
            compile: function(element, attr) {
                if (attr.ngSrc) {
                    var scriptUrl = $parse(attr.ngSrc)($rootScope);
                     lazyScripts.register(scriptUrl);
                }
            }
        };
    });
    

    还有你的 HTML

    <script type="application/javascript" ng-src="prefixUrl('inlineCalledScript.js')"></script>
    
    <style type="text/css">
        .greenListItem {
            color: #44bb44;
        }
    </style>
    
    <ul>
        <li>This is a dynamically loaded template.</li>
        <li>Note that angular must already be bootstrapped, with the new script directive above. This will not work in your index.html file</li>
        <li class="greenListItem">Inline CSS works!</li>
    </ul>
    
    <!-- this would work without problems -->
    <div ng-include="prefixUrl('anotherPartial.html')"></div>
    

    【讨论】:

    • 免责声明 - 我没有在普通应用程序中测试过这个。我正在使用 $provider 和 $compileProvider 将它们插入到新引导的应用程序中,这在这种情况下确实有效。
    • 什么是$clotho?它似乎没有在您的 lazyScripts 服务中定义。
    • 糟糕。你说得对。它基本上只是一个 javascript 下载的包装器,它返回一个 promise 而不是接受回调,它不会多次下载相同的路径。
    • 我无法再访问该代码。您可以使用像 $script (github.com/ded/script.js) 或任何其他 JS 加载器之类的库,然后将其包装以便它返回一个承诺(即包装在一个承诺中,在回调中解析)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多