JavaScript中是否有类似于CSS中的
旧版本的JavaScript没有导入、包含或要求,因此开发了许多不同的方法来解决这个问题。
但是从2015年(ES6)开始,JavaScript就有了在Node中导入模块的ES6模块标准。,大多数现代浏览器也支持它。
为了与旧浏览器兼容,可以使用构建和/或转置工具。
ES6模块
从v8.5开始,ECMAScript (ES6)模块在Node.js中得到了支持,带有
1 2 3 4 | // module.mjs export function hello() { return"Hello"; } |
1 2 3 | // main.mjs import { hello } from 'module'; // or './module' let val = hello(); // val is"Hello"; |
ECMAScript模块在浏览器
自Safari 10.1、Chrome 61、Firefox 60和Edge 16以来,浏览器一直支持直接加载ECMAScript模块(不需要Webpack之类的工具)。检查当前在caniuse的支持。
1 2 3 4 | <script type="module"> import { hello } from './hello.mjs'; hello('world'); </script> |
1 2 3 4 5 6 | // hello.mjs export function hello(text) { const div = document.createElement('div'); div.textContent = `Hello ${text}`; document.body.appendChild(div); } |
更多信息请访问https://jakearchibald.com/2017/e-modules-inbrowsers/
动态导入浏览器动态导入让脚本根据需要加载其他脚本:
1 2 3 4 5 | <script type="module"> import('hello.mjs').then(module => { module.hello('world'); }); </script> |
更多信息请访问https://developers.google.com/web/updates/2017/11/dynamic-import
node . js要求
老式的模块导入方式,在Node中仍被广泛使用。是模块。出口/需要系统。
1 2 3 4 5 6 | // mymodule.js module.exports = { hello: function() { return"Hello"; } } |
1 2 3 | // server.js const myModule = require('./mymodule'); let val = myModule.hello(); // val is"Hello" |
JavaScript还可以通过其他方式在浏览器中包含不需要预处理的外部JavaScript内容。
AJAX加载您可以使用AJAX调用加载一个附加脚本,然后使用
获取加载
与动态导入一样,您可以使用
1 2 3 4 5 | fetchInject([ 'https://cdn.jsdelivr.net/momentjs/2.17.1/moment.min.js' ]).then(() => { console.log(`Finish in less than ${moment().endOf('year').fromNow(true)}`) }) |
jQuery加载
jQuery库提供了一行加载功能:
1 2 3 | $.getScript("my_lovely_script.js", function() { alert("Script loaded but not necessarily executed."); }); |
动态脚本加载
您可以将带有脚本URL的脚本标记添加到HTML中。为了避免jQuery的开销,这是一个理想的解决方案。
脚本甚至可以驻留在不同的服务器上。此外,浏览器会评估代码。
下面是一个例子:
1 2 3 4 5 6 | function dynamicallyLoadScript(url) { var script = document.createElement("script"); // create a script DOM node script.src = url; // set its src to the provided URL document.head.appendChild(script); // add it to the end of the head section of the page (could change 'head' to 'body' to add it to the end of the body section instead) } |
这个函数将在页面头部的末尾添加一个新的
这两种解决方案都在JavaScript crazy:动态脚本加载中进行了讨论和说明。
检测脚本何时执行现在,有一个大问题你必须知道。这样做意味着远程加载代码。现代web浏览器将加载文件并继续执行当前脚本,因为它们异步加载所有内容以提高性能。(这适用于jQuery方法和手动动态脚本加载方法。)
这意味着,如果直接使用这些技巧,在请求加载新加载的代码后,将无法在下一行使用新加载的代码,因为它仍然在加载中。
例如:
1 2 3 4 5 6 7 8 9 10 | var js = document.createElement("script"); js.type ="text/javascript"; js.src = jsFilePath; document.body.appendChild(js); var s = new MySuperObject(); Error : MySuperObject is undefined |
然后按F5重新加载页面。和它的工作原理!困惑……
那么该怎么做呢?
好吧,你可以使用作者在我给你的链接中建议的黑客技术。总之,对于赶时间的人,他在加载脚本时使用事件运行回调函数。因此,您可以使用远程库将所有代码放到回调函数中。例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | function loadScript(url, callback) { // Adding the script tag to the head as suggested before var head = document.head; var script = document.createElement('script'); script.type = 'text/javascript'; script.src = url; // Then bind the event to the callback function. // There are several events for cross browser compatibility. script.onreadystatechange = callback; script.onload = callback; // Fire the loading head.appendChild(script); } |
然后你写代码后,你想使用脚本加载在lambda函数:
1 2 3 | var myPrettyCode = function() { // Here, do whatever you want }; |
然后你运行所有这些:
1 | loadScript("my_lovely_script.js", myPrettyCode); |
注意,脚本可以在加载DOM之后执行,也可以在加载之前执行,这取决于浏览器以及是否包含
源代码合并/预处理
正如在这个答案的顶部所提到的,许多开发人员在他们的项目中使用构建/转置工具(如package、Webpack或Babel),允许他们使用即将到来的JavaScript语法,为旧的浏览器提供向后兼容性,组合文件,缩小,执行代码分割等。
如果有人正在寻找更高级的东西,请尝试RequireJS。您将获得附加的好处,比如依赖关系管理、更好的并发性和避免重复(即多次检索脚本)。
您可以在"模块"中编写JavaScript文件,然后将它们作为依赖项引用到其他脚本中。或者您可以使用RequireJS作为一个简单的"获取这个脚本"解决方案。
例子:
将依赖关系定义为模块:
some-dependency.js
1 2 3 4 5 6 7 | define(['lib/dependency1', 'lib/dependency2'], function (d1, d2) { //Your actual script goes here. //The dependent scripts will be fetched if necessary. return libraryObject; //For example, jQuery object }); |
js是您的"主"JavaScript文件,它依赖于某些依赖项
1 2 3 4 5 6 | require(['some-dependency'], function(dependency) { //Your script goes here //some-dependency.js is fetched. //Then your script is executed }); |
摘自GitHub README:
RequireJS loads plain JavaScript files as well as more defined modules. It is optimized for in-browser use, including in a Web Worker, but it can be used in other JavaScript environments, like Rhino and Node. It implements the Asynchronous Module API.
RequireJS uses plain script tags to load modules/files, so it should allow for easy debugging. It can be used simply to load existing JavaScript files, so you can add it to your existing project without having to re-write your JavaScript files.
...
实际上,有一种方法可以不异步地加载JavaScript文件,所以您可以在加载后立即使用新加载文件中包含的函数,我认为它适用于所有浏览器。
您需要在页面的
1 | $("head").append('<script type="text/javascript" src="' + script + '"></script>'); |
然而,这个方法也有一个问题:如果一个错误发生在导入的JavaScript文件,Firebug(还有Firefox错误控制台和Chrome开发工具)将报告它的位置不正确,这是一个大问题如果使用Firebug追踪JavaScript错误很多(我)。由于某种原因,Firebug根本不知道新加载的文件,所以如果该文件中发生错误,它会报告它发生在您的主HTML文件中,而您将很难找出错误的真正原因。
但是如果这对你来说不是一个问题,那么这个方法应该是有效的。
实际上,我已经编写了一个jQuery插件$.import_js(),它使用这个方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | (function($) { /* * $.import_js() helper (for JavaScript importing within JavaScript code). */ var import_js_imported = []; $.extend(true, { import_js : function(script) { var found = false; for (var i = 0; i < import_js_imported.length; i++) if (import_js_imported[i] == script) { found = true; break; } if (found == false) { $("head").append('<script type="text/javascript" src="' + script + '"></script>'); import_js_imported.push(script); } } }); })(jQuery); |
所以导入JavaScript只需要:
1 | $.import_js('/path_to_project/scripts/somefunctions.js'); |
我还对这个示例做了一个简单的测试。
它在主HTML中包含一个
1 2 3 4 | function hello() { alert("Hello world!"); } |
在包含
(这是对e-satis评论的回应)。
在我看来,另一种更简洁的方法是发出同步Ajax请求,而不是使用
下面是一个使用jQuery的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 | function require(script) { $.ajax({ url: script, dataType:"script", async: false, // <-- This is the key success: function () { // all good... }, error: function () { throw new Error("Could not load script" + script); } }); } |
然后你可以在你的代码中使用它,就像你通常使用include一样:
1 | require("/scripts/subscript.js"); |
并且能够在下一行调用所需脚本中的函数:
1 | subscript.doSomethingCool(); |
有个好消息要告诉你。很快您就可以轻松地加载JavaScript代码了。它将成为导入JavaScript代码模块的标准方式,并成为核心JavaScript本身的一部分。
只需编写
因此,您不必依赖于任何JavaScript框架,也不必显式地调用Ajax。
请参考:
静态模块解决方案
模块加载器
可以动态生成JavaScript标记,并从其他JavaScript代码中将其附加到HTML文档中。这将加载目标JavaScript文件。
1 2 3 4 5 6 7 8 9 10 | function includeJs(jsFilePath) { var js = document.createElement("script"); js.type ="text/javascript"; js.src = jsFilePath; document.body.appendChild(js); } includeJs("/path/to/some/file.js"); |
语句
语法
1 2 3 4 5 6 7 | import name from"module-name"; import { member } from"module-name"; import { member as alias } from"module-name"; import { member1 , member2 } from"module-name"; import { member1 , member2 as alias2 , [...] } from"module-name"; import name , { member [ , [...] ] } from"module-name"; import"module-name" as name; |
也许你可以使用我在这个页面上找到的这个函数,我如何在一个JavaScript文件中包含一个JavaScript文件?
1 2 3 4 5 6 7 8 9 10 | function include(filename) { var head = document.getElementsByTagName('head')[0]; var script = document.createElement('script'); script.src = filename; script.type = 'text/javascript'; head.appendChild(script) } |
下面是一个没有jQuery的同步版本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | function myRequire( url ) { var ajax = new XMLHttpRequest(); ajax.open( 'GET', url, false ); // <-- the 'false' makes it synchronous ajax.onreadystatechange = function () { var script = ajax.response || ajax.responseText; if (ajax.readyState === 4) { switch( ajax.status) { case 200: eval.apply( window, [script] ); console.log("script loaded:", url); break; default: console.log("ERROR: script not loaded:", url); } } }; ajax.send(null); } |
注意,要获得这个跨域的工作状态,服务器需要在响应中设置
我刚刚写了这段JavaScript代码(使用原型DOM操作):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | var require = (function() { var _required = {}; return (function(url, callback) { if (typeof url == 'object') { // We've (hopefully) got an array: time to chain! if (url.length > 1) { // Load the nth file as soon as everything up to the // n-1th one is done. require(url.slice(0, url.length - 1), function() { require(url[url.length - 1], callback); }); } else if (url.length == 1) { require(url[0], callback); } return; } if (typeof _required[url] == 'undefined') { // Haven't loaded this URL yet; gogogo! _required[url] = []; var script = new Element('script', { src: url, type: 'text/javascript' }); script.observe('load', function() { console.log("script" + url +" loaded."); _required[url].each(function(cb) { cb.call(); // TODO: does this execute in the right context? }); _required[url] = true; }); $$('head')[0].insert(script); } else if (typeof _required[url] == 'boolean') { // We already loaded the thing, so go ahead. if (callback) { callback.call(); } return; } if (callback) { _required[url].push(callback); } }); })(); |
用法:
1 2 3 4 5 6 7 | <script src="prototype.js"></script> <script src="require.js"></script> <script> require(['foo.js','bar.js'], function () { /* Use foo.js and bar.js here */ }); </script> |
要点:http://gist.github.com/284442。
以下是Facebook为其无处不在的Like按钮所做的概括版本:
1 2 3 4 5 6 7 8 9 10 | <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有效,对你也会有效。
我们寻找第一个
如果希望使用纯JavaScript,可以使用
1 | document.write('<script src="myscript.js" type="text/javascript"></script>'); |
如果使用jQuery库,可以使用
1 | $.getScript("another_script.js"); |
这里所示的大多数解都包含动力载荷。相反,我正在寻找一个编译器,它将所有依赖的文件组装成一个单独的输出文件。与Less/Sass预处理程序处理CSS
下面是编译器https://github.com/dsheiko/jsic,它用请求的文件内容安全地替换了
在jQuery主分支上,它们只是将原子源文件连接成一个以
src / main.js
1 | var foo = $import("./Form/Input/Tel"); |
src /形式/输入/ Tel.js
1 2 3 4 5 6 | function() { return { prop:"", method: function(){} } } |
现在我们可以运行编译器:
1 | node jsic.js src/main.js build/mail.js |
并获得组合文件
构建/ main.js
1 2 3 4 5 6 | var foo = function() { return { prop:"", method: function(){} } }; |
你也可以用PHP汇编你的脚本:
文件
1 2 3 4 5 6 7 | <?php header('Content-type:text/javascript; charset=utf-8'); include_once("foo.js.php"); include_once("bar.js.php"); ?> // Main JavaScript code goes here |
如果您打算使用导入/包含文件中的函数来加载JavaScript文件,还可以定义一个全局对象并将函数设置为对象项。例如:
global.js
1 | A = {}; |
file1.js
1 2 3 | A.func1 = function() { console.log("func1"); } |
file2.js
1 2 3 | A.func2 = function() { console.log("func2"); } |
main.js
1 2 | A.func1(); A.func2(); |
在HTML文件中包含脚本时,您只需要小心。订购次序如下:
1 2 3 4 5 6 | <head> <script type="text/javascript" src="global.js"></script> <script type="text/javascript" src="file1.js"></script> <script type="text/javascript" src="file2.js"></script> <script type="text/javascript" src="main.js"></script> </head> |
这个应该做的是:
1 2 3 4 | xhr = new XMLHttpRequest(); xhr.open("GET","/soap/ajax/11.0/connection.js", false); xhr.send(); eval(xhr.responseText); |
或者,与其在运行时包含,不如在上传之前使用脚本进行连接。
我用链轮(我不知道是否还有其他的)。您可以在单独的文件中构建JavaScript代码,并包含由Sprockets引擎作为include处理的注释。对于开发,您可以顺序包含文件,然后对于生产,您可以合并它们…
参见:
介绍链轮:JavaScript依赖关系管理和连接如果您正在使用Web worker,并且希望在worker的范围内包含其他脚本,那么提供的关于向
幸运的是,Web Worker有自己的
另外,作为您的问题的第二高投票答案,RequireJS还可以处理Web Worker内部的脚本(可能本身调用
我有一个简单的问题,但我对这个问题的回答感到困惑。
我必须在另一个JavaScript文件(main.js)中使用在一个JavaScript文件(myvariables.js)中定义的变量(myVar1)。
为此,我做了如下工作:
在HTML文件中加载JavaScript代码,顺序正确,先myvariables.js,然后main.js:
1 2 3 4 5 6 7 8 9 | <html> <body onload="bodyReady();"> <script src="myvariables.js"> </script> <script src="main.js"> </script> <!-- Some other code --> </body> </html> |
文件:myvariables.js
1 | var myVar1 ="I am variable from myvariables.js"; |
文件:main.js
1 2 3 4 5 6 7 | // ... function bodyReady() { // ... alert (myVar1); // This shows"I am variable from myvariables.js", which I needed // ... } // ... |
如您所见,我在一个JavaScript文件中使用了另一个JavaScript文件中的变量,但我不需要在另一个JavaScript文件中包含该变量。我只需要确保在加载第二个JavaScript文件之前加载第一个JavaScript文件,并且第一个JavaScript文件的变量可以在第二个JavaScript文件中自动访问。
这挽救了我的一天。我希望这能有所帮助。
从关于
Mix files are simply .js or .css files with .mix. in the file name. A mix file simply extends the functionality of a normal style or script file and allows you to import and combine.
下面是一个示例
1 2 3 4 5 6 7 | // scripts-global.mix.js // Plugins - Global @import"global-plugins/headroom.js"; @import"global-plugins/retina-1.1.0.js"; @import"global-plugins/isotope.js"; @import"global-plugins/jquery.fitvids.js"; |
混合物输出为
注意:除了将其用作前端开发工具之外,我没有以任何方式与mix关联。当我看到一个正在运行的
更新:混合现在是免费的(离线)。
更新:混合物现在停止。旧的混合物仍然可用
我通常的方法是:
1 2 3 4 5 6 7 8 9 10 11 12 | var require = function (src, cb) { cb = cb || function () {}; var newScriptTag = document.createElement('script'), firstScriptTag = document.getElementsByTagName('script')[0]; newScriptTag.src = src; newScriptTag.async = true; newScriptTag.onload = newScriptTag.onreadystatechange = function () { (!this.readyState || this.readyState === 'loaded' || this.readyState === 'complete') && (cb()); }; firstScriptTag.parentNode.insertBefore(newScriptTag, firstScriptTag); } |
它工作得很好,不需要为我重新加载页面。我尝试了AJAX方法(另一种方法),但似乎对我来说效果不太好。
下面解释一下代码是如何为那些好奇的人工作的:本质上,它在URL的第一个脚本标记之后创建了一个新的脚本标记。它将其设置为异步模式,这样就不会阻塞代码的其余部分,而是在readyState(要加载内容的状态)更改为"loaded"时调用回调。
1 2 3 4 5 6 | var js = document.createElement("script"); js.type ="text/javascript"; js.src = jsFilePath; document.body.appendChild(js); |
我编写了一个简单的模块,它可以用JavaScript自动导入/包含模块脚本。有关代码的详细说明,请参阅JavaScript的博客文章require / import / include模块。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | // ----- USAGE ----- require('ivar.util.string'); require('ivar.net.*'); require('ivar/util/array.js'); require('http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js'); ready(function(){ //Do something when required scripts are loaded }); //-------------------- var _rmod = _rmod || {}; //Require module namespace _rmod.LOADED = false; _rmod.on_ready_fn_stack = []; _rmod.libpath = ''; _rmod.imported = {}; _rmod.loading = { scripts: {}, length: 0 }; _rmod.findScriptPath = function(script_name) { var script_elems = document.getElementsByTagName('script'); for (var i = 0; i < script_elems.length; i++) { if (script_elems[i].src.endsWith(script_name)) { var href = window.location.href; href = href.substring(0, href.lastIndexOf('/')); var url = script_elems[i].src.substring(0, script_elems[i].length - script_name.length); return url.substring(href.length+1, url.length); } } return ''; }; _rmod.libpath = _rmod.findScriptPath('script.js'); //Path of your main script used to mark //the root directory of your library, any library. _rmod.injectScript = function(script_name, uri, callback, prepare) { if(!prepare) prepare(script_name, uri); var script_elem = document.createElement('script'); script_elem.type = 'text/javascript'; script_elem.title = script_name; script_elem.src = uri; script_elem.async = true; script_elem.defer = false; if(!callback) script_elem.onload = function() { callback(script_name, uri); }; document.getElementsByTagName('head')[0].appendChild(script_elem); }; _rmod.requirePrepare = function(script_name, uri) { _rmod.loading.scripts[script_name] = uri; _rmod.loading.length++; }; _rmod.requireCallback = function(script_name, uri) { _rmod.loading.length--; delete _rmod.loading.scripts[script_name]; _rmod.imported[script_name] = uri; if(_rmod.loading.length == 0) _rmod.onReady(); }; _rmod.onReady = function() { if (!_rmod.LOADED) { for (var i = 0; i < _rmod.on_ready_fn_stack.length; i++){ _rmod.on_ready_fn_stack[i](); }); _rmod.LOADED = true; } }; _.rmod = namespaceToUri = function(script_name, url) { var np = script_name.split('.'); if (np.getLast() === '*') { np.pop(); np.push('_all'); } if(!url) url = ''; script_name = np.join('.'); return url + np.join('/')+'.js'; }; //You can rename based on your liking. I chose require, but it //can be called include or anything else that is easy for you //to remember or write, except"import", because it is reserved //for future use. var require = function(script_name) { var uri = ''; if (script_name.indexOf('/') > -1) { uri = script_name; var lastSlash = uri.lastIndexOf('/'); script_name = uri.substring(lastSlash+1, uri.length); } else { uri = _rmod.namespaceToUri(script_name, ivar._private.libpath); } if (!_rmod.loading.scripts.hasOwnProperty(script_name) && !_rmod.imported.hasOwnProperty(script_name)) { _rmod.injectScript(script_name, uri, _rmod.requireCallback, _rmod.requirePrepare); } }; var ready = function(fn) { _rmod.on_ready_fn_stack.push(fn); }; |
在现代语言中,答案是肯定的
1 2 3 4 5 6 7 8 | function loadJs( url ){ return new Promise( resolve => { const script = document.createElement("script" ); script.src = url; script.onload = resolve; document.head.appendChild( script ); }); } |
还有Head.js。这很容易处理:
1 2 3 4 5 | head.load("js/jquery.min.js", "js/jquery.someplugin.js", "js/jquery.someplugin.css", function() { alert("Everything is ok!"); }); |
正如您所看到的,它比Require.js更简单,并且与jQuery的
这个脚本将在任何其他
1 2 3 4 5 6 7 8 | (function () { var li = document.createElement('script'); li.type = 'text/javascript'; li.src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"; li.async=true; var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(li, s); })(); |
我遇到这个问题是因为我在寻找一种简单的方法来维护一组有用的JavaScript插件。在看到这里的一些解决方案后,我想到了这个:
设置一个名为"plugins"的文件。(或extension .js或类似的东西)。将插件文件与一个主文件放在一起。
js将有一个名为"pluginNames[]"的数组,我们将对每个()进行迭代,然后在每个插件的头部添加一个标签
//设置要在添加或删除插件文件时更新的数组var pluginNames =["刻字"、"fittext"、"butterjam"等];//每个插件有一个脚本标签美元。每个(pluginNames,函数(){$("头").append (");});
手动调用你头脑中的一个文件:
我发现,即使所有的插件都以它们应该的方式被放到head标签中,但当你点击进入页面或刷新时,它们并不总是由浏览器运行。
我发现用PHP include编写脚本标记更可靠。您只需要编写一次,这与使用JavaScript调用插件一样多。
这个问题有很多潜在的答案。我的答案显然是基于其中的一些。这是我读完所有答案后得出的结论。
例子:
file3.js
1 2 3 | var f3obj ="file3"; // Define other stuff |
file2.js:
1 2 3 4 5 6 7 | var f2obj ="file2"; $.getScript("file3.js", function(){ alert(f3obj); // Use anything defined in file3. }); |
file1.js:
1 2 3 4 5 6 | $.getScript("file2.js", function(){ alert(f3obj); //This will probably fail because file3 is only guaranteed to have loaded inside the callback in file2. alert(f2obj); // Use anything defined in the loaded script... }); |
您说可以指定Ajax以同步方式运行或使用XMLHttpRequest,这是对的,但是当前的趋势似乎是不支持同步请求,所以您现在或将来可能得不到完全的浏览器支持。
您可以尝试使用
我决定向后走而不是向前走。谢谢你
当然,您可以使用$("body").append(),但是这样就不能再正确地调试了。
注意:您必须只在页面加载时使用此选项,否则将得到一个空白屏幕。换句话说,总是把这个放在document.ready的前面/外面。我还没有使用这个测试后,页面加载在点击事件或类似的东西,但我很肯定它会失败。
我喜欢扩展jQuery的想法,但显然您不需要这样做。
在调用
我假设脚本在执行完它的
当加载其他文件时,
您可以尝试修改jQuery
解决方案:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | $.extend(true, { import_js : function(scriptpath, reAddLast) { if (typeof reAddLast ==="undefined" || reAddLast === null) { reAddLast = true; // Default this value to true. It is not used by the end user, only to facilitate recursion correctly. } var found = false; if (reAddLast == true) // If we are re-adding the originating script we do not care if it has already been added. { found = $('script').filter(function () { return ($(this).attr('src') == scriptpath); }).length != 0; // jQuery to check if the script already exists. (replace it with straight JavaScript if you don't like jQuery. } if (found == false) { var callingScriptPath = $('script').last().attr("src"); // Get the script that is currently loading. Again this creates a limitation where this should not be used in a button, and only before document.ready. document.writeln("<script type='text/javascript' src='" + scriptpath +"'></script>"); // Add the script to the document using writeln if (reAddLast) { $.import_js(callingScriptPath, false); // Call itself with the originating script to fix the order. throw 'Readding script to correct order: ' + scriptpath + ' < ' + callingScriptPath; // This halts execution of the originating script since it is getting reloaded. If you put a try / catch around the call to $.import_js you results will vary. } return true; } return false; } }); |
用法:
File3:
1 2 3 4 5 6 | var f3obj ="file3"; // Define other stuff $(function(){ f3obj ="file3docready"; }); |
File2:
1 2 3 4 5 | $.import_js('js/file3.js'); var f2obj ="file2"; $(function(){ f2obj ="file2docready"; }); |
File1:
1 2 3 4 5 6 7 8 9 10 11 | $.import_js('js/file2.js'); // Use objects from file2 or file3 alert(f3obj); //"file3" alert(f2obj); //"file2" $(function(){ // Use objects from file2 or file3 some more. alert(f3obj); //"file3docready" alert(f2obj); //"file2docready" }); |
尽管这些答案都很好,但是有一个简单的"解决方案"自脚本加载存在以来就一直存在,它将覆盖99.999%的大多数人的用例。只需在需要它的脚本之前包含所需的脚本。对于大多数项目来说,不需要很长时间就可以确定需要哪些脚本以及它们的顺序。
1 2 3 4 5 6 7 8 | <!DOCTYPE HTML> <html> <head> <script src="script1.js"></script> <script src="script2.js"></script> </head> <body></body> </html> |
如果script2需要script1,这是最简单的方法。我很惊讶没有人提出过这个问题,因为它是最明显、最简单的答案,几乎适用于所有情况。
我创建了一个函数,它允许您使用类似于c# /Java的语言来包含JavaScript文件。我在另一个JavaScript文件中对它进行了一些测试,它似乎可以工作。不过,它确实需要jQuery在最后提供一些"魔力"。
我将这段代码放在脚本目录根目录下的一个文件中(我将它命名为
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | /** * @fileoverview This file stores global functions that are required by other libraries. */ if (typeof(jQuery) === 'undefined') { throw 'jQuery is required.'; } /** Defines the base script directory that all .js files are assumed to be organized under. */ var BASE_DIR = 'js/'; /** * Loads the specified file, outputting it to the <head> HTMLElement. * * This method mimics the use of using in C# or import in Java, allowing * JavaScript files to"load" other JavaScript files that they depend on * using a familiar syntax. * * This method assumes all scripts are under a directory at the root and will * append the .js file extension automatically. * * @param {string} file A file path to load using C#/Java"dot" syntax. * * Example Usage: * imports('core.utils.extensions'); * This will output: <script type="text/javascript" src="/js/core/utils/extensions.js"></script> */ function imports(file) { var fileName = file.substr(file.lastIndexOf('.') + 1, file.length); // Convert PascalCase name to underscore_separated_name var regex = new RegExp(/([A-Z])/g); if (regex.test(fileName)) { var separated = fileName.replace(regex,",$1").replace(',', ''); fileName = separated.replace(/[,]/g, '_'); } // Remove the original JavaScript file name to replace with underscore version file = file.substr(0, file.lastIndexOf('.')); // Convert the dot syntax to directory syntax to actually load the file if (file.indexOf('.') > 0) { file = file.replace(/[.]/g, '/'); } var src = BASE_DIR + file + '/' + fileName.toLowerCase() + '.js'; var script = document.createElement('script'); script.type = 'text/javascript'; script.src = src; $('head').find('script:last').append(script); } |
有几种方法可以用Javascript实现模块,下面是两种最流行的方法:
ES6模块
浏览器还不支持这种模块化系统,所以为了使用这种语法,您必须使用像webpack这样的bundler。无论如何,使用bundler更好,因为它可以将所有不同的文件组合成一个(或几个相关的)文件。这将更快地将文件从服务器提供给客户机,因为每个HTTP请求都有一些相关的开销。因此,通过减少总体HTTP请求,我们可以提高性能。下面是ES6模块的一个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | // main.js file export function add (a, b) { return a + b; } export default function multiply (a, b) { return a * b; } // test.js file import {add}, multiply from './main'; // for named exports between curly braces {export1, export2} // for default exports without {} console.log(multiply(2, 2)); // logs 4 console.log(add(1, 2)); // logs 3 |
CommonJS(在NodeJS中使用)
这个调制系统在NodeJS中使用。您基本上将导出添加到一个名为
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | // main.js file function add (a, b) { return a + b; } module.exports = add; // here we add our add function to the exports object // test.js file const add = require('./main'); console.log(add(1,2)); // logs 3 |
这里有一个Grunt插件,允许您在任何文件中使用
它可以与npm install一起安装:https://npmjs.org/package/grunt-import
最好使用jQuery方法。要延迟就绪事件,首先调用
1 2 3 4 | $.holdReady(true); $.getScript("myplugin.js", function() { $.holdReady(false); }); |
这里有一个针对浏览器(而不是Node.js)使用HTML导入的解决方案。
首先,所有JavaScript类和脚本都不在
1 2 3 4 5 6 7 8 | <script> class MyClass { // Your code here.. } </script> |
然后,如果你想导入你的类,你只需要使用HTML导入:
1 2 3 4 5 6 | <link rel="import" href="relative/path/to/MyClass.js.html"/> <script> var myClass = new MyClass(); // Your code here.. </script> |
编辑:HTML导入将被删除
HTML导入和ES6模块已经在世界上大多数浏览器中得到了很好的实现。但是,由于HTML导入肯定不会成为标准的一部分,与ES6模块不同,它的开发将被放弃,那么您应该开始使用ES6模块。
保持它良好、简短、简单和可维护!:]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | // 3rd party plugins / script (don't forget the full path is necessary) var FULL_PATH = '', s = [ FULL_PATH + 'plugins/script.js' // Script example FULL_PATH + 'plugins/jquery.1.2.js', // jQuery Library FULL_PATH + 'plugins/crypto-js/hmac-sha1.js', // CryptoJS FULL_PATH + 'plugins/crypto-js/enc-base64-min.js' // CryptoJS ]; function load(url) { var ajax = new XMLHttpRequest(); ajax.open('GET', url, false); ajax.onreadystatechange = function () { var script = ajax.response || ajax.responseText; if (ajax.readyState === 4) { switch(ajax.status) { case 200: eval.apply( window, [script] ); console.log("library loaded:", url); break; default: console.log("ERROR: library not loaded:", url); } } }; ajax.send(null); } // initialize a single load load('plugins/script.js'); // initialize a full load of scripts if (s.length > 0) { for (i = 0; i < s.length; i++) { load(s[i]); } } |
这段代码只是一个简短的函数示例,它可能需要额外的功能才能在任何(或给定的)平台上得到完全支持。
我基本上是这样做的,创建一个新的元素,并附加到头部:
1 2 3 | var x = document.createElement('script'); x.src = 'http://example.com/test.js'; document.getElementsByTagName("head")[0].appendChild(x); |
jQuery:
1 2 3 4 5 6 | // jQuery $.getScript('/path/to/imported/script.js', function() { // Script is now loaded and executed. // Put your dependent JavaScript code here. }); |
仅对NodeJS,这对我来说是最好的!
我在这里尝试了大多数解决方案,但是没有一个能够帮助我在不改变范围的情况下加载另一个文件。最后我用了这个。它保留了范围和一切。在这一点上,它和你的代码一样好。
1 2 | const fs = require('fs'); eval(fs.readFileSync('file.js')+''); |
是的,有…
请继续阅读,在ES6中,我们可以将
但是等一下,ES6并不是所有的浏览器都支持,所以您需要的是使用
所以你创建一个类如下:
1 2 3 4 5 6 7 8 9 10 11 | class Person { constructor(name) { this.name = name; } build() { return new Person(this); } } module.exports = Person; |
在另一个JavaScript文件中,执行如下导入:
1 | import { Person } from 'Person'; |
你也可以要求文件如下:
1 | const Person = require('./Person'); |
如果你使用旧的JavaScript版本,你可以使用requirejs:
1 2 3 4 5 6 | requirejs(["helper/util"], function(util) { //This function is called when scripts/helper/util.js is loaded. //If util.js calls define(), then this function is not fired until //util's dependencies have loaded, and the util argument will hold //the module value for"helper/util". }); |
如果你想坚持使用旧版本的东西,比如jQuery,你也可以使用getScript:
1 2 3 | jQuery.getScript('./another-script.js', function() { // Call back after another-script loaded }); |
最后但并非最不重要的一点是,不要忘记您可以使用
1 2 3 | <script src="./first-script.js"></script> <script src="./second-script.js"></script> <script src="./third-script.js"></script> |
还有异步和延迟属性,我应该在这里提到它们…
Note: There are several ways an external script can be executed:
If async is present: The script is executed asynchronously
with the rest of the page (the script will be executed while the page
continues the parsing) If async is not present and defer is
present: The script is executed when the page has finished
parsing If neither async or defer is present: The script is
fetched and executed immediately, before the browser continues
parsing the page
如果您使用Angular,那么插件模块$ocLazyLoad可以帮助您做到这一点。
以下是它的文档中的一些引用:
Load one or more modules & components with multiple files:
1 $ocLazyLoad.load(['testModule.js', 'testModuleCtrl.js', 'testModuleService.js']);Load one or more modules with multiple files and specify a type where necessary:
Note: When using the requireJS style formatting (with js! at the beginning for example), do not specify a file extension. Use one or the other.
1
2
3
4
5
6
7
8 $ocLazyLoad.load([
'testModule.js',
{type: 'css', path: 'testModuleCtrl'},
{type: 'html', path: 'testModuleCtrl.html'},
{type: 'js', path: 'testModuleCtrl'},
'js!testModuleService',
'less!testModuleLessFile'
]);You can load external libs (not angular):
1
2 $ocLazyLoad.load(['testModule.js',
'bower_components/bootstrap/dist/js/bootstrap.js', 'anotherModule.js']);You can also load css and template files:
1
2
3
4
5 $ocLazyLoad.load([
'bower_components/bootstrap/dist/js/bootstrap.js',
'bower_components/bootstrap/dist/css/bootstrap.css',
'partials/template1.html'
]);
我需要异步加载JavaScript文件数组,并在最后进行回调。基本上,我最好的方法是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | // Load a JavaScript file from other JavaScript file function loadScript(urlPack, callback) { var url = urlPack.shift(); var subCallback; if (urlPack.length == 0) subCallback = callback; else subCallback = function () { console.log("Log script:" + new Date().getTime()); loadScript(urlPack, callback); } // Adding the script tag to the head as suggested before var head = document.getElementsByTagName('head')[0]; var script = document.createElement('script'); script.type = 'text/javascript'; script.src = url; // Then bind the event to the callback function. // There are several events for cross browser compatibility. script.onreadystatechange = subCallback; script.onload = subCallback; // Fire the loading head.appendChild(script); } |
例子:
1 2 3 4 5 6 7 8 9 10 11 | loadScript( [ "js/DataTable/jquery.dataTables.js", "js/DataTable/dataTables.bootstrap.js", "js/DataTable/dataTables.buttons.min.js", "js/DataTable/dataTables.colReorder.min.js", "js/DataTable/dataTables.fixedHeader.min.js", "js/DataTable/buttons.bootstrap.min.js", "js/DataTable/buttons.colVis.min.js", "js/DataTable/buttons.html5.min.js" ], function() { gpLoad(params); }); |
第二个脚本将不会加载,直到第一个脚本被完全加载,所以…
结果:
很简单。假设您想要在文件B.js中导入文件A.js。
现在可以确定您已经在HTML文件中链接了B.js,然后只需在该HTML文件中链接B.js之前链接A.js。然后A.js的公共变量将在B.js中可用
这并不需要一个复杂的答案。
在过去的一个项目中,我成功地使用ajile导入了可重用的JavaScript文件。我一直希望JavaScript本身能够内置这个特性。
导入和导出模块使用ES6与Node.js一起工作
扩展名为
创建文件
1 | touch main.mjs lib.mjs |
main.js
1 2 | import { add } from './lib.mjs'; console.log(add(40, 2)); |
lib.mjs
1 2 3 | export let add = (x,y) => { return x + y } |
运行
1 | node --experimental-modules main.js |
1 2 3 4 5 6 7 | var s=["Hscript.js","checkRobert.js","Hscript.js"]; for(i=0;i<s.length;i++){ var script=document.createElement("script"); script.type="text/javascript"; script.src=s[i]; document.getElementsByTagName("head")[0].appendChild(script) }; |
现在,我可能完全被误导了,但这是我最近开始做的事情……用一个回车开始和结束JavaScript文件,放置在PHP脚本中,然后再返回一个回车。JavaScript注释"//"被PHP忽略,所以无论如何都会包含它。回车的目的是使包含的JavaScript的第一行不被注释掉。
从技术上讲,你不需要评论,但它会在Dreamweaver中发布错误,这让我很恼火。如果您在一个不发布错误的IDE中编写脚本,您不应该需要注释或回车。
1 2 3 4 5 | //<?php require_once("path/to/javascript/dependency.js"); ?> function myFunction(){ // stuff } |
别忘了查看LAB.js!
1 2 3 4 5 | <script type="text/javascript"> $LAB .script("jquery-1.8.3.js").wait() .script("scripts/clientscript.js"); </script> |
另一种方法是使用HTML导入。它们可以包含脚本引用和样式表引用。
你可以像这样链接一个HTML文件
1 | <link rel="import" href="vendorScripts.html"/> |
在
1 2 3 4 | <script src="scripts/vendors/jquery.js"></script> <script src="scripts/vendors/bootstrap.js"></script> <script src="scripts/vendors/angular.js"></script> <script src="scripts/vendors/angular-route.js"></script> |
查看HTML导入以获得更多细节。
不幸的是,这只适用于Chrome。
这也许是另一种方法!在Node.js中,您可以像下面这样做!http://requirejs.org/docs/node.html
sub.js
1 2 3 4 5 6 7 8 | module.exports = { log: function(string) { if(console) console.log(string); } mylog: function(){ console.log('just for log test!'); } } |
main.js
1 2 3 4 | var mylog =require('./sub'); mylog.log('Hurray, it works! :)'); mylog.mylog(); |
您不能导入,但可以引用。
PhpShtorm IDE。要引用,在一个
1 | <reference path="../js/file.js" /> |
当然,您应该使用自己的JavaScript文件路径。
我不知道它是否能在其他ide中工作。也许是的,试试吧。它也应该在Visual Studio中工作。
我用另一种方法尝试了这个问题,
脚本导入的顺序,在这里没有影响。
index . html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>Trials</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <script src="main.js"></script> <script src="scriptA.js"></script> </head> <body> <hh3>testing js in js (check console logs)</hh3> <button onclick="fnClick()">TEST</button> </body> </html> |
main.js
1 2 3 4 5 | function fnClick() { console.log('From\tAAAAA'); var pro = myExpo.hello(); console.log(pro); } |
scriptA.js
1 2 3 4 5 6 | myExpo = { hello: function () { console.log('From\tBBBBB'); return"Hello"; } } |
结果是
1 2 3 | From AAAAA From BBBBB Hello |
请注意,我们通常使用静态脚本。所以我们希望尽可能地从缓存中取出数据。这节省了网络流量,加快了着陆速度。
使用
1 2 3 | $.cachedScript("ajax/test.js" ).done(function( script, textStatus ) { console.log( textStatus ); }); |
缓存:true选项已添加到ajax方法中
如果您发现有2个或更多的脚本在调用时占用了相同的函数,那么我们就不能在相同的时间内包含它们,我们需要通过用户选择动态地进行处理。
使用
HTML
1 2 3 4 | <select class="choice"> <option value="script1" selected>Script-1</option> <option value="script2">Script-2</option> </select> |
JS
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | $(".choice").change(on_change); var url ="https://example.com"; $.url1 = url +"/script1.js"; $.url2 = url +"/script2.js"; function on_change() { if ($(".choice").val()=="script1") { script1(); } else { script2(); } // script1 function script1() { $.getScript($.url1, function( data, textStatus, jqxhr ) { //excecute here }); } // script2 function script2() { $.getScript($.url2, function( data, textStatus, jqxhr ) { //excecute here }); } |
1 | var xxx = require("../lib/your-library.js") |
或
1 2 3 | import xxx from"../lib/your-library.js" //get default export import {specificPart} from '../lib/your-library.js' //get named export import * as _name from '../lib/your-library.js' //get full export to alias _name |
动态加载多个脚本,顺序为
如果只加载一个脚本,或者不关心多个脚本的加载顺序,则上述函数可以正常工作。如果您有一些脚本依赖于其他脚本,则需要使用Promise来指定加载的顺序。这背后的原因是Javascript异步加载脚本和图像等资源。加载序列不依赖于异步调用的序列,这意味着即使在调用
这是dynamicallyLoadScript的另一个版本,它保证了加载顺序:
1 2 3 4 5 6 7 8 9 | // Based on: https://javascript.info/promise-basics#example-loadscript function dynamicallyLoadScript(url) { return new Promise(function(resolve, reject) { var script = document.createElement("script"); script.src = url; script.onload = resolve; script.onerror = () => reject(new Error(`Error when loading ${url}!`)); document.body.appendChild(script); }); |
有关承诺的更多信息,请参见这一优秀页面。
这个动态加载脚本的使用非常简单:
1 2 3 4 5 6 | dynamicallyLoadScript("script1.js") .then(() => dynamicallyLoadScript("script2.js")) .then(() => dynamicallyLoadScript("script3.js")) .then(() => dynamicallyLoadScript("script4.js")) .then(() => dynamicallyLoadScript("script5.js")) //... |
现在脚本按script1的顺序加载。js, script2。js, script3。js等。
脚本加载后运行依赖代码此外,您可以在加载脚本之后立即运行使用脚本的代码。只需在加载脚本后添加另一个
1 2 3 4 5 6 7 8 9 10 11 12 | dynamicallyLoadScript("script1.js") .then(() => dynamicallyLoadScript("script2.js")) .then(() => foo()) // foo can be a function defined in either script1, script2 .then(() => dynamicallyLoadScript("script3.js")) .then(() => { if (var1){ // var1 can be a global variable defined in either script1, script2, or script3 bar(var1); // bar can be a function defined in either script1, script2, or script3 } else { foo(var1); } }) //more .then chains... |
处理加载错误
要显示未处理的承诺拒绝(错误加载脚本等),将这个
1 2 3 4 5 6 | // Based on: https://javascript.info/promise-error-handling#unhandled-rejections window.addEventListener('unhandledrejection', function(event) { // the event object has two special properties: console.error(event.promise);// the promise that generated the error console.error(event.reason); // the unhandled error object }); |
现在,您将收到任何脚本加载错误的通知。
快捷功能
如果你加载了很多脚本,而没有在加载后立即执行代码,这个简写函数可能会派上用场:
1 2 3 4 5 6 7 8 9 | function dynamicallyLoadScripts(urls){ if (urls.length === 0){ return; } let promise = dynamicallyLoadScript(urls[0]); urls.slice(1).forEach(url => { promise = promise.then(() => dynamicallyLoadScript(url)); }); } |
要使用它,只需传入一个脚本url数组,如下所示:
1 2 | const scriptURLs = ["dist/script1.js","dist/script2.js","dist/script3.js"]; dynamicallyLoadScripts(scriptURLs); |
脚本将按照它们在数组中出现的顺序加载。