提问人:Alec Smart 提问时间:6/4/2009 最后编辑:Mateen UlhaqAlec Smart 更新时间:8/13/2023 访问量:4305295
如何在另一个 JavaScript 文件中包含一个 JavaScript 文件?
How do I include a JavaScript file in another JavaScript file?
答:
可以动态生成 JavaScript 标签,并将其从其他 JavaScript 代码中附加到 HTML 文档。这将加载目标 JavaScript 文件。
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");
评论
js.type
也许您可以使用我在此页面上找到的这个函数 如何在 JavaScript 文件中包含 JavaScript 文件?
function include(filename)
{
var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script');
script.src = filename;
script.type = 'text/javascript';
head.appendChild(script)
}
旧版本的 JavaScript 没有导入、包含或要求,因此已经开发了许多不同的方法来解决这个问题。
但自 2015 年(ES6)以来,JavaScript 已经拥有了 ES6 模块标准,可以在 Node.js 中导入模块,大多数现代浏览器也支持它。
为了与旧版浏览器兼容,可以使用 Webpack 和 Rollup 等构建工具和/或 Babel 等转译工具。
ES6 模块
自 v8.5 以来,Node.js 一直支持 ECMAScript (ES6) 模块,并且至少从 Node.js v13.8.0 开始支持没有标志。要启用“ESM”(相对于 Node.js 以前的 CommonJS 样式模块系统 [“CJS”]),您可以使用或为文件指定扩展名。(同样,如果您的默认值为 ESM,则可以命名使用 Node.js 以前的 CJS 模块编写的模块。--experimental-modules
"type": "module"
package.json
.mjs
.cjs
用:package.json
{
"type": "module"
}
然后:module.js
export function hello() {
return "Hello";
}
然后:main.js
import { hello } from './module.js';
let val = hello(); // val is "Hello";
使用 ,您将拥有:.mjs
module.mjs
export function hello() {
return "Hello";
}
然后:main.mjs
import { hello } from './module.mjs';
let val = hello(); // val is "Hello";
浏览器中的 ECMAScript 模块
从 Safari 10.1、Chrome 61、Firefox 60 和 Edge 16 开始,浏览器就支持直接加载 ECMAScript 模块(不需要 Webpack 等工具)。检查 caniuse 的当前支持。无需使用 Node.js 扩展;浏览器完全忽略模块/脚本上的文件扩展名。.mjs
<script type="module">
import { hello } from './hello.mjs'; // Or the extension could be just `.js`
hello('world');
</script>
// hello.mjs -- or the extension could be just `.js`
export function hello(text) {
const div = document.createElement('div');
div.textContent = `Hello ${text}`;
document.body.appendChild(div);
}
在 https://jakearchibald.com/2017/es-modules-in-browsers/ 阅读更多内容
浏览器中的动态导入
动态导入允许脚本根据需要加载其他脚本:
<script type="module">
import('hello.mjs').then(module => {
module.hello('world');
});
</script>
在 https://developers.google.com/web/updates/2017/11/dynamic-import 阅读更多内容
节点.js 需要
在Node.js中仍然广泛使用的较旧的CJS模块样式是module.exports
/require
系统。
// mymodule.js
module.exports = {
hello: function() {
return "Hello";
}
}
// server.js
const myModule = require('./mymodule');
let val = myModule.hello(); // val is "Hello"
JavaScript 还有其他方法可以在不需要预处理的浏览器中包含外部 JavaScript 内容。
AJAX 加载
您可以使用 AJAX 调用加载其他脚本,然后使用它来运行它。这是最直接的方法,但由于 JavaScript 沙盒安全模型,它仅限于您的域。使用还为错误、黑客和安全问题打开了大门。eval
eval
Fetch 加载
与动态导入一样,您可以使用 promise 通过调用加载一个或多个脚本,以使用 Fetch Inject 库控制脚本依赖项的执行顺序:fetch
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 加载
$.getScript("my_lovely_script.js", function() {
alert("Script loaded but not necessarily executed.");
});
动态脚本加载
您可以在 HTML 中添加带有脚本 URL 的脚本标记。为了避免jQuery的开销,这是一个理想的解决方案。
该脚本甚至可以驻留在不同的服务器上。此外,浏览器会评估代码。标签可以注入到网页中,也可以插入到结束标签之前。<script>
<head>
</body>
以下是其工作原理的示例:
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)
}
此函数将在页面的 head 部分的末尾添加一个新标记,其中属性设置为作为第一个参数提供给函数的 URL。<script>
src
这两种解决方案在 JavaScript Madness: Dynamic Script Loading 中都有讨论和说明。
检测脚本何时执行
现在,您必须了解一个大问题。这样做意味着您远程加载代码。现代 Web 浏览器将加载文件并继续执行当前脚本,因为它们异步加载所有内容以提高性能。(这适用于 jQuery 方法和手动动态脚本加载方法。
这意味着,如果您直接使用这些技巧,则在要求加载新加载的代码后,您将无法在下一行使用新加载的代码,因为它仍在加载中。
例如:包含:my_lovely_script.js
MySuperObject
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
那么该怎么办呢?
好吧,您可以使用作者在我给您的链接中建议的技巧。综上所述,对于匆忙的人来说,他在加载脚本时使用事件来运行回调函数。因此,您可以将使用远程库的所有代码放在回调函数中。例如:
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 函数中后,编写要使用的代码:
var myPrettyCode = function() {
// Here, do whatever you want
};
然后你运行所有这些:
loadScript("my_lovely_script.js", myPrettyCode);
请注意,脚本可能会在 DOM 加载之后或之前执行,具体取决于浏览器以及是否包含行 。有一篇关于 Javascript 加载的好文章对此进行了讨论。script.async = false;
源代码合并/预处理
正如本答案顶部提到的,许多开发人员在他们的项目中使用 Parcel、Webpack 或 Babel 等构建/转译工具,允许他们使用即将到来的 JavaScript 语法、为旧浏览器提供向后兼容性、合并文件、缩小、执行代码拆分等。
评论
Failed to load module script: Expected a JavaScript module script but the server responded with a MIME type of "". Strict MIME type checking is enforced for module scripts per HTML spec.
hello.mjs
hello.js
我刚刚编写了这个 JavaScript 代码(使用 Prototype 进行 DOM 操作):
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);
}
});
})();
用法:
<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。
您还可以使用 PHP 组装脚本:
文件:main.js.php
<?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 文件,因此您可以在加载后立即使用新加载文件中包含的功能,我认为它适用于所有浏览器。
您需要在页面的元素上使用,即:jQuery.append()
<head>
$("head").append($("<script></script>").attr("src", url));
/* Note that following line of code is incorrect because it doesn't escape the
* HTML attribute src correctly and will fail if `url` contains special characters:
* $("head").append('<script src="' + url + '"></script>');
*/
但是,这种方法也有一个问题:如果导入的 JavaScript 文件中发生错误,Firebug(以及 Firefox 错误控制台和 Chrome 开发者工具)将错误地报告其位置,如果您使用 Firebug 来跟踪 JavaScript 错误,这是一个大问题(我确实这样做)。由于某种原因,Firebug 根本不知道新加载的文件,因此如果该文件中发生错误,它会报告它发生在您的主 HTML 文件中,您将很难找出错误的真正原因。
但是,如果这对您来说不是问题,那么这种方法应该有效。
我实际上已经编写了一个名为$.import_js()的jQuery插件,它使用这种方法:
(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></script').attr('src', script));
import_js_imported.push(script);
}
}
});
})(jQuery);
因此,导入 JavaScript 所需要做的就是:
$.import_js('/path_to_project/scripts/somefunctions.js');
我还在Example中对此进行了简单的测试。
它在主 HTML 中包含一个文件,然后脚本用于导入一个名为 的附加文件,该文件定义了以下函数:main.js
main.js
$.import_js()
included.js
function hello()
{
alert("Hello world!");
}
在包含 之后,立即调用该函数,您会收到警报。included.js
hello()
(这个答案是对e-satis评论的回应)。
在我看来,另一种更简洁的方法是发出同步 Ajax 请求而不是使用标签。这也是 Node.js 处理的方式。<script>
下面是使用 jQuery 的示例:
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 一样:
require("/scripts/subscript.js");
并能够在下一行中从所需的脚本调用函数:
subscript.doSomethingCool();
我之所以提出这个问题,是因为我一直在寻找一种简单的方法来维护一组有用的 JavaScript 插件。在看到这里的一些解决方案后,我想出了这个:
设置一个名为“plugins.js”的文件(或扩展名 .js 或任何你想要的东西)。将您的插件文件与该主文件放在一起。
插件.js将有一个名为的数组,我们将遍历它, 然后为每个插件的头部附加一个标签
pluginNames[]
each()
<script>
//set array to be updated when we add or remove plugin files
var pluginNames = ["lettering", "fittext", "butterjam", etc.];
//one script tag for each plugin
$.each(pluginNames, function(){
$('head').append('<script src="js/plugins/' + this + '.js"></script>');
});
- 手动调用您脑海中的一个文件:
<script src="js/plugins/plugins.js"></script>
但:
即使所有插件都以应有的方式放入 head 标签中,但当您单击页面或刷新时,它们并不总是被浏览器运行。
我发现只在 PHP include 中编写脚本标签更可靠。你只需要写一次,这与使用JavaScript调用插件一样多。
评论
$('head').append('<script src="js/plugins/' + this + '.js"></script>');
我创建了一个函数,它允许您使用与 C#/Java 类似的措辞来包含 JavaScript 文件。我甚至从另一个 JavaScript 文件内部对它进行了一些测试,它似乎可以工作。它确实需要jQuery,尽管最后需要一些“魔术”。
我把这段代码放在我的脚本目录根目录的一个文件中(我把它命名为,但你可以使用任何你想要的东西。除非我弄错了,否则jQuery应该是给定页面上唯一需要的脚本。请记住,除了一些基本用法之外,这在很大程度上未经测试,因此我这样做的方式可能会或可能不会有任何问题;使用风险自负 yadda yadda 如果你搞砸了任何事情,我不负责 yadda yadda:global.js
/**
* @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);
}
在过去的一个项目中,我使用 ajile 导入可重用的 JavaScript 文件取得了相当大的成功。我一直希望 JavaScript 本身有一个内置的功能。
或者,与其在运行时包含,不如在上传之前使用脚本进行连接。
我使用链轮(我不知道是否有其他)。您可以在单独的文件中构建 JavaScript 代码,并包含由 Sprockets 引擎处理的注释作为 include。对于开发,您可以按顺序包含文件,然后用于生产以合并它们......
另请参阅:
如果有人正在寻找更高级的东西,请尝试 RequireJS。您将获得额外的好处,例如依赖项管理、更好的并发性和避免重复(即多次检索脚本)。
您可以在“模块”中编写 JavaScript 文件,然后在其他脚本中将它们作为依赖项引用。或者,你可以将 RequireJS 用作一个简单的“去获取此脚本”解决方案。
例:
将依赖项定义为模块:
某种依赖关系.js
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是依赖于某些依赖项.js的“主要”JavaScript文件
require(['some-dependency'], function(dependency) {
//Your script goes here
//some-dependency.js is fetched.
//Then your script is executed
});
摘自 GitHub README:
RequireJS 加载普通的 JavaScript 文件以及更多定义的文件 模块。它针对浏览器内使用进行了优化,包括在 Web 中使用 worker,但它可以在其他 JavaScript 环境中使用,例如 Rhino 和 Node。它实现了异步模块 API。
RequireJS 使用纯脚本标签来加载模块/文件,因此它应该 便于调试。它可以简单地用于加载现有的 JavaScript 文件,因此您可以将其添加到现有项目中,而无需 必须重写 JavaScript 文件。
...
有一个好消息要告诉你。很快,您将能够轻松加载 JavaScript 代码。它将成为导入 JavaScript 代码模块的标准方式,并将成为核心 JavaScript 本身的一部分。
您只需写入即可加载从文件命名的宏。import cond from 'cond.js';
cond
cond.js
因此,您不必依赖任何 JavaScript 框架,也不必显式地进行 Ajax 调用。
指:
评论
var js = document.createElement("script");
js.type = "text/javascript";
js.src = jsFilePath;
document.body.appendChild(js);
评论
js.type = "text/javascript"
最好使用jQuery方式。若要延迟就绪事件,请先调用 。
示例(来源):$.holdReady(true)
$.holdReady(true);
$.getScript("myplugin.js", function() {
$.holdReady(false);
});
别忘了查看 LAB.js!
<script type="text/javascript">
$LAB.script("jquery-1.8.3.js").wait().script("scripts/clientscript.js");
</script>
现在,我可能完全被误导了,但这是我最近开始做的事情...... 以回车符开始和结束 JavaScript 文件,放在 PHP 脚本中,然后再回车。 JavaScript 注释 “//” 被 PHP 忽略,因此无论如何都会包含。回车的目的是使包含的 JavaScript 的第一行不会被注释掉。
从技术上讲,您不需要注释,但它会在 Dreamweaver 中发布让我烦恼的错误。如果在不发布错误的 IDE 中编写脚本,则不需要注释或回车符。
\n
//<?php require_once("path/to/javascript/dependency.js"); ?>
function myFunction(){
// stuff
}
\n
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)
};
这应该做:
xhr = new XMLHttpRequest();
xhr.open("GET", "/soap/ajax/11.0/connection.js", false);
xhr.send();
eval(xhr.responseText);
我编写了一个简单的模块,可以自动执行在 JavaScript 中导入/包含模块脚本的工作。有关代码的详细说明,请参阅博客文章 JavaScript require / import / include modules。
// ----- 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);
};
我通常的方法是:
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”时调用回调。
此处显示的大多数解决方案都意味着动态加载。相反,我正在寻找一个编译器,它将所有依赖的文件组合成一个输出文件。与 Less/Sass 预处理器一样,处理 CSS 规则。由于我没有找到任何像样的东西,所以我写了一个简单的工具来解决这个问题。@import
因此,这里是编译器 https://github.com/dsheiko/jsic,它安全地替换为请求的文件内容。以下是相应的 Grunt 插件:https://github.com/dsheiko/grunt-jsic。$import("file-path")
在 jQuery master 分支上,它们只是将原子源文件连接成一个以 开头并以 结尾的文件。这不适合我,因为它在源代码设计上没有提供灵活性。看看它是如何与jsic一起工作的:intro.js
outtro.js
src/main.js
var foo = $import("./Form/Input/Tel");
src/Form/Input/Tel.js
function() {
return {
prop: "",
method: function(){}
}
}
现在我们可以运行编译器了:
node jsic.js src/main.js build/mail.js
并获取组合文件
构建/main.js
var foo = function() {
return {
prop: "",
method: function(){}
}
};
此脚本会将 JavaScript 文件添加到任何其他标记的顶部:<script>
(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);
})();
这是一个 Grunt 插件,允许您在任何文件(包括 JavaScript 文件)中使用语法。它可以与 uglify 或 watch 或任何其他插件配对。@import "path/to/file.js";
可以使用 npm install 安装它: https://npmjs.org/package/grunt-import
如果你想在纯 JavaScript 中使用它,你可以使用 .document.write
document.write('<script src="myscript.js" type="text/javascript"></script>');
如果使用 jQuery 库,则可以使用该方法。$.getScript
$.getScript("another_script.js");
还有 Head.js。这很容易处理:
head.load("js/jquery.min.js",
"js/jquery.someplugin.js",
"js/jquery.someplugin.css", function() {
alert("Everything is ok!");
});
如您所见,它比 Require.js 更容易,并且与 jQuery 的方法一样方便。它还具有一些高级功能,例如条件加载、功能检测等等。$.getScript
下面是一个没有jQuery的同步版本:
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);
}
请注意,要使这种跨域工作,服务器需要在其响应中设置标头。allow-origin
使用诸如 Mixture 之类的工具,可以通过其特殊文件类型实现类似 CSS 的 JavaScript 导入的语法(请参阅此处)。我假设应用程序通过上述方法之一执行此操作。@import
.mix
从关于文件的 Mixture 文档中:.mix
混合文件只是带有 .mix 的.js或 .css 文件。在文件名中。一个 混合文件只是扩展了普通样式的功能,或者 脚本文件,并允许您导入和组合。
下面是一个将多个文件合并为一个文件的示例文件:.mix
.js
// 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";
Mixture 将其输出为缩小版本 ()。scripts-global.js
scripts-global.min.js
注意:除了将其用作前端开发工具外,我与 Mixture 没有任何关联。当我看到一个 JavaScript 文件在运行(在其中一个 Mixture 样板中)并对此感到有点困惑时,我遇到了这个问题(“你能做到吗?我心想)。然后我意识到这是一种特定于应用程序的文件类型(有点令人失望,同意)。尽管如此,认为这些知识可能对其他人有所帮助。.mix
注意:Mixture 已于 2016/07/26 停止供应(在 2015/04/12 开源后)。
评论
如果您使用的是 Web Worker,并且希望在 worker 的作用域中包含其他脚本,则提供的有关将脚本添加到标记等的其他答案将不适合您。head
幸运的是,Web Worker 有自己的 importScripts
函数,它是 Web Worker 范围内的全局函数,是浏览器本身的原生函数,因为它是规范的一部分。
或者,作为对你的问题的第二高票的答案,RequireJS也可以处理包含Web Worker中的脚本(可能调用自己,但具有一些其他有用的功能)。importScripts
这个问题有很多潜在的答案。我的回答显然是基于其中的一些。这是我在阅读完所有答案后得出的结论。
加载完成时需要回调的任何其他解决方案的问题在于,如果您有多个文件使用它并相互依赖,您将无法再知道所有脚本何时加载(一旦它们嵌套在多个文件中)。$.getScript
例:
文件3.js
var f3obj = "file3";
// Define other stuff
文件2.js:
var f2obj = "file2";
$.getScript("file3.js", function(){
alert(f3obj);
// Use anything defined in file3.
});
文件1.js:
$.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 时,你是对的,但目前的趋势似乎是弃用同步请求,所以你现在或将来可能不会得到完整的浏览器支持。
您可以尝试使用来检查延迟对象的数组,但现在您正在每个文件中执行此操作,并且 file2 将在执行后立即被视为已加载,而不是在执行回调时,因此 file1 在加载 file3 之前仍会继续执行。这确实仍然存在同样的问题。$.when
$.when
我决定倒退而不是前进。谢谢。我知道这是禁忌,但只要使用得当,效果很好。你最终会得到可以轻松调试的代码,在DOM中正确显示,并且可以确保依赖项的加载顺序正确。document.writeln
你当然可以使用$(“body”).append(),但是你不能再正确调试了。
注意:您只能在页面加载时使用它,否则会出现空白屏幕。换句话说,始终将其放在 document.ready 之前/之外。在页面加载到点击事件或类似事件中后,我还没有测试过使用它,但我很确定它会失败。
我喜欢扩展jQuery的想法,但显然你不需要。
在调用 之前,它会通过评估所有脚本元素来检查以确保脚本尚未加载。document.writeln
我假设脚本在执行其事件之前不会完全执行。(我知道使用不是必需的,但很多人使用它,处理它是一种保护措施。document.ready
document.ready
加载其他文件时,回调将以错误的顺序执行。为了在实际加载脚本时解决此问题,导入该脚本的脚本将自行重新导入并停止执行。这会导致原始文件现在在它导入的任何脚本中的任意脚本之后执行其回调。document.ready
document.ready
您可以尝试修改 jQuery ,而不是这种方法,但这似乎是一个更糟糕的解决方案。readyList
溶液:
$.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;
}
});
用法:
文件3:
var f3obj = "file3";
// Define other stuff
$(function(){
f3obj = "file3docready";
});
文件2:
$.import_js('js/file3.js');
var f2obj = "file2";
$(function(){
f2obj = "file2docready";
});
罚款:
$.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"
});
保持美观、简短、简单且易于维护!:]
// Third-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]);
}
}
此代码只是一个简短的功能示例,可能需要额外的功能才能在任何(或给定)平台上获得完全支持。
评论
语句导入
在 ECMAScript 6 中。
语法
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;
以下是Facebook如何为他们无处不在的“喜欢”按钮做这件事的广义版本:
<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,它也适用于您。
我们之所以寻找第一个元素而不是 or 是因为某些浏览器在缺少时不会创建一个元素,但我们保证有一个元素 - 这个。在 http://www.jspatterns.com/the-ridiculous-case-of-adding-a-script-element/ 阅读更多内容。script
head
body
script
我有一个简单的问题,但我对这个问题的回答感到困惑。
我不得不使用在另一个 JavaScript 文件 (main.js) 中的一个 JavaScript 文件 (myvariables.js) 中定义的变量 (myVar1)。
为此,我做了以下操作:
在 HTML 文件中加载了 JavaScript 代码,顺序正确,首先是 myvariables.js,然后是 main.js:
<html>
<body onload="bodyReady();" >
<script src="myvariables.js" > </script>
<script src="main.js" > </script>
<!-- Some other code -->
</body>
</html>
文件:myvariables.js
var myVar1 = "I am variable from myvariables.js";
文件:main.js
// ...
function bodyReady() {
// ...
alert (myVar1); // This shows "I am variable from myvariables.js", which I needed
// ...
}
// ...
如您所见,我在另一个 JavaScript 文件中的一个 JavaScript 文件中使用了一个变量,但我不需要在另一个文件中包含一个变量。我只需要确保第一个 JavaScript 文件在第二个 JavaScript 文件之前加载,并且第一个 JavaScript 文件的变量可以在第二个 JavaScript 文件中自动访问。
这挽救了我的一天。我希望这会有所帮助。
如果加载 JavaScript 文件的意图是使用导入/包含文件中的函数,则还可以定义全局对象并将函数设置为对象项。例如:
全局.js
A = {};
文件1.js
A.func1 = function() {
console.log("func1");
}
文件2.js
A.func2 = function() {
console.log("func2");
}
main.js
A.func1();
A.func2();
当您在 HTML 文件中包含脚本时,您只需要小心。顺序应如下:
<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>
评论
我基本上是这样做的,创建一个新元素并将其附加到头部:
var x = document.createElement('script');
x.src = 'http://example.com/test.js';
document.getElementsByTagName("head")[0].appendChild(x);
在jQuery中:
// jQuery
$.getScript('/path/to/imported/script.js', function()
{
// Script is now loaded and executed.
// Put your dependent JavaScript code here.
});
我需要异步加载一组 JavaScript 文件,并在最后进行回调。基本上,我最好的方法是以下几点:
// 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);
}
例:
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); });
在第一个脚本完全加载之前,第二个脚本不会加载,因此...
结果:
您无法导入,但可以引用。
PhpShtorm的集成开发环境。要引用,在一个文件中引用到另一个文件,只需将以下内容添加到文件顶部:.js
.js
<reference path="../js/file.js" />
当然,您应该使用自己的 JavaScript 文件的 PATH。
我不知道它是否适用于其他 IDE。可能是的,试试吧。它也应该在 Visual Studio 中工作。
这也许是另一种方式!
在 Node.js 中,您可以像以下代码所示一样执行此操作!
子.js
module.exports = {
log: function(string) {
if(console) console.log(string);
}
mylog: function(){
console.log('just for log test!');
}
}
main.js
const mylog = require('./sub');
mylog.log('Hurray, it works! :)');
mylog.mylog();
TE S
http://requirejs.org/docs/node.html
var xxx = require("../lib/your-library.js")
或
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
另一种方法是使用 HTML 导入。这些可以包含脚本引用以及样式表引用。
您可以链接一个 HTML 文件,例如
<link rel="import" href="vendorScripts.html"/>
在文件中,您可以包含脚本引用,例如:vendorScripts.html
<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。
评论
如果你使用 Angular,那么插件模块$ocLazyLoad可以帮助您做到这一点。
以下是其文档中的一些引述:
加载一个或多个包含多个文件的模块和组件:
$ocLazyLoad.load(['testModule.js', 'testModuleCtrl.js', 'testModuleService.js']);
加载一个或多个包含多个文件的模块,并在必要时指定类型: 注意:当使用 requireJS 样式格式时(例如,在开头使用 js!),不要指定文件扩展名。使用其中之一。
$ocLazyLoad.load([ 'testModule.js', {type: 'css', path: 'testModuleCtrl'}, {type: 'html', path: 'testModuleCtrl.html'}, {type: 'js', path: 'testModuleCtrl'}, 'js!testModuleService', 'less!testModuleLessFile' ]);
您可以加载外部库(不是 angular):
$ocLazyLoad.load(['testModule.js', 'bower_components/bootstrap/dist/js/bootstrap.js', 'anotherModule.js']);
您还可以加载 css 和模板文件:
$ocLazyLoad.load([ 'bower_components/bootstrap/dist/js/bootstrap.js', 'bower_components/bootstrap/dist/css/bootstrap.css', 'partials/template1.html' ]);
这是使用 HTML 导入的浏览器(不是 Node.js)的解决方法。
首先,所有的JavaScript类和脚本都不在文件中,而是在文件(.js只是为了识别HTML页面和完整的JavaScript脚本/类之间),在标签中,如下所示:.js
.js.html
html
<script>
MyClass.js.html
:
<script>
class MyClass {
// Your code here..
}
</script>
然后,如果你想导入你的类,你只需要使用HTML导入:
<link rel="import" href="relative/path/to/MyClass.js.html"/>
<script>
var myClass = new MyClass();
// Your code here..
</script>
编辑:HTML导入将被丢弃
HTML 导入被丢弃,取而代之的是 ES6 模块。您应该使用 ES6 模块。
这很简单。假设您要在文件 B.js 中导入文件 A.js。
现在确定您已在 HTML 文件中链接了 B.js,然后只需在该 HTML 文件中的 B.js 之前链接 A.js。然后 A.js 的公共变量将在 B.js 中可用
这不需要复杂的答案。
在现代语言中,检查脚本是否已经加载,它将是:
function loadJs( url ){
return new Promise(( resolve, reject ) => {
if (document.querySelector( `head > script[ src = "${url}" ]`) !== null ){
console.warn( `script already loaded: ${url}` );
resolve();
}
const script = document.createElement( "script" );
script.src = url;
script.onload = resolve;
script.onerror = function( reason ){
// This can be useful for your error-handling code
reason.message = `error trying to load script ${url}`;
reject( reason );
};
document.head.appendChild( script );
});
}
用法 (async/await):
try { await loadJs("https://.../script.js"); }
catch(error) { console.log(error); }
或
await loadJs( "https://.../script.js" ).catch( err => {} );
用法(承诺):
loadJs( "https://.../script.js" ).then( res => {} ).catch( err => {} );
评论
async
await
url
需要在此处正确转义:`head > script[ src = "${url}" ]`
虽然这些答案很好,但自从脚本加载存在以来,就一直存在一个简单的“解决方案”,它将覆盖大多数人 99.999% 的用例。只需在需要它的脚本之前包含您需要的脚本即可。对于大多数项目,确定需要哪些脚本以及以什么顺序进行不会花费很长时间。
<!DOCTYPE HTML>
<html>
<head>
<script src="script1.js"></script>
<script src="script2.js"></script>
</head>
<body></body>
</html>
如果 script2 需要 script1,这确实是做这样的事情的绝对最简单的方法。我很惊讶没有人提出这个问题,因为这是最明显和最简单的答案,几乎适用于每一个案例。
评论
请注意,我们通常使用静态脚本。因此,我们希望尽可能多地从缓存中获取。
这样可以节省网络流量并加快着陆速度。
用法
$.cachedScript( "ajax/test.js" ).done(function( script, textStatus ) {
console.log( textStatus );
});
cache: true 选项已添加到 Ajax 方法中。
如果发现调用时有两个或多个脚本占用了同一个功能,而我们不能同时包含它们,则需要通过用户选择来动态地进行。
在jQuery中包含另一个文件是有效的,因为默认情况下不会缓存脚本。因此,我们可以安全地调用其他脚本。通话可以这样安排:$.getScript
[HTML全文]
<select class="choice">
<option value="script1" selected>Script-1</option>
<option value="script2">Script-2</option>
</select>
JavaScript的
$(".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 ) {
// Execute here
});
}
// script2
function script2() {
$.getScript($.url2, function( data, textStatus, jqxhr ) {
// Execute here
});
}
是的,有...
继续阅读。在 ES6 中,我们可以将部分或整个 JavaScript 文件放入另一个文件中......export
import
但是等等,并非所有浏览器都支持 ES6,因此您需要使用例如...babel.js
因此,您可以创建一个如下所示的类:
class Person {
constructor(name) {
this.name = name;
}
build() {
return new Person(this);
}
}
module.exports = Person;
在另一个 JavaScript 文件中,执行如下导入:
import { Person } from 'Person';
您还可以要求以下文件:
const Person = require('./Person');
如果您使用的是较旧的 JavaScript 版本,则可以使用 requirejs:
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这样的东西:
jQuery.getScript('./another-script.js', function() {
// Call back after another-script loaded
});
最后但并非最不重要的一点是,不要忘记您可以使用标签将脚本放在一起的传统方式......<script>
<script src="./first-script.js"></script>
<script src="./second-script.js"></script>
<script src="./third-script.js"></script>
还有我应该在这里提到的 async 和 defer 属性......
注意:有几种方法可以执行外部脚本:
- 如果存在异步:脚本异步执行 与页面的其余部分(脚本将在页面执行时执行 继续解析)
- 如果 async 不存在且 defer 为 present:脚本在页面完成后执行 解析
- 如果 async 和 defer 都不存在:脚本是 在浏览器继续之前立即获取并执行 解析页面
仅适用于 Node.js,这对我最有效!
我在这里尝试了大多数解决方案,但没有一个能帮助我能够在不改变范围的情况下加载另一个文件。最后我用了这个。这保留了范围和一切。在这一点上,它和你的代码一样好。
const fs = require('fs');
eval(fs.readFileSync('file.js') + '');
评论
+ ''
使用与 Node.js 配合使用的 ES6 导入和导出模块
使用扩展名而不是.mjs
.js
创建文件
touch main.mjs lib.mjs
main.js
import { add } from './lib.mjs';
console.log(add(40, 2));
库.mjs
export let add = (x,y) => {
return x + y
}
跑
node --experimental-modules main.js
有几种方法可以在 JavaScript 中实现模块。以下是两个最受欢迎的:
ES6 模块
浏览器还不支持这种调制系统,所以为了使用这种语法,你必须使用像 Webpack 这样的打包器。无论如何,使用打包器会更好,因为这可以将所有不同的文件组合成一个(或几个相关)文件。这将更快地将文件从服务器提供给客户端,因为每个 HTTP 请求都伴随着一些相关的开销。因此,通过减少整体 HTTP 请求,我们提高了性能。以下是 ES6 模块的示例:
// 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(在 Node.js 中使用)
此调制系统用于 Node.js。基本上,您将导出添加到一个名为 .然后,您可以通过 .这里重要的是要意识到这些模块正在被缓存,所以如果你对某个模块进行了两次缓存,它将返回已经创建的模块。module.exports
require('modulePath')
require()
// 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
我用另一种方法尝试了这个问题,
脚本导入的顺序,在这里不起作用。
索引.html
<!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>
<h3>testing js in js (check console logs)</h3>
<button onclick="fnClick()">TEST</button>
</body>
</html>
main.js
function fnClick() {
console.log('From\tAAAAA');
var pro = myExpo.hello();
console.log(pro);
}
脚本.js
myExpo = {
hello: function () {
console.log('From\tBBBBB');
return "Hello";
}
}
结果是
From AAAAA
From BBBBB
Hello
按顺序动态加载多个脚本
如果您只加载一个脚本或不关心多个脚本的加载顺序,则上述函数可以正常工作。如果某些脚本依赖于其他脚本,则需要使用 Promise 来指定加载顺序。这背后的原因是 Javascript 异步加载脚本和图像等资源。加载顺序不依赖于异步调用的顺序,这意味着即使您在调用之前调用,也不能保证 script1 在 script2 之前加载dynamicallyLoadScript("scrip1")
dynamicallyLoadScript("scrip2")
因此,这是另一个保证加载顺序的 dynamicallyLoadScript 版本:
// 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);
});
}
有关 Promise 的更多信息,请参阅此优秀页面。
这个新的 dynamicallyLoadScript 的用法非常简单:
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 等顺序加载。
在脚本加载后运行依赖代码
此外,还可以在加载脚本后立即运行使用脚本的代码。只需在加载脚本后添加另一个:.then
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...
处理加载错误
若要显示未处理的 promise 拒绝(加载脚本时出错等),请将此事件侦听器放在代码的顶部:unhandledrejection
// 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
});
现在,您将收到任何脚本加载错误的通知。
快捷功能
如果您要加载大量脚本,而没有在加载后立即执行代码,则此速记函数可能会派上用场:
function dynamicallyLoadScripts(urls) {
if (urls.length === 0)
return;
let promise = dynamicallyLoadScript(urls[0]);
urls.slice(1).forEach(url => {
promise = promise.then(() => dynamicallyLoadScript(url));
});
}
要使用它,只需传入一个脚本 url 数组,如下所示:
const scriptURLs = ["dist/script1.js", "dist/script2.js", "dist/script3.js"];
dynamicallyLoadScripts(scriptURLs);
脚本将按照它们在数组中的显示顺序加载。
评论
您可以使用我的 loadScript ES 模块来加载 JavaScript 文件。
用法:
在 head 标记中,包含以下代码:
<script src="https://raw.githack.com/anhr/loadScriptNodeJS/master/build/loadScript.js"></script>
或
<script src="https://raw.githack.com/anhr/loadScriptNodeJS/master/build/loadScript.min.js"></script>
现在,您可以使用 window.loadScript 加载 JavaScript 文件。
loadScript.async( src, [选项] )
异步加载 JavaScript 文件。
src
:外部脚本文件的 URL 或脚本文件名的数组。
options
:以下选项可用
onload: function () The onload event occurs when a script has been loaded. Default is undefined.
onerror: function ( str, e ) The onerror event occurs when an error has been occurred. The default is undefined.
str: error details
e: event
appendTo: The node to which the new script will be append. The default is the head node.
例如
loadScript.async( "JavaScript.js",
{
onload: function () {
var str = 'file has been loaded successfully';
console.log( str );
},
onerror: function ( str, e ) {
console.error( str );
},
} );
丹·达斯卡莱斯库(Dan Dascalescu)的回答摘自Facebook的想法,对图书馆进行了一些扩展。
(function() {
var __ = {};
this._ = function(name, callback) {
if(__[name]==undefined) {
__[name] = true;
var firstScript = document.getElementsByTagName('script')[0],
js = document.createElement('script');
js.src = name;
js.onload = callback;
firstScript.parentNode.insertBefore(js, firstScript);
}
}
})();
(new _('https://cdnjs.cloudflare.com/ajax/libs/Snowstorm/20131208/snowstorm-min.js', function() {
snowStorm.snowColor = '#99ccff';
}));
ES6 模块
是的,在脚本标签中使用 type=“module” (support):
<script type="module" src="script.js"></script>
在一个文件中,包括另一个文件,如下所示:script.js
import { hello } from './module.js';
...
// alert(hello());
在“module.js”中,您必须导出要导入的函数/类:
export function hello() {
return "Hello World";
}
这里有一个工作的例子。
所以这是一个边缘情况。但是,如果您需要从远程源加载 JavaScript,大多数现代浏览器可能会由于 CORS 或类似原因而阻止您的跨站点请求。太正常了
<script src="https://another-domain.com/example.js"></script>
行不通。这样做也不会削减它。相反,您可以做的是通过标准请求将 JavaScript 代码加载为资源,然后执行以下操作:document.createElement('script').src = '...'
GET
<script type="text/javascript">
var script = document.createElement('script');
script.type = 'text/javascript';
let xhr = new XMLHttpRequest();
xhr.open("GET", 'https://raw.githubusercontent.com/Torxed/slimWebSocket/master/slimWebSocket.js', true);
xhr.onreadystatechange = function() {
if (this.readyState === XMLHttpRequest.DONE && this.status === 200) {
script.innerHTML = this.responseText; // <-- This one
document.head.appendChild(script);
}
}
xhr.send();
</script>
通过自己抓取内容,浏览器不会注意到恶意意图,并允许您执行请求。然后,将其添加到 中。这仍然会导致浏览器(至少在 Chrome 中测试过)解析/执行脚本。<script>
innerHTML
同样,这是一个边缘用例。而且您可能没有向后兼容性或浏览器合规性。但是有趣/有用的事情要知道。
我没有看到一个答案,即您在一个文件中创建所有函数和变量的对象,然后将该对象作为参数以在另一个文件中引用它。
例如,您有名为“jsMod.js”、“jsView”和“jsContr.js”的文件:
文件 jsMod.js
JSMODOBJ = {};
JSMODOBJ.valueAddition = function(/* element value 1 */ val1, /* element value 2 */ val2) {
return val1 + val2;
}
文件 jsView.js
JSVIEWOBJ = {};
JSVIEWOBJ.elementColour = function(/* element id to change colour */ id, /* css colour classname */ col) {
document.getElementById(id).className = col;
}
文件 jsContr.js
JSCONTROBJ = {};
var jsMod = JSMODOBJ;
var jsView = JSVIEWOBJ;
JSCONTROBJ.changeColourByValue = function (val1, val2, id, clss) {
if (jsMod.valueAddition(val1,val2) !== 0) {
jsView.elementColour(id, clss);
}
}
然后,您可以通过将 .html 或 .php 文件回显来动态设置.js文件:scripts
<?php
echo "<script src = './js/dleafView.js'></script>
<script src = './js/dleafModule.js'></script>
<script src = './js/dleafContr.js'></script>";
?>
然后只需在标签中调用控制函数即可。当然,这在开始时需要花费大量时间进行设置,但从长远来看,它可以节省您的时间。<script type="text/javascript"></script>
我以略有不同的方式使用它,但这种方式也有效。
您还可以将 , , 与 includes 一起使用:gulp
gulp-concat
gulp-typescript
/// <reference path=
文件 packages.json
{
"scripts": {
"gulp": "gulp main"
},
"dependencies": {
"@types/gulp": "^4.0.6",
"@types/gulp-concat",
"@types/gulp-typescript",
"gulp": "^4.0.2",
"gulp-concat": "^2.6.1",
"gulp-resolve-dependencies": "^3.0.1",
"gulp-typescript": "^6.0.0-alpha.1",
"typescript": "^3.7.3"
}
}
文件 src/someimport.ts
class SomeClass {
delay: number;
}
文件 src/main.ts
/// <reference path="./someimport.ts" />
someclass = new SomeClass();
someclass.delay = 1;
此 Gulp.js 任务 (on ) 仅针对文件,解析其所有包含引用。这些包含被称为 ,它们仅用于用于合并文件的转译器工具。在我们的例子中,当检查文件是否缺少类型、变量等时,TypeScript 本身会显式使用它们。main
gulpfile.js
src/main.js
/// <reference path=...
Triple-Slash Directives
.pipe(resolveDependencies({
如果要自定义调用而不使用文件或覆盖其参数,请参阅 gulp-typescript。var tsProject = ts.createProject
tsconfig.json
文件 gulpfile.js
var gulp = require("gulp");
var concat = require('gulp-concat');
var resolveDependencies = require('gulp-resolve-dependencies');
var ts = require("gulp-typescript");
var tsProject = ts.createProject("tsconfig.json");
gulp.task("main", function() {
return gulp
.src(["src/main.ts"])
.pipe(resolveDependencies({
pattern: /^\s*\/\/\/\s*<\s*reference\s*path\s*=\s*(?:"|')([^'"\n]+)/gm
}))
.on('error', function(err) {
console.log(err.message);
})
.pipe(tsProject())
.pipe(concat('main.js'))
.pipe(gulp.dest("build/"));
});
纯 javascript 版本
如果您想以所有 TypeScript 项目文件为目标,而不仅仅是 ,则可以替换以下内容:src/main.ts
return gulp
.src(["src/main.ts"])
.pipe(resolveDependencies({
...
// -->
return tsProject
.src()
.pipe(resolveDependencies({
...
如果你不想使用 TypeScript,你可以使用这个简化的,并从中删除所有 TypeScript 包含:gulpfile.js
package.json
文件 gulpfile.js
var gulp = require("gulp");
var concat = require('gulp-concat');
var resolveDependencies = require('gulp-resolve-dependencies');
gulp.task("main", function() {
return gulp
.src(["src/main.js"])
.pipe(resolveDependencies({
pattern: /^\s*\/\/\/\s*<\s*reference\s*path\s*=\s*(?:"|')([^'"\n]+)/gm
}))
.on('error', function(err) {
console.log(err.message);
})
.pipe(concat('main.js'))
.pipe(gulp.dest("build/"));
});
文件 packages.json
{
"scripts": {
"gulp": "gulp main"
},
"dependencies": {
"gulp": "^4.0.2",
"gulp-concat": "^2.6.1",
"gulp-resolve-dependencies": "^3.0.1"
}
}
然后,在运行命令后,将创建包含以下内容的文件:npm run gulp
build/main.js
文件构建/main.js
class SomeClass {
}
/// <reference path="./someimport.ts" />
someclass = new SomeClass();
someclass.delay = 1;
这允许我在提供目录文件后将其包含在带有标签的浏览器中:script
build
<html>
<head>
<script src="main.js"></script>
</head>
<body>
<script type="text/javascript">
console.log(someclass.delay);
</script>
</body>
</html>
相关问题:
- 打字稿:Gulp
- 我可以在没有 RequireJS 的情况下使用 TypeScript 吗?
- 主文件的简单串联,需要使用 Gulp.js 的另一个 JavaScript 文件
- Node.js 上的客户端:未捕获的引用错误:未定义要求
- 如何使用 Gulp.js 编译 TypeScript 浏览器 Node.js 模块?
- 使用 babel 连接文件
- 如何在浏览器中“需要”CommonJS模块?
- 有没有 Browserify 的替代品?
提出请求和结果。fetch
eval
评论
我的一般解决方案取自 EdgeS(我编写的)的库。efekt.js.st
无耻的插头警报 - 我在其他stackexchange网络站点上。这是
https://codereview.stackexchange.com/questions/263764/dynamic-load-css-or-script
的重新链接。
你会用什么代码或设计来支持和的动态加载?css
scripts
要求
- 支持 promise-await-async,包括错误处理
- 支持一次加载缓存,包括重新加载
- 支持负载 、 或电流
head
body
script-element
- 支持加载、模块或其他脚本类型
css
js
mjs
- 支持其他标签属性,如、等
nonce
crossorigin
static loadScriptOrStyle(url, options) {
// provenance :<# **Smallscript EdgeS efekt** `efekt.js.st` github libraries #>
// returns :<Promise#onload;onerror>
// options :<# `fIgnoreCache`, `fAppendToHead`, `fUrlIsStyle`, `attrs:{}` #>
const head = document.head; let node = options?.fAppendToBody ? document.body : head;
const url_loader_cache = document.head.url_loader_cache
? head.url_loader_cache
: (head.url_loader_cache = {script:{},link:{}})
const kind = (options?.fUrlIsStyle || /\.css(?:(?:\?|#).*)?$/i.test(url))
? 'link' : 'script';
// check already-loaded cache
if(url_loader_cache[kind][url]) {
const el = url_loader_cache[kind][url];
// support `fIgnoreCache` reload-option; should not use on `head`
if(options?.fIgnoreCache)
el.remove();
else
return(new CustomEvent('cache',{detail:el}));
}
// (re)create and record it
const self = document.currentScript;
const el = url_loader_cache[kind][url] = document.createElement(kind);
const append = (!self || options?.fAppendToHead || options?.fAppendToBody)
? el => node.appendChild(el)
: el => self.parentNode.insertBefore(el, self);
const load = new Promise((resolve, reject) => {
el.onload = e => {e.detail = el;resolve(e)};
el.onerror = e => {e.detail = el;reject(e)};
// `onload` or `onerror` possibly alter `cache` value
// throw(new URIError(`The ${url} didn't load correctly.`))
});
// configure `module` attr, as appropriate
if(/\.mjs(?:(?:\?|#).*)?$/i.test(url))
el.type = 'module'
// configure other attrs as appropriate (referrer, nonce, etc)
for(const key in options?.attrs) {el[key] = attrs[key]}
// trigger it
if(kind === 'link') el.rel = 'stylesheet', el.href = url; else el.src = url;
append(el);
return(load);
}
在后端,您可以使用 CommonJS 模块。例如:
//a.js
function func () {
var result = "OK Bro";
return result;
}
module.exports = { func };
//b.js
var a = require('./a.js');
console.log(a.func);
因此,如果您想要快速、轻松地... 试试这个:
function include(filename)
{
var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script');
script.src = filename;
script.type = 'text/javascript';
head.appendChild(script)
}
就是这么简单:
var js = document.createElement("script");
js.type = "text/javascript";
js.src = jsFilePath;
document.body.appendChild(js);
你可以只使用 require();标记。
例如,如果我有一个 addition.js 模块,我想将其添加到 math.js 中,我会这样做:
//this is math.js
//vars
let a = 1;
let b = 3;
//start of code
const additionfile = require('addition.js');
window.alert("You added " + a + " and " + b + " together, to get " + additionfile.add(a,b) + "!");
如果您想要 addition.js 文件,它将如下所示
function add(a,b) {
const sum = a + b;
return sum;
}
评论
Uncaught ReferenceError: require is not defined
这是最简单的解决方案。使用像 Vite.js 这样的打包器,然后简单地执行:
import "./path/to/js/file";
就是这样!OP 要求像“在 CSS 中”这样的东西,这完全是这样。它也不像一些旧方法那样复杂。这至少无疑是最适合初学者的方法,但我相信非初学者也喜欢它。@import
要开始使用 Vite 进行普通 JavaScript 项目,只需安装 Node.js 和 [NPM3,然后执行:
npm create vite@latest <your-vanilla-js-app-name> --template vanilla
例如:
npm create vite@latest my-js-app --template vanilla
现在添加导入,如本答案开头所述,然后收工。
顺便说一句:另外,您可能会想到的另一件事是命名空间问题,例如,如果您在要包含的文件中使用的名称与您当前文件中已有的名称相似,该怎么办?但这就是 JavaScript 的本质,对吧?这不是特定于此方法的问题。
因此,您需要制定单独处理的策略。Addy Osmani 的博客上有一篇全面的文章,如果你想了解更多相关信息:在 JavaScript 中处理全局命名空间的设计模式。
评论
npm run dev
要在 JavaScript 中导入另一个脚本,请使用关键字:import
import '/src/js/example.js';
// both types of quotes work
import "/src/js/example2.js";
如果你想有一个指向位于不同文件中的所有 javascript 函数的链接,你可以使用 php 做这样的事情:
创建一个 php 文件,该文件将存储您所有的 javascript 函数/触发器,并确保它是一个文件:javascript.php
.php
在您的<head>
部分
<script src="/directory/javascript.php"></script>
假设您有一个名为 JavaScript 文件的文件夹,其中所有 javascript 文件都位于其中。在您的 中,创建一个内容类型的标头,并使用 php 包含所有 javascript 文件/脚本,如下所示:/functions
javascript.php
application/javascript
glob
javascript.php
<?php
header("content-type:application/javascript");
foreach(glob("/functions/*.js") as $filename){include($filename);}
?>
现在,您可以创建单独的 javascript 文件并将它们添加到您的文件夹中,或者您可以称呼它的任何内容。这些将自动包含在文件中,该文件实际上是一个正常运行的 js 文件,您可以在您的部分中链接该文件。/functions
javascript.php
<head>
我假设您正在从同一目录导入文件,如果没有,您可以更新路径以适合路径。
要在同一目录中导入另一个 JavaScript 文件,可以使用 ES6 语句。假设您有两个文件,并且 ,它们都位于同一目录中,您可以按如下方式导入:import
main.js
helper.js
helper.js
main.js
在帮助程序.js中:
export function helperFunction() {
// helper function code
}
在 main.js 中:
import { helperFunction } from './helper.js';
// use helper function
helperFunction();
import 语句后跟要导入的函数或变量的名称,以及文件的路径,以指示它位于当前目录中。./
请注意,文件扩展名 .js 通常在 import 语句中省略,但如果您愿意,可以包含它。
请确保在 HTML 文件中包含适当的脚本标记,以加载 main.js 和 helper.js。
包含 JS 内部 URL 路径
function createElement(urlPath) {
let s = document.createElement("script");
s.url = urlPath
document.body.appendChild(s);
}
function includeMoreJsPath(jsFilePath) {
for(let path of jsFilePath){
createElement(path)
}
}
includeMoreJsPath(["/path/to/some/file.js","/path/to/some/file2.js"]);
/*
<script src="/path/to/some/file.js"></script>
<script src="/path/to/some/file2.js"></script>
*/
包含外部 JS URL 路径
,或者您可以直接从文本eval
code
function createElement(code) {
let s = document.createElement("script");
s.appendChild(document.createTextNode(code));
document.body.appendChild(s);
}
async function includeMoreJsPath(jsFilePath) {
for(let path of jsFilePath){
let code = await(await fetch(path)).text()
createElement(code)
}
}
includeMoreJsPath(["'https://cdn.jsdelivr.net/momentjs/2.17.1/moment.min.js'"]);
/*
<script> ...code... </script>
*/
评论