5

我编写了 JavaScript 库来使用FileSaver.js及其相关库。但是,当有人想使用我的库时,我不想总是加载 FileSaver.js。而且我不想强迫他们用script标签本身加载所有各种与 FileSaver 相关的 JavaScript 库(或者甚至加载我的一个可以做到这一点的库)。

相反,我更喜欢这样的东西。当他们调用我的createImage函数时,它首先执行以下操作:

function createImage(image, name) {
  if (typeof(saveAs) !== 'function') {
    var element = document.createElement('script');
    element.async = false;
    element.src = 'FileSaver.js';
    element.type = 'text/javascript';
    (document.getElementsByTagName('head')[0]||document.body).appendChild(element);
  }
  // now do the saveImage code
}

问题是,在上面之后,saveAs功能仍然没有定义。只有createImage完成之后saveAs才最终定义了函数。

4

5 回答 5

9

整体解决方案是使用模块系统。AMD 可能是最常用的浏览器异步代码加载系统。AMD 只是一个规范,但像require.js这样的东西是使用 AMD 模块的非常流行的工具。

这个想法是您可以定义模块之间的依赖关系,并且 require.js 将在需要时获取它们。总体思路是模仿其他语言(如 java、C# 或 python)的导入/命名空间功能。“代码共享”我认为是这个词吗?

只需将所有代码放在一个回调函数中,该函数在加载依赖项后运行,因此您可以确保存在所需的对象和方法。

2015 年更新

只是一个附录。虽然上面的信息仍然正确,但前端代码管理正在迅速转向像 Webpack 和 Browserify 这样的解决方案,它们捆绑和连接任何模块类型的代码,并且都具有动态代码加载功能(webpack 称之为代码拆分)。再加上用于依赖管理的 npm 呈指数增长,AMD 开始变得不那么重要了。

于 2013-11-04T02:03:48.480 回答
1

好的,您需要做的是听脚本完成加载。不幸的是,对于 ie<7,此代码存在一些错误。

这是 MootoolsAsset.javascript加载脚本并在完成时调用回调的方式:

var loadScript = function (source, properties) {
    properties || (properties = {});
    var script = document.createElement('script');
    script.async = true;
    script.src = source;
    script.type = 'text/javascript';
    var doc = properties.document || document, load = properties.onload || properties.onLoad;
    return delete properties.onload, delete properties.onLoad, delete properties.document, 
    load && (script.addEventListener ? script.addEventListener("load", load) : script.attachEvent("readystatechange", function() {
        [ "loaded", "complete" ].indexOf(this.readyState) >= 0 && load.call(this);
    })), script.set(properties).appendChild(doc.head);
}

现在loadImage您可以按如下方式加载文件库:

function createImage(image, name) {
  function createImg() {
      // now do the saveImage code
  }
  if (typeof(saveAs) !== 'function') {
     loadScript("FileSaver.js", {onLoad: createImg});//load library
  }
  else {
     createImg();
  }
}

应该适用于大多数浏览器。

于 2013-11-04T01:07:43.530 回答
0

使用 Head.js:http ://headjs.com/

它将按需加载脚本。

于 2013-11-04T01:11:50.877 回答
0

所以我同意 AMD 评论(不能将代码阻塞放入评论中,嗯……)

这是我为 FileSaver.js 所做的

首先在我的 requirejs config / main.js :

(function() {
    // REMEMBER TO DUPLICATE CHANGES IN GRUNTFILE.JS
    requirejs.config({
        paths: {
            "jquery": "PATH/jquery.min", // NO .js
            "lib.filesaver" : "PATH/FileSaver", // NO .js
            "shim.blob" : "PATH/Blob" // NO .js
        },
        shim: {
            "lib.filesaver": {deps: ["shim.blob"]}
        }
    });

    define([
        "jquery"
    ], function(
        $
        ) {
            $(document).ready(function() {
                // start up code...
            });
        return {};
        });
})();

然后我将 Blob.js/jquery 和 Filersaver 放在正确的位置

我还为 pre IE10 创建了一个 IEShim

define([], function () {
    /**
     * @class IEshims
     * container for static IE shim functions
     */
    var IEShims = {
        /**
         * saveFile, pops up a built in javascript file as a download
         * @param {String} filename, eg doc.csv
         * @param {String} filecontent eg "this","is","csv"
         */
        saveAs: function (filename, filecontent, mimetype ) {
            var w = window.open();
            var doc = w.document;
            doc.open( mimetype,'replace');
            doc.charset = "utf-8";
            doc.write(filecontent);
            doc.close();
            doc.execCommand("SaveAs", null, filename);
        }
    };
    return IEShims;
});

最后,当我想使用 Filesaver 时,将其设为必需(与 IEShim 一起用于不良浏览器)

define([
"lib.filesaver",
"IEShims"
],
function (
    FileSaver, // it's empty, see saveAs global var
    IEShims
    ) {
...
    var fileName = "helloworld.txt";
    var fileContents = "Me haz file contents, K Thx Bye";
    var mimeType = "text/plain";
    if(saveAs) {
        var blob = new Blob(
            [fileContents],
            {type: mimeType + ";charset=" + document.characterSet}
        );
        saveAs(blob, fileName);
    } else {
        IEShims.saveAs(fileName, fileContents,mimeType );
    }
    ...
};
于 2014-03-20T09:55:10.773 回答
0

最简单的答案是将您的代码放在您创建onload的标签的处理程序中:script

<script>
  var firstScript = document.getElementsByTagName('script')[0],
      js = document.createElement('script');
  js.src = 'https://cdnjs.cloudflare.com/ajax/libs/Snowstorm/20131208/snowstorm-min.js';
  js.onload = function () {
    // do stuff with your dynamically loaded script
    snowStorm.snowColor = '#99ccff';
  };
  firstScript.parentNode.insertBefore(js, firstScript);
</script>

以这种方式动态加载脚本由 Facebook 完成

于 2015-07-08T02:45:46.627 回答