带有Typescript的Angular2,如何在延迟加载模块中使用Plupload CDN脚本文件?

Angular2 with Typescript, how to use Plupload CDN script file in lazy-loaded module?

我想在 Angular2 组件中使用 Plupload,并从 CDN 访问 Plupload JavaScript 文件。我希望它特定于一个组件,以便在不需要时不会下载它 - 我希望它位于延迟加载的模块中。我怎样才能做到这一点?

现在已在此页面上完整回答!

这个任务的结果如下:

  1. 将 Plupload 与 Angular 2 和 TypeScript
  2. 结合使用的示例
  3. 如何在 Angular 2
  4. 中从 CDN 延迟加载脚本
  5. 如何在惰性加载模块中使用 Plupload 的示例
  6. 如何在Angular2

    中使用延迟加载的脚本

    (查看编辑历史,了解曾经构成此问题的丑陋细节。)

在这种方法中不需要任何额外的加载器模块。

查看示例(检查 Woohoo 的控制台):http://plnkr.co/edit/gfUs4Uhe8kMGzPxwpBay?p=preview 更新了 plunkerhttps://plnkr.co/edit/leG062tg7uX8sLrA0i2i?p=preview

您可以通过将脚本 url 添加到您的文档来延迟加载一些 js:

创建 my-lazy-load.function.ts:

export function lazyload(url) {
    // based on https://friendlybit.com/js/lazy-loading-asyncronous-javascript/

    let scripts = document.getElementsByTagName('script');
    for (let i = scripts.length; i--;) {
        if (scripts[i].src.match(url)) return true;
    }

    let s = document.createElement('script');
    s.type = 'text/javascript';
    s.async = true;
    s.src = url;
    let x = document.getElementsByTagName('script')[0];
    x.parentNode.insertBefore(s, x);

    return true;
}

在您要添加 plupload 的组件中:

import {lazyload} from "./my-lazy-load.function.ts";

export class MyComponent  implements OnInit {

    pluploadInterval:number = null;
    hasPlupload: boolean = false;

    ngOnInit() {
        lazyload("https://cdnjs.cloudflare.com/ajax/libs/plupload/2.3.1/plupload.full.min.js");

        this.pluploadInterval = window.setInterval(()=>{
            if(window.plupload) { // you can check existence of plupload object any way you want

                // Woohoo, I am ready to be used

                this.hasPlupload = true; // everything is run outside ngZone, wrap it if angular2 is not reacting to changes, or change window.setInterval to setInterval
                window.clearInterval(this.pluploadInterval); // don't forget to clean interval
            }
        }, 100); // timeinterval can vary 
....

浏览器会自动加载。

注意if(plupload)它假定脚本添加了全局对象plupload(我不知道它是否真的添加了,检查你的工作示例在纯javascript)。因为它是 jquery 扩展,你可以像这样检查它的原型:jQuery test for whether an object has a method?

旧历史: @Reid 这里是 plunker:https://plnkr.co/edit/zDWWQbTQUSHBqCsrUMUi?p=preview plupload 实际上已加载,但添加到需要 define("plupload", ['./moxie'], extract); 我现在不确定如何从那里提取以及 require 属于哪个包......寻找正确模块加载器的代码属于plupload本身,这里是(来自plupload.dev.js):

if (typeof define === "function" && define.amd) {
    define("plupload", ['./moxie'], extract);
} else if (typeof module === "object" && module.exports) {
    module.exports = extract(require('./moxie'));
} else {
    global.plupload = extract(global.moxie);
}

我认为最好的办法是使用 Require.js 库,这样您就可以从组件中动态加载脚本。

小的权衡是您必须将这个 18KB 的库添加到您的 index.html 页面 (CDN),但是如果您的第 3 方库很大,这可以为您节省大量的加载。

我没有使用 plupload 的经验,所以我将以下 plunkr 放在一起,它使用从 CDN 绘制的外部动画库。 plunkr 为 0 - 100 之间的数字设置动画。

https://plnkr.co/edit/fJCtezsERYHOYplLh7Jo?p=preview


index.html

<script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.3/require.min.js"></script>

component.ts

ngOnInit(){
    // Dynamically loads the framework from the CDN.
    require(["https://cdnjs.cloudflare.com/ajax/libs/gsap/1.19.1/TweenLite.min.js"],
    // This function is then called ONCE LOAD IS COMPLETE
    function (common) {
      // Do greensock things
      var demo = {score:0},
      scoreDisplay = document.getElementById("scoreDisplay");

      //create a tween that changes the value of the score property of the demo object from 0 to 100 over the course of 20 seconds.
      var tween = TweenLite.to(demo, 20, {score:100, onUpdate:showScore})

      //each time the tween updates this function will be called.
      function showScore() {
        scoreDisplay.innerHTML = demo.score.toFixed(2);
      }  
    });
  }

我喜欢这种方法的一点是,在 require 的 onLoad 回调中,语法与库的正常实现没有变化,因此您只需将当前工作的代码复制粘贴到回调中即可.

以下是从 CDN 加载 Plupload 时创建延迟加载 Plupload 功能所需执行的操作的概述:

  1. 当需要该功能时(例如用户单击按钮或访问页面),动态添加一个 <script> 标签到页面以从 CDN 加载 Plupload 库。
  2. 等到库加载后再继续(否则您可能会收到 "plupload is undefined" 错误)。
  3. 显示 UI 以在您的 Angular 模板之一中与 Plupload 交互。在最简单的形式中,这个 UI 由两个按钮组成:"Select files" 和 "Upload files"。
  4. 初始化 Plupload 并将其连接到 UI。

完整的工作代码:https://plnkr.co/edit/4t39Rod4YNAOrHmZdxqc?p=preview

我的实现中请注意以下几点:

  • 关于#2。检查 Plupload 是否已完成加载的更好方法是轮询全局名称空间以查找 plupload 变量是否存在。只要 window.plupload 不存在,就意味着库还没有加载,我们不应该继续。为简单起见,我的代码只等待一秒钟然后继续。
  • 数字 4 可能有点棘手。 Plupload 大量使用直接 DOM 访问将其 API 连接到 HTML(例如 document.getElementById('filelist'))。这是 Angular 不鼓励的事情,您应该尽可能避免。更具体的直接DOM访问用在以下地方:
    • 告诉 Plupload 哪个 DOM 元素应该触发 "Select files" 对话框 (他们称之为 browse_button 配置选项)。为此,我无法避免直接 DOM 引用,我使用 @ViewChild 装饰器来获取 "Select Files" 按钮。
    • 在模板中显示选定的文件。 为此,我将 Plupload 语法转换为常规 Angular 语法。我将选定的文件推送到名为 fileList 的 class 属性,我使用标准 *ngFor.
    • 在模板中显示该文件
    • "Upload Files" 按钮会触发一些执行实际上传的代码,并刷新 UI 以显示上传进度。再一次,我使用事件绑定和数据绑定将其转换为常规 Angular 语法。

如果您有任何问题,请告诉我。