如何在另一个JavaScript文件中包含JavaScript文件?
JavaScript中是否存在类似于@import
CSS的内容,允许您在另一个JavaScript文件中包含JavaScript文件?
回答
旧版本的JavaScript没有导入,包含或要求,因此开发了许多不同的方法来解决这个问题.
但自2015年(ES6)以来,JavaScript已经有了ES6模块标准来导入Node.js中的模块,大多数现代浏览器也支持这些模块.
为了与旧版浏览器兼容,可以使用构建和/或转换工具.
ES6模块
自v8.5起,Node.js中支持ECMAScript(ES6)模块,带有--experimental-modules
标志.涉及的所有文件必须具有.mjs
扩展名.
// module.mjs
export function hello() {
return "Hello";
}
// 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的当前支持.
<script type="module">
import { hello } from './hello.mjs';
hello('world');
</script>
// hello.mjs
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
Node.js需要
仍然在Node.js中广泛使用的旧模式导入模块是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调用加载其他脚本,然后使用eval
它来运行它.这是最简单的方法,但由于JavaScript沙箱安全模型,它仅限于您的域.使用eval
也打开了通往错误,黑客和安全问题的大门.
获取加载
与Dynamic Imports一样,您可以fetch
使用promises 加载一个或多个脚本,使用Promise来控制脚本依赖项的执行顺序,使用Fetch Inject库:
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的库提供加载功能在同一行:
$.getScript("my_lovely_script.js", function() {
alert("Script loaded but not necessarily executed.");
});
动态脚本加载
您可以将带有脚本URL的脚本标记添加到HTML中.为了避免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)
}
此函数将<script>
在页面的head部分的末尾添加一个新标记,其中该src
属性设置为作为第一个参数赋予函数的URL.
这两个解决方案都在JavaScript疯狂:动态脚本加载中进行了讨论和说明.
检测脚本何时执行
现在,您必须了解一个大问题.这样做意味着您远程加载代码.现代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加载之后或之前执行,具体取决于浏览器以及是否包含该行script.async = false;
.有一篇关于Javascript加载的文章,讨论了这个问题.
源代码合并/预处理
截至本答案的上方所提到的,许多开发人员使用编译/ transpilation工具(S),如包裹,的WebPack,或者巴贝尔在自己的项目,允许他们使用即将推出的JavaScript语法,旧的浏览器提供向后兼容性,合并文件,缩小,执行代码拆分等
- 为了完成,还有第三种方法:在某些解决方案中,当你控制两个javascript文件时,你可以制作一个巨大的javascript文件,它结合了两个文件的内容.
- 没有人使用像Rhino这样先进的东西,否则不会问这个问题.
- 不应该"document.createElement("my_lovely_script.js");" 在示例中是"document.createElement("script")"?
- 如果你正在执行你的代码,eval如何打开hack的大门?
- 您的答案需要对IE进行一些修改(`onreadystatechange`事件和`readyState`属性).此外,动态脚本加载不会受益于broswer的预加载扫描程序.推荐这篇HTML5Rocks文章:http://www.html5rocks.com/en/tutorials/speed/script-loading/
- 通过ajax加载脚本和发布表单是jQuery展示其优势的地方.
- 我不是说盗版,而是说骇客。例如,如果您的代码中包含“严格使用”,则必须彻底解决它,以使其与eval一起使用。
- 但我的页面不知道`JQUERY`这正是我想要添加的!该怎么办?
如果有人正在寻找更高级的东西,请尝试RequireJS.您将获得额外的好处,例如依赖关系管理,更好的并发性,并避免重复(即,多次检索脚本).
您可以在"模块"中编写JavaScript文件,然后在其他脚本中将它们作为依赖项引用.或者您可以将RequireJS用作简单的"go get this script"解决方案.
例:
将依赖项定义为模块:
一些-dependency.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
});
implementation.js是依赖some-dependency.js的 "主"JavaScript文件
require(['some-dependency'], function(dependency) {
//Your script goes here
//some-dependency.js is fetched.
//Then your script is executed
});
摘自GitHub自述文件:
RequireJS使用普通脚本标记来加载模块/文件,因此它应该允许轻松调试.它可以简单地用于加载现有的JavaScript文件,因此您可以将其添加到现有项目中,而无需重新编写JavaScript文件.
...
- -1:那些抽象 - "some_dependency" - 非常糟糕,索引增加了混乱.我很难理解工作代码示例的样子.如果作者提供了工作示例,几乎任何人都可以根据自己的需要进行定制和推广.
实际上有一种方法可以非异步地加载JavaScript文件,因此您可以在加载后立即使用新加载的文件中包含的函数,我认为它适用于所有浏览器.
您需要jQuery.append()
在<head>
页面元素上使用,即:
$("head").append('<script type="text/javascript" src="' + script + '"></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 type="text/javascript" src="' + script + '"></script>');
import_js_imported.push(script);
}
}
});
})(jQuery);
所以你需要做的就是导入JavaScript:
$.import_js('/path_to_project/scripts/somefunctions.js');
我也在Example中做了一个简单的测试.
它包括一个main.js
主HTML文件,然后在脚本中main.js
使用$.import_js()
导入称为一个附加文件included.js
,它定义了这个功能:
function hello()
{
alert("Hello world!");
}
在包括之后included.js
,hello()
调用该函数,您就会收到警报.
(这个答案是对e-satisf'评论的回应).
- @juanpastas - 使用[`jQuery.getScript`](http://api.jquery.com/jQuery.getScript/),这样你就不必担心编写插件......
- 嗯,根据[本文](http://www.html5rocks.com/en/tutorials/speed/script-loading/),将`script`元素附加到`head`会导致它以异步方式运行,除非`async`专门设置为`false`.
另一种方式,在我看来更清晰,是制作同步Ajax请求而不是使用<script>
标记.这也是Node.js处理的方式.
这是使用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);
}
});
}
然后,您可以在代码中使用它,因为您通常使用包含:
require("/scripts/subscript.js");
并且能够在下一行中从所需脚本调用函数:
subscript.doSomethingCool();
- 正如其他人提到的那样,requirejs.org执行此操作并且还有一个预编译器将js文件放在一起,以便加载更快.你可能想看一下.
- 不幸的是,async:false现在已经在jQuery中弃用了.未来可能会破裂,所以我会避免.
- @katsh我们这里没有使用jqXHR对象.您的引用似乎没有备份您之前的评论,声称`async:false`据称已被弃用.它不是!正如你的引用所述,只有jqXHR相关的东西是.
- 发现我可以通过在Chrome文件底部添加此指令来调试它:// @ sourceURL = view_index.js
对你来说有一个好消息.很快您就可以轻松加载JavaScript代码了.它将成为导入JavaScript代码模块的标准方式,并将成为核心JavaScript本身的一部分.
您只需编写import cond from 'cond.js';
以加载cond
从文件命名的宏cond.js
.
因此,您不必依赖任何JavaScript框架,也不必显式地进行Ajax调用.
参考:
- jsfile上的require/import在接下来的时间太长了.(IMO).
- 2015年中期 - 仍未在任何浏览器中实施,https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#Browser_compatibility
- @rwheadon是啊骇人听闻,这不是语言的一部分!如何让人们完成任何事情都超出我的意义!我是新手,这似乎是最糟糕的(很多)疯狂的
可以动态生成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");
- @ e-satisf - 实际上,这是一个优势,同步脚本将被阻止.课程的马匹,但10个中的9次你想要非阻塞选项.
- @ e-satisf异步很好,因为它不会冻结你的页面.当回调完成时,使用回调来通知`js.onload = callback;`
- 它确实有效,但由于异步负载而存在严重问题.
声明import
在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;
- 您现在可以编写ES6代码并使用Babel.js(https://babeljs.io)将其编译为您首选的当前模块系统(CommonJS/AMD/UMD):https://babeljs.io/docs/usage/模块/
也许您可以使用我在此页面上找到的此功能如何在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)
}
- 添加`script.onload = callback;`应该很有用
这是没有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
在其响应中设置标头.
- @heinob:我能做些什么来让它适用于跨域?*(从http://web.archive.org/web/20140905044059/http://www.howtocreate.co.uk/operaStuff/userjs/aagmfunctions.js`)加载脚本
- @ user2284570:我理解您的评论,即您不是要加载脚本的域的所有者.在这种情况下,您只能通过插入的`<script>`标记加载脚本,而不是通过`XMLHttpRequest`.
- 对于计划在Firefox中使用它的人(比如imacros脚本),将这一行添加到文件的顶部:`const XMLHttpRequest = Components.Constructor("@ mozilla.org/xmlextras/xmlhttprequest;1");`
我刚写了这个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="https://qa.1r1g.com/sf/ask/66506121/prototype.js"></script>
<script src="https://qa.1r1g.com/sf/ask/66506121/require.js"></script>
<script>
require(['foo.js','bar.js'], function () {
/* Use foo.js and bar.js here */
});
</script>
要点:http://gist.github.com/284442.
- jrburke将此写为RequireJS.Github:http://requirejs.org/docs/requirements.html
以下是Facebook为普遍使用的Like按钮做广告的一般化版本:
<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,它将适合您.
为什么我们寻找的第一个原因script
元素代替head
或者body
是因为有些浏览器不创建一个,如果缺少,但我们保证有一个script
元素-这一个.欲了解更多信息,请访问http://www.jspatterns.com/the-ridiculous-case-of-adding-a-script-element/.
- 该死的好!这里的一些方法也有效,但在动态设置下,这种方法效果最好.
如果你想要纯JavaScript,你可以使用document.write
.
document.write('<script src="https://qa.1r1g.com/sf/ask/66506121/myscript.js" type="text/javascript"></script>');
如果使用jQuery库,则可以使用该$.getScript
方法.
$.getScript("another_script.js");
- 不会document.write删除其他一切?
您还可以使用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中
此处显示的大多数解决方案都意味着动态加载.我正在搜索一个编译器,它将所有依赖的文件组合成一个输出文件.与Less/Sass预处理器相同,处理CSS @import
at-rule.由于我没有找到这种类似的东西,我写了一个简单的工具来解决这个问题.
所以这里是编译器,https://github.com/dsheiko/jsic,它可以$import("file-path")
安全地替换所请求的文件内容.这是相应的Grunt插件:https://github.com/dsheiko/grunt-jsic.
在jQuery master分支上,他们只是简单地将原子源文件连接成一个intro.js
以outtro.js
.开头和结尾的单个文件.这不适合我,因为它没有提供源代码设计的灵活性.看看它如何与jsic一起使用:
SRC/main.js
var foo = $import("./Form/Input/Tel");
SRC /表格/输入/ 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(){}
}
};
- 从这篇文章开始,我提出了更好的解决方案 - CommonJS模块编译器 - https://github.com/dsheiko/cjsc因此,您可以简单地编写CommonJs或NodeJs模块并相互访问,同时将它们保持在隔离的范围内.好处:不需要多个影响性能的HTTP请求您不需要手动包装模块代码 - 它是编译器的责任(因此更好的源代码可读性)您不需要任何外部库它与UMD兼容 - 和NodeJs模块(例如,您可以将jQuery,Backbone作为模块解决而无需触及其代码)
如果您要加载JavaScript文件的意图是使用导入/包含文件中的函数,您还可以定义全局对象并将函数设置为对象项.例如:
global.js
A = {};
file1.js
A.func1 = function() {
console.log("func1");
}
file2.js
A.func2 = function() {
console.log("func2");
}
main.js
A.func1();
A.func2();
在HTML文件中包含脚本时,您需要小心.订单应如下所示:
<head>
<script type="text/javascript" src="https://qa.1r1g.com/sf/ask/66506121/global.js"></script>
<script type="text/javascript" src="https://qa.1r1g.com/sf/ask/66506121/file1.js"></script>
<script type="text/javascript" src="https://qa.1r1g.com/sf/ask/66506121/file2.js"></script>
<script type="text/javascript" src="https://qa.1r1g.com/sf/ask/66506121/main.js"></script>
</head>
这应该做:
xhr = new XMLHttpRequest();
xhr.open("GET", "/soap/ajax/11.0/connection.js", false);
xhr.send();
eval(xhr.responseText);
- @MattDMo"有人说这很糟糕"并不是真正的争论.
- @MattDMo我完全清楚他是谁,但他是一个人,而不是一个神.
- `eval`是它的错误.来自[Crockford](http://javascript.crockford.com/code.html),"eval"是邪恶的."eval"函数是JavaScript中最被滥用的特性.避免它.`eval`有别名.不要使用`Function`构造函数.不要将字符串传递给`setTimeout`或`setInterval`." 如果您还没有阅读他的"JavaScript:The Good Parts",那么现在就去做吧.你不会后悔的.
- @emodendroket我认为你不知道谁是[Douglas Crockford](http://en.wikipedia.org/wiki/Douglas_Crockford).
- @tggagne:我可以做些什么来让它适用于跨域?*(从http://web.archive.org/web/20140905044059/http://www.howtocreate.co.uk/operaStuff/userjs/aagmfunctions.js`)加载脚本
或者不是在运行时包括在上载之前使用脚本连接.
我使用链轮(我不知道是否还有其他链轮).您可以在单独的文件中构建JavaScript代码,并包含由Sprockets引擎作为包括处理的注释.对于开发,您可以按顺序包含文件,然后生产以合并它们...
也可以看看:
- 介绍Sprockets:JavaScript依赖关系管理和连接
如果您正在使用Web Workers并希望在worker的范围内包含其他脚本,则提供有关向head
标记添加脚本等的其他答案将不适合您.
幸运的是,Web Workers有自己的importScripts
功能,这是Web Worker范围内的全局功能,是浏览器本身的原生功能,因为它是规范的一部分.
或者,作为对您的问题突出显示的第二高投票答案,RequireJS还可以处理包含Web Worker中的脚本(可能调用importScripts
自身,但具有一些其他有用的功能).
我有一个简单的问题,但我对这个问题的回答感到困惑.
我不得不在另一个JavaScript文件(main.js)中使用一个JavaScript文件(myvariables.js)中定义的变量(myVar1).
为此,我做了如下:
以正确的顺序加载HTML文件中的JavaScript代码,首先是myvariables.js,然后是main.js:
<html>
<body onload="bodyReady();" >
<script src="https://qa.1r1g.com/sf/ask/66506121/myvariables.js" > </script>
<script src="https://qa.1r1g.com/sf/ask/66506121/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文件中自动访问.
这节省了我的一天.我希望这有帮助.
ES6 模块
是的,在脚本标签中使用 type="module" ( support ):
<script type="module" src="https://qa.1r1g.com/sf/ask/66506121/script.js"></script>
在一个script.js
文件中包含另一个文件,如下所示:
import { hello } from './module.js';
...
// alert(hello());
在“module.js”中,您必须导出您将导入的函数/类:
export function hello() {
return "Hello World";
}
一个工作示例是here。
在@import
实现CSS-像JavaScript语法进口可能使用的工具,如通过其特殊的混合.mix
文件类型(见这里).我想应用程序只是在内部使用上述方法之一,但我不知道.
从文件的混合文档.mix
:
这是一个.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无任何关联.我看到一个.mix
JavaScript文件在运行中(在其中一个Mixture样板中)并且有点困惑("你能做到这一点吗?"我想到了自己)时遇到了这个问题.然后我意识到这是一个特定于应用程序的文件类型(有点令人失望,同意).然而,认为这些知识可能对其他人有所帮助.
更新:混合物现在是免费的(离线).
更新:混合物现已停产.旧的混合物发布仍然可用
我通常的方法是:
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方法(其他一个答案),但它似乎对我来说效果不佳.
下面解释代码如何为那些好奇的代码工作:实际上,它创建了一个新的脚本标记(在第一个之后).它将其设置为异步模式,因此它不会阻止其余代码,但在readyState(要加载的内容的状态)更改为"已加载"时调用回调.
用现代语言来说就是这样
function loadJs( url ){
return new Promise( resolve => {
const script = document.createElement( "script" );
script.src = url;
script.onload = resolve;
document.head.appendChild( script );
});
}
var js = document.createElement("script");
js.type = "text/javascript";
js.src = jsFilePath;
document.body.appendChild(js);
- 这是最简单的代码,但是[在`body`尚不存在的情况下会失败](http://stackoverflow.com/questions/950087/include-a-javascript-file-in-another-javascript -file/31282622#31282622)或无法修改.此外,它有助于解释答案.
我编写了一个简单的模块,可以自动执行在JavaScript中导入/包含模块脚本的工作.有关代码的详细说明,请参阅博客文章JavaScript require/import/include模块.
// ----- 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);
};
虽然这些答案很棒,但是存在一个简单的"解决方案",因为脚本加载已存在,它将覆盖大多数人的99.999%的用例.只需在需要它的脚本之前包含所需的脚本.对于大多数项目,确定需要哪些脚本以及按什么顺序排列并不需要很长时间.
<!DOCTYPE HTML>
<html>
<head>
<script src="https://qa.1r1g.com/sf/ask/66506121/script1.js"></script>
<script src="https://qa.1r1g.com/sf/ask/66506121/script2.js"></script>
</head>
<body></body>
</html>
如果script2需要script1,这确实是做这样的事情的绝对最简单的方法.我很惊讶没有人提出这个问题,因为这是几乎每一个案例中最明显和最简单的答案.
我来到这个问题是因为我正在寻找一种简单的方法来维护一组有用的JavaScript插件.在看到这里的一些解决方案之后,我想出了这个:
-
//当我们添加或删除插件文件时设置要更新的数组var pluginNames = ["lettering","fittext","butterjam"等]; //每个插件的一个脚本标签$ .each(pluginNames,function(){$('head').append('');});
我发现即使所有的插件都按照它们应该的方式放入头标签,但当你点击页面或刷新时,它们并不总是被浏览器运行.
我发现在PHP包中编写脚本标记更可靠.您只需编写一次,这与使用JavaScript调用插件一样重要.
此脚本将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);
})();
还有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
方法一样方便.它还具有一些高级功能,如条件加载,功能检测等等.
这个问题有很多潜在的答案.我的回答显然基于其中的一些.这是我在阅读完所有答案后最终得到的结果.
$.getScript
加载完成后需要回调的任何其他解决方案的问题是,如果您有多个文件使用它并相互依赖,则您无法知道何时加载所有脚本(一旦它们被嵌套在多个文件中).
例:
file3.js
var f3obj = "file3";
// Define other stuff
file2.js:
var f2obj = "file2";
$.getScript("file3.js", function(){
alert(f3obj);
// Use anything defined in file3.
});
file1.js:
$.getScript("https://qa.1r1g.com/sf/ask/66506121/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时,你是对的,但当前的趋势似乎是弃用同步请求,所以你现在或将来可能无法获得完整的浏览器支持.
您可以尝试使用$.when
来检查延迟对象的数组,但是现在您在每个文件中执行此操作,并且file2将在$.when
执行时被视为已加载,而不是在执行回调时,因此file1仍然在加载file3之前继续执行.这仍然有同样的问题.
我决定倒退而不是前锋.谢谢document.writeln
.我知道这是禁忌,但只要使用得当,这种方法效果很好.您最终得到的代码可以轻松调试,正确显示在DOM中,并且可以确保正确加载依赖项的顺序.
你当然可以使用$("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";
});
文件1:
$.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"
});
这是使用HTML导入的浏览器(不是Node.js)的解决方法.
首先,所有的JavaScript类和脚本不是.js
文件,而是在.js.html
文件(.js文件,html
仅仅是HTML页面和完整的JavaScript脚本/类之间的认识),里面<script>
的标签,就像这样:
MyClass.js.html
:
<script>
class MyClass {
// Your code here..
}
</script>
然后,如果您想导入您的类,您只需要使用HTML导入:
<link rel="import" href="https://qa.1r1g.com/sf/ask/66506121/relative/path/to/MyClass.js.html"/>
<script>
var myClass = new MyClass();
// Your code here..
</script>
编辑:HTML导入将被删除
HTML导入和ES6模块已经在世界上大多数浏览器中得到很好的实现.但是由于HTML导入绝对不会成为标准的一部分,与ES6模块不同,它的开发将被删除,那么你应该明确地开始使用ES6模块.
有几种方法可以在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(用于NodeJS)
该模块系统用于NodeJS.您基本上将导出添加到被调用的对象module.exports
.然后,您可以通过a访问此对象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
我创建了一个函数,允许您使用与C#/ Java类似的措辞来包含JavaScript文件.我甚至从另一个 JavaScript文件内部测试了一下它似乎工作.它确实需要jQuery,但最后需要一些"魔术".
我把这段代码放在脚本目录根目录下的文件中(我把它命名为global.js
,但是你可以使用你想要的任何东西.除非我弄错了,jQuery应该是给定页面上唯一需要的脚本.请记住这一点除了一些基本用法之外基本上没有经过测试,因此我可能会或可能不会有任何问题;使用自己的风险yadda yadda如果你把yadda yadda搞砸了,我不负责任:
/**
* @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="https://qa.1r1g.com/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 本身的功能。
保持简洁,简洁,可维护!:]
// 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]);
}
}
此代码只是一个简短的功能示例,可能需要其他功能,以便在任何(或给定)平台上提供全面支持.
我基本上像下面这样做,创建一个新元素并将其附加到头部:
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.
});
仅限NodeJS,这对我来说是最好的!
我在这里尝试了大多数解决方案,但没有人帮助我只是在不改变范围的情况下加载另一个文件.最后我用了这个.这保留了范围和一切.它就像你的代码那样好.
const fs = require('fs');
eval(fs.readFileSync('file.js')+'');
更好地使用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 脚本中,然后再按一个回车。PHP 会忽略 JavaScript 注释“//”,因此无论如何都会发生包含。回车的目的是为了不注释掉包含的 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)
};
这是一个Grunt插件,允许您@import "path/to/file.js";
在任何文件中使用语法,包括JavaScript文件.它可以与uglify或手表或任何其他插件配对.
它可以使用npm install安装:https://npmjs.org/package/grunt-import
这也许是另一种方式!
在 Node.js 中,您可以像以下代码所示那样执行此操作!
子.js
module.exports = {
log: function(string) {
if(console) console.log(string);
}
mylog: function(){
console.log('just for log test!');
}
}
主文件
const mylog = require('./sub');
mylog.log('Hurray, it works! :)');
mylog.mylog();
参考
http://requirejs.org/docs/node.html
是的,有...
请继续阅读,在ES6,我们可以export
和import
部分或全部JavaScript文件到另一个...
但是,等等,并不是所有的浏览器都支持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="https://qa.1r1g.com/sf/ask/66506121/first-script.js"></script>
<script src="https://qa.1r1g.com/sf/ask/66506121/second-script.js"></script>
<script src="https://qa.1r1g.com/sf/ask/66506121/third-script.js"></script>
还有async和defer属性,在这里我应该提到它们...
- 如果存在异步:脚本与页面的其余部分异步执行(脚本将在页面继续解析的同时执行)
- 如果不存在异步且存在延迟:在页面完成解析后执行脚本
- 如果不存在异步或延迟:在浏览器继续解析页面之前,立即获取并执行脚本
我需要异步加载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); });
直到第一个脚本完全加载后,第二个脚本才会加载,因此...
结果:
- `script.onreadystatechange`将永远不会触发。它特定于[`XMLHttpRequest`](https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest)。例如,如果因为您实际上是使用XMLHttpRequest加载脚本而触发了,那将导致您的回调被频繁调用。因此,您应该删除该行。
如果您使用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' ]);
您可以加载外部库(不是角度库):
$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' ]);
这很简单。假设您要在文件 B.js 中导入文件 A.js。
现在确定您已经在 HTML 文件中链接了 B.js,然后只需在该 HTML 文件中的 B.js 之前链接 A.js。然后 A.js 的公共变量将在 B.js 中可用
这不需要复杂的答案。
使用与Node.js一起使用的ES6导入和导出模块
用.mjs
扩展名代替文件名.js
建立档案
touch main.mjs lib.mjs
main.js
import { add } from './lib.mjs';
console.log(add(40, 2));
lib.mjs
export let add = (x,y) => {
return x + y
}
跑
node --experimental-modules main.js
我用另一种方法尝试了这个问题,
脚本导入的顺序,在这里没有影响。
索引.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="https://qa.1r1g.com/sf/ask/66506121/main.js"></script>
<script src="https://qa.1r1g.com/sf/ask/66506121/scriptA.js"></script>
</head>
<body>
<h3>testing js in js (check console logs)</h3>
<button onclick="fnClick()">TEST</button>
</body>
</html>
主文件
function fnClick() {
console.log('FromtAAAAA');
var pro = myExpo.hello();
console.log(pro);
}
脚本A.js
myExpo = {
hello: function () {
console.log('FromtBBBBB');
return "Hello";
}
}
而结果是
From AAAAA
From BBBBB
Hello