Có một cái gì đó trong JavaScript tương tự như @import
trong CSS cho phép bạn bao gồm một tệp JavaScript bên trong một tệp JavaScript khác?
script
thẻ theo thứ tự ?
Có một cái gì đó trong JavaScript tương tự như @import
trong CSS cho phép bạn bao gồm một tệp JavaScript bên trong một tệp JavaScript khác?
script
thẻ theo thứ tự ?
Câu trả lời:
Các phiên bản cũ của JavaScript không có nhập, bao gồm hoặc yêu cầu, vì vậy nhiều cách tiếp cận khác nhau cho vấn đề này đã được phát triển.
Nhưng kể từ năm 2015 (ES6), JavaScript đã có tiêu chuẩn mô-đun ES6 để nhập mô-đun trong Node.js, cũng được hầu hết các trình duyệt hiện đại hỗ trợ .
Để tương thích với các trình duyệt cũ hơn, hãy xây dựng các công cụ như Webpack và Rollup và / hoặc các công cụ dịch mã như Babel có thể sử dụng .
Các mô-đun ECMAScript (ES6) đã được hỗ trợ trong Node.js kể từ v8.5, với --experimental-modules
cờ và vì ít nhất Node.js v13.8.0 không có cờ. Để bật "ESM" (so với hệ thống mô-đun kiểu CommonJS trước đây của Node.js ["CJS"]), bạn có thể sử dụng "type": "module"
trong package.json
hoặc cung cấp cho các tệp phần mở rộng .mjs
. (Tương tự, các mô-đun được viết bằng mô-đun CJS trước đó của Node.js có thể được đặt tên .cjs
nếu mặc định của bạn là ESM.)
Sử dụng package.json
:
{
"type": "module"
}
Sau đó module.js
:
export function hello() {
return "Hello";
}
Sau đó main.js
:
import { hello } from './module.js';
let val = hello(); // val is "Hello";
Sử dụng .mjs
, bạn có module.mjs
:
export function hello() {
return "Hello";
}
Sau đó main.mjs
:
import { hello } from './module.mjs';
let val = hello(); // val is "Hello";
Các trình duyệt đã hỗ trợ tải trực tiếp các mô-đun ECMAScript (không yêu cầu công cụ như Webpack) kể từ Safari 10.1, Chrome 61, Firefox 60 và Edge 16. Kiểm tra hỗ trợ hiện tại tại caniuse . Không cần sử dụng .mjs
tiện ích mở rộng của Node.js ; trình duyệt hoàn toàn bỏ qua phần mở rộng tập tin trên các mô-đun / tập lệnh.
<script type="module">
import { hello } from './hello.mjs'; // Or it could be simply `hello.js`
hello('world');
</script>
// hello.mjs -- or it could be simply `hello.js`
export function hello(text) {
const div = document.createElement('div');
div.textContent = `Hello ${text}`;
document.body.appendChild(div);
}
Đọc thêm tại https://jakearchibald.com/2017/es-modules-in-browsers/
Nhập động cho phép tập lệnh tải các tập lệnh khác khi cần:
<script type="module">
import('hello.mjs').then(module => {
module.hello('world');
});
</script>
Đọc thêm tại https://developers.google.com/web/updates/2017/11/dynamic-import
Kiểu mô-đun CJS cũ hơn, vẫn được sử dụng rộng rãi trong Node.js, là module.exports
/require
system.
// mymodule.js
module.exports = {
hello: function() {
return "Hello";
}
}
// server.js
const myModule = require('./mymodule');
let val = myModule.hello(); // val is "Hello"
Có nhiều cách khác để JavaScript đưa nội dung JavaScript bên ngoài vào các trình duyệt không yêu cầu tiền xử lý.
Bạn có thể tải một tập lệnh bổ sung với một cuộc gọi AJAX và sau đó sử dụng eval
để chạy nó. Đây là cách đơn giản nhất, nhưng nó bị giới hạn trong miền của bạn do mô hình bảo mật hộp cát JavaScript. Sử dụng eval
cũng mở ra cánh cửa cho các lỗi, hack và các vấn đề bảo mật.
Giống như Nhập khẩu động, bạn có thể tải một hoặc nhiều tập lệnh bằng một fetch
cuộc gọi bằng cách sử dụng lời hứa để kiểm soát thứ tự thực hiện cho các phụ thuộc tập lệnh bằng thư viện Fetch Tiêm :
fetchInject([
'https://cdn.jsdelivr.net/momentjs/2.17.1/moment.min.js'
]).then(() => {
console.log(`Finish in less than ${moment().endOf('year').fromNow(true)}`)
})
Các jQuery thư viện cung cấp chức năng tải trong một dòng :
$.getScript("my_lovely_script.js", function() {
alert("Script loaded but not necessarily executed.");
});
Bạn có thể thêm thẻ tập lệnh với URL tập lệnh vào HTML. Để tránh chi phí hoạt động của jQuery, đây là một giải pháp lý tưởng.
Kịch bản thậm chí có thể nằm trên một máy chủ khác. Hơn nữa, trình duyệt đánh giá mã. Các <script>
thẻ có thể được tiêm vào một trong hai trang web <head>
, hoặc chèn ngay trước thẻ đóng </body>
thẻ.
Đây là một ví dụ về cách thức này có thể hoạt động:
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)
}
Hàm này sẽ thêm một <script>
thẻ mới vào cuối phần đầu của trang, trong đó src
thuộc tính được đặt thành URL được cung cấp cho hàm làm tham số đầu tiên.
Cả hai giải pháp này đều được thảo luận và minh họa trong JavaScript Madness: Dynamic Script Loading .
Bây giờ, có một vấn đề lớn bạn phải biết về. Làm điều đó có nghĩa là bạn tải mã từ xa . Các trình duyệt web hiện đại sẽ tải tệp và tiếp tục thực thi tập lệnh hiện tại của bạn vì chúng tải mọi thứ không đồng bộ để cải thiện hiệu suất. (Điều này áp dụng cho cả phương thức jQuery và phương thức tải tập lệnh động thủ công.)
Điều đó có nghĩa là nếu bạn sử dụng các thủ thuật này trực tiếp, bạn sẽ không thể sử dụng mã mới được tải của mình dòng tiếp theo sau khi bạn yêu cầu nó được tải , bởi vì nó sẽ vẫn đang tải.
Ví dụ: my_lovely_script.js
chứa 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
Sau đó, bạn tải lại các trang nhấn F5. Và nó hoạt động! Gây nhầm lẫn...
Vậy giờ làm gì với nó ?
Chà, bạn có thể sử dụng bản hack mà tác giả gợi ý trong liên kết tôi đưa cho bạn. Tóm lại, đối với những người vội vàng, anh ta sử dụng một sự kiện để chạy chức năng gọi lại khi tập lệnh được tải. Vì vậy, bạn có thể đặt tất cả mã bằng thư viện từ xa trong chức năng gọi lại. Ví dụ:
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);
}
Sau đó, bạn viết mã bạn muốn sử dụng SAU kịch bản được tải trong hàm lambda :
var myPrettyCode = function() {
// Here, do whatever you want
};
Sau đó, bạn chạy tất cả:
loadScript("my_lovely_script.js", myPrettyCode);
Lưu ý rằng tập lệnh có thể thực thi sau khi DOM được tải hoặc trước đó, tùy thuộc vào trình duyệt và liệu bạn có bao gồm dòng không script.async = false;
. Có một bài viết tuyệt vời về tải Javascript nói chung về vấn đề này.
Như đã đề cập ở đầu câu trả lời này, nhiều nhà phát triển sử dụng (các) công cụ xây dựng / dịch mã như Parcel, Webpack hoặc Babel trong các dự án của họ, cho phép họ sử dụng cú pháp JavaScript sắp tới, cung cấp khả năng tương thích ngược cho các trình duyệt cũ hơn, kết hợp các tệp, thu nhỏ, thực hiện tách mã, v.v.
onreadystatechange
sự kiện và thuộc readyState
tính). Ngoài ra, tải tập lệnh động không được hưởng lợi từ các máy quét tải trước của broswer's. Đề xuất bài viết HTML5Rocks này: html5rocks.com/en/tutorials/speed/script-loading
Nếu bất cứ ai đang tìm kiếm một cái gì đó cao cấp hơn, hãy thử RequireJS . Bạn sẽ nhận được các lợi ích bổ sung như quản lý phụ thuộc, đồng thời tốt hơn và tránh trùng lặp (nghĩa là truy xuất tập lệnh nhiều lần).
Bạn có thể viết các tệp JavaScript của mình trong "các mô-đun" và sau đó tham chiếu chúng dưới dạng các phụ thuộc trong các tập lệnh khác. Hoặc bạn có thể sử dụng RequireJS như một giải pháp "đi lấy tập lệnh" đơn giản này.
Thí dụ:
Xác định các phụ thuộc dưới dạng các mô-đun:
một số phụ thuộc.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
});
exec.js là tệp JavaScript "chính" của bạn phụ thuộc vào một số phụ thuộc.j
require(['some-dependency'], function(dependency) {
//Your script goes here
//some-dependency.js is fetched.
//Then your script is executed
});
Trích từ GitHub README:
RequireJS tải các tệp JavaScript đơn giản cũng như các mô-đun được xác định rõ hơn. Nó được tối ưu hóa để sử dụng trong trình duyệt, kể cả trong Web Worker, nhưng nó có thể được sử dụng trong các môi trường JavaScript khác, như Rhino và Node. Nó triển khai API mô-đun không đồng bộ.
RequireJS sử dụng các thẻ script đơn giản để tải các mô-đun / tệp, vì vậy nó sẽ cho phép gỡ lỗi dễ dàng. Nó có thể được sử dụng đơn giản để tải các tệp JavaScript hiện có, vì vậy bạn có thể thêm nó vào dự án hiện tại của mình mà không phải viết lại các tệp JavaScript của mình.
...
Thực sự có một cách để tải tệp JavaScript không đồng bộ, vì vậy bạn có thể sử dụng các chức năng có trong tệp mới tải ngay sau khi tải và tôi nghĩ rằng nó hoạt động trong tất cả các trình duyệt.
Bạn cần sử dụng jQuery.append()
trên thành <head>
phần của trang của bạn, đó là:
$("head").append('<script type="text/javascript" src="' + script + '"></script>');
Tuy nhiên, phương pháp này cũng có một vấn đề: nếu xảy ra lỗi trong tệp JavaScript đã nhập, Fireorms (và cả Firefox Error Console và Chrome Developer Tools ) sẽ báo cáo vị trí của nó không chính xác, đó là một vấn đề lớn nếu bạn sử dụng Fireorms để theo dõi Lỗi JavaScript rất nhiều (tôi làm). Firebird chỉ đơn giản là không biết về tệp mới được tải vì một số lý do, vì vậy nếu xảy ra lỗi trong tệp đó, nó báo cáo rằng nó đã xảy ra trong HTML chính của bạn tệp và bạn sẽ gặp khó khăn khi tìm ra lý do thực sự gây ra lỗi.
Nhưng nếu đó không phải là vấn đề với bạn, thì phương pháp này sẽ hoạt động.
Tôi thực sự đã viết một plugin jQuery có tên $ .import_js () sử dụng phương thức này:
(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);
Vì vậy, tất cả những gì bạn cần làm để nhập JavaScript là:
$.import_js('/path_to_project/scripts/somefunctions.js');
Tôi cũng đã thực hiện một thử nghiệm đơn giản cho điều này tại Ví dụ .
Nó bao gồm một main.js
tệp trong HTML chính và sau đó tập lệnh được main.js
sử dụng $.import_js()
để nhập một tệp bổ sung được gọi là included.js
định nghĩa hàm này:
function hello()
{
alert("Hello world!");
}
Và ngay sau khi bao gồm included.js
, hello()
chức năng được gọi và bạn nhận được cảnh báo.
(Câu trả lời này là để đáp lại bình luận của e-satis).
jQuery.getScript
, theo cách đó bạn không phải lo lắng về việc viết plugin ...
script
phần tử vào head
sẽ khiến nó chạy không đồng bộ, trừ khi async
được đặt riêng false
.
"
, mã sẽ bị
Một cách khác, theo tôi là sạch hơn nhiều, là tạo một yêu cầu Ajax đồng bộ thay vì sử dụng <script>
thẻ. Đó cũng là cách xử lý Node.js bao gồm.
Đây là một ví dụ sử dụng 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);
}
});
}
Sau đó, bạn có thể sử dụng nó trong mã của mình vì bạn thường sử dụng bao gồm:
require("/scripts/subscript.js");
Và có thể gọi một hàm từ tập lệnh được yêu cầu trong dòng tiếp theo:
subscript.doSomethingCool();
async: false
được cho là không được chấp nhận. Không phải vậy! Như trích dẫn của bạn, chỉ có những thứ liên quan đến jqXHR.
Có một tin tốt cho bạn. Bạn sẽ sớm có thể tải mã JavaScript một cách dễ dàng. Nó sẽ trở thành một cách tiêu chuẩn để nhập các mô-đun mã JavaScript và sẽ là một phần của chính JavaScript cốt lõi.
Bạn chỉ cần viết import cond from 'cond.js';
để tải một macro có tên cond
từ một tệp cond.js
.
Vì vậy, bạn không cần phải dựa vào bất kỳ khung JavaScript nào và bạn cũng không phải thực hiện các cuộc gọi Ajax một cách rõ ràng .
Tham khảo:
Có thể tự động tạo thẻ JavaScript và gắn nó vào tài liệu HTML từ bên trong mã JavaScript khác. Điều này sẽ tải tệp JavaScript được nhắm mục tiêu.
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.onload = callback;
Tuyên bố import
trong ECMAScript 6.
Cú pháp
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;
Có lẽ bạn có thể sử dụng chức năng này mà tôi tìm thấy trên trang này Làm cách nào để đưa tệp JavaScript vào tệp 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;
var
, biến sẽ là toàn cầu?
head
.
Đây là phiên bản đồng bộ không có 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);
}
Lưu ý rằng để có được tên miền chéo hoạt động này, máy chủ sẽ cần đặt allow-origin
tiêu đề trong phản hồi của nó.
http://web.archive.org/web/20140905044059/http://www.howtocreate.co.uk/operaStuff/userjs/aagmfunctions.js
)
<script>
thẻ được chèn , không qua XMLHttpRequest
.
const XMLHttpRequest = Components.Constructor("@mozilla.org/xmlextras/xmlhttprequest;1");
Tôi vừa viết mã JavaScript này (sử dụng Prototype để thao tác 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);
}
});
})();
Sử dụng:
<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>
Gist: http://gist.github.com/284442 .
Đây là phiên bản tổng quát về cách Facebook thực hiện nó cho nút Like phổ biến của họ:
<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>
Nếu nó hoạt động cho Facebook, nó sẽ làm việc cho bạn.
Lý do tại sao chúng tôi tìm kiếm script
phần tử đầu tiên thay vì head
hoặc body
là vì một số trình duyệt không tạo phần tử nếu thiếu, nhưng chúng tôi đảm bảo có script
phần tử - phần tử này. Đọc thêm tại http: //www.jspotypes.com/the-ridicificent-case-of-adding-a-script-element/ .
Nếu bạn muốn trong JavaScript thuần, bạn có thể sử dụng document.write
.
document.write('<script src="myscript.js" type="text/javascript"></script>');
Nếu bạn sử dụng thư viện jQuery, bạn có thể sử dụng $.getScript
phương thức này.
$.getScript("another_script.js");
Bạn cũng có thể tập hợp các tập lệnh của mình bằng PHP :
Tập tin 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
Hầu hết các giải pháp hiển thị ở đây ngụ ý tải động. Thay vào đó, tôi đã tìm kiếm một trình biên dịch tập hợp tất cả các tệp phụ thuộc vào một tệp đầu ra. Giống như các bộ tiền xử lý Ít / Sass xử lý @import
theo quy tắc CSS . Vì tôi không tìm thấy bất cứ điều gì tử tế kiểu này, tôi đã viết một công cụ đơn giản để giải quyết vấn đề.
Vì vậy, đây là trình biên dịch, https://github.com/dsheiko/jsic , thay thế $import("file-path")
cho nội dung tệp được yêu cầu một cách an toàn. Đây là plugin Grunt tương ứng : https://github.com/dsheiko/grunt-jsic .
Trên nhánh chính của jQuery, họ chỉ cần ghép các tệp nguồn nguyên tử thành một tệp duy nhất bắt đầu intro.js
và kết thúc bằng outtro.js
. Điều đó không phù hợp với tôi vì nó không cung cấp sự linh hoạt trong thiết kế mã nguồn. Kiểm tra cách nó hoạt động với jsic:
src / main.js
var foo = $import("./Form/Input/Tel");
src / Form / Input / Tel.js
function() {
return {
prop: "",
method: function(){}
}
}
Bây giờ chúng ta có thể chạy trình biên dịch:
node jsic.js src/main.js build/mail.js
Và lấy tập tin kết hợp
xây dựng / main.js
var foo = function() {
return {
prop: "",
method: function(){}
}
};
Nếu bạn có ý định tải tệp JavaScript đang sử dụng các chức năng từ tệp đã nhập / bao gồm , bạn cũng có thể xác định một đối tượng toàn cục và đặt các hàm làm các mục đối tượng. Ví dụ:
A = {};
A.func1 = function() {
console.log("func1");
}
A.func2 = function() {
console.log("func2");
}
A.func1();
A.func2();
Bạn chỉ cần cẩn thận khi đưa các tập lệnh vào tệp HTML. Thứ tự nên như dưới đây:
<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>
Điều này nên làm:
xhr = new XMLHttpRequest();
xhr.open("GET", "/soap/ajax/11.0/connection.js", false);
xhr.send();
eval(xhr.responseText);
eval
chuyện gì với nó vậy. Từ Crockford , " eval
là xấu. eval
Hàm này là tính năng bị lạm dụng nhiều nhất của JavaScript. Tránh nó. eval
Có bí danh. Không sử dụng hàm Function
tạo. Không chuyển chuỗi sang setTimeout
hoặc setInterval
." Nếu bạn chưa đọc "JavaScript: Bộ phận tốt" của anh ấy thì hãy ra ngoài và làm ngay bây giờ. Bạn sẽ không hối tiếc.
http://web.archive.org/web/20140905044059/http://www.howtocreate.co.uk/operaStuff/userjs/aagmfunctions.js
)
Hoặc thay vì bao gồm trong thời gian chạy, sử dụng tập lệnh để ghép nối trước khi tải lên.
Tôi sử dụng Sprockets (Tôi không biết nếu có người khác). Bạn xây dựng mã JavaScript của mình trong các tệp riêng biệt và bao gồm các nhận xét được xử lý bởi công cụ Sprockets như bao gồm. Để phát triển, bạn có thể bao gồm các tệp tuần tự, sau đó để sản xuất hợp nhất chúng ...
Xem thêm:
Tôi đã có một vấn đề đơn giản, nhưng tôi đã gặp khó khăn khi trả lời câu hỏi này.
Tôi đã phải sử dụng một biến (myVar1) được xác định trong một tệp JavaScript (myvariables.js) trong một tệp JavaScript khác (main.js).
Đối với điều này, tôi đã làm như dưới đây:
Đã tải mã JavaScript trong tệp HTML, theo đúng thứ tự, trước tiên là myvariables.js, sau đó là main.js:
<html>
<body onload="bodyReady();" >
<script src="myvariables.js" > </script>
<script src="main.js" > </script>
<!-- Some other code -->
</body>
</html>
Tập tin: myvariables.js
var myVar1 = "I am variable from myvariables.js";
Tệp: main.js
// ...
function bodyReady() {
// ...
alert (myVar1); // This shows "I am variable from myvariables.js", which I needed
// ...
}
// ...
Như bạn đã thấy, tôi đã sử dụng một biến trong một tệp JavaScript trong một tệp JavaScript khác, nhưng tôi không cần đưa một biến vào một tệp khác. Tôi chỉ cần đảm bảo rằng tệp JavaScript đầu tiên được tải trước tệp JavaScript thứ hai và, các biến của tệp JavaScript đầu tiên có thể truy cập được trong tệp JavaScript thứ hai, tự động.
Điều này đã cứu ngày của tôi. Tôi hi vọng cái này giúp được.
import
. Bạn cần một tệp HTML để lấy nội dung từ tệp js này sang tệp khác.
<script>
thẻ. Điều này có thể giúp với tổ chức. Câu trả lời này đơn giản không phải là những gì câu hỏi được yêu cầu, và không lý tưởng trong bối cảnh này.
Trong trường hợp bạn đang sử dụng Web Worker và muốn bao gồm các tập lệnh bổ sung trong phạm vi của công nhân, các câu trả lời khác được cung cấp về việc thêm tập lệnh vào head
thẻ, v.v. sẽ không hiệu quả với bạn.
May mắn thay, Web Worker có importScripts
chức năng riêng của họ , đó là chức năng toàn cầu trong phạm vi của Web Worker, có nguồn gốc từ chính trình duyệt vì nó là một phần của đặc tả .
Ngoài ra, là câu trả lời được bình chọn cao thứ hai cho các câu hỏi nổi bật của bạn , RequireJS cũng có thể xử lý bao gồm các tập lệnh bên trong Công nhân web (có thể importScripts
tự gọi , nhưng với một vài tính năng hữu ích khác).
Trong ngôn ngữ hiện đại với kiểm tra nếu tập lệnh đã được tải, nó sẽ là:
function loadJs(url){
return new Promise( (resolve, reject) => {
if (document.querySelector(`head > script[src="${src}"]`) !== null) return resolve()
const script = document.createElement("script")
script.src = url
script.onload = resolve
script.onerror = reject
document.head.appendChild(script)
});
}
Cách sử dụng (async / await):
try { await loadJs("https://.../script.js") }
catch(error) {console.log(error)}
hoặc là
await loadJs("https://.../script.js").catch(err => {})
Cách sử dụng (Hứa hẹn):
loadJs("https://.../script.js").then(res => {}).catch(err => {})
var pi = 3.14
. gọi hàm loadJS () qualoadJs("pi.js").then(function(){ console.log(pi); });
Các @import
cú pháp để đạt được CSS-như JavaScript nhập khẩu là có thể sử dụng một công cụ như Hỗn hợp đặc biệt của họ thông qua .mix
loại tập tin (xem ở đây ). Tôi tưởng tượng ứng dụng chỉ đơn giản là sử dụng một trong những phương pháp đã nói ở trên, mặc dù tôi không biết.
Từ tài liệu Hỗn hợp trên .mix
các tệp:
Trộn các tệp chỉ đơn giản là các tệp .js hoặc .css với .mix. trong tên tập tin. Một tập tin hỗn hợp chỉ đơn giản là mở rộng chức năng của một tập tin kiểu hoặc tập lệnh thông thường và cho phép bạn nhập và kết hợp.
Đây là một .mix
tệp ví dụ kết hợp nhiều .js
tệp thành một:
// 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";
Hỗn hợp xuất ra điều này dưới dạng scripts-global.js
và cũng là một phiên bản rút gọn ( scripts-global.min.js
).
Lưu ý: Tôi không liên kết với Mixture theo bất kỳ cách nào, ngoài việc sử dụng nó làm công cụ phát triển giao diện người dùng. Tôi đã bắt gặp câu hỏi này khi thấy một .mix
tệp JavaScript đang hoạt động (trong một trong các bảng mẫu hỗn hợp) và hơi bối rối với nó ("bạn có thể làm điều này không?" Tôi tự nghĩ). Sau đó, tôi nhận ra rằng đó là một loại tệp dành riêng cho ứng dụng (hơi thất vọng, đồng ý). Tuy nhiên, hình dung kiến thức có thể hữu ích cho những người khác.
CẬP NHẬT : Hỗn hợp hiện miễn phí (ngoại tuyến).
CẬP NHẬT : Hỗn hợp hiện đang ngưng. Phát hành hỗn hợp cũ vẫn có sẵn
var js = document.createElement("script");
js.type = "text/javascript";
js.src = jsFilePath;
document.body.appendChild(js);
body
chưa tồn tại hoặc không thể sửa đổi. Ngoài ra, nó giúp giải thích câu trả lời.
Phương pháp thông thường của tôi là:
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);
}
Nó hoạt động rất tốt và không sử dụng tải lại trang cho tôi. Tôi đã thử phương pháp AJAX (một trong những câu trả lời khác) nhưng dường như nó không hoạt động tốt với tôi.
Đây là một lời giải thích về cách mã hoạt động cho những người tò mò: về cơ bản, nó tạo ra một thẻ script mới (sau cái đầu tiên) của URL. Nó đặt nó ở chế độ không đồng bộ để nó không chặn phần còn lại của mã, nhưng gọi lại khi readyState (trạng thái của nội dung sẽ được tải) thay đổi thành 'được tải'.
Mặc dù những câu trả lời này rất hay, nhưng có một "giải pháp" đơn giản đã xuất hiện kể từ khi tải tập lệnh tồn tại và nó sẽ bao gồm 99,999% trong hầu hết các trường hợp sử dụng của mọi người. Chỉ cần bao gồm tập lệnh bạn cần trước tập lệnh yêu cầu. Đối với hầu hết các dự án, không mất nhiều thời gian để xác định tập lệnh nào là cần thiết và theo thứ tự nào.
<!DOCTYPE HTML>
<html>
<head>
<script src="script1.js"></script>
<script src="script2.js"></script>
</head>
<body></body>
</html>
Nếu script2 yêu cầu script1, đây thực sự là cách dễ nhất tuyệt đối để làm một cái gì đó như thế này. Tôi rất ngạc nhiên không ai đưa ra điều này, vì đó là câu trả lời rõ ràng và đơn giản nhất sẽ được áp dụng trong gần như mọi trường hợp.
Tôi đã viết một mô-đun đơn giản tự động hóa công việc nhập / bao gồm các tập lệnh mô-đun trong JavaScript. Để được giải thích chi tiết về mã, hãy tham khảo bài đăng trên blog yêu cầu / nhập / bao gồm các mô-đun .
// ----- 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);
};
Tập lệnh này sẽ thêm một tệp JavaScript vào đầu bất kỳ <script>
thẻ nào khác :
(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);
})();
Ngoài ra còn có Head.js . Nó rất dễ dàng để đối phó với:
head.load("js/jquery.min.js",
"js/jquery.someplugin.js",
"js/jquery.someplugin.css", function() {
alert("Everything is ok!");
});
Như bạn thấy, nó dễ hơn Require.js và thuận tiện như $.getScript
phương thức của jQuery . Nó cũng có một số tính năng nâng cao, như tải có điều kiện, phát hiện tính năng và nhiều hơn nữa .
Có rất nhiều câu trả lời tiềm năng cho câu hỏi này. Câu trả lời của tôi rõ ràng là dựa trên một số trong số họ. Đây là những gì tôi đã kết thúc sau khi đọc qua tất cả các câu trả lời.
Vấn đề với $.getScript
và thực sự là bất kỳ giải pháp nào khác yêu cầu gọi lại khi tải xong là nếu bạn có nhiều tệp sử dụng nó và phụ thuộc vào nhau, bạn không còn cách nào để biết khi nào tất cả các tập lệnh đã được tải (một khi chúng được lồng vào nhau trong nhiều tập tin).
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("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...
});
Bạn đã đúng khi nói rằng bạn có thể chỉ định Ajax để chạy đồng bộ hoặc sử dụng XMLHttpRequest , nhưng xu hướng hiện tại dường như là không dùng các yêu cầu đồng bộ, do đó bạn có thể không nhận được hỗ trợ trình duyệt đầy đủ ngay bây giờ hoặc trong tương lai.
Bạn có thể thử sử dụng $.when
để kiểm tra một mảng các đối tượng bị trì hoãn, nhưng bây giờ bạn đang thực hiện việc này trong mọi tệp và tệp 2 sẽ được xem là được tải ngay khi $.when
thực thi không phải khi thực hiện cuộc gọi lại, vì vậy tệp 1 vẫn tiếp tục thực thi trước khi tệp 3 được tải . Điều này thực sự vẫn có cùng một vấn đề.
Tôi quyết định đi lùi thay vì tiến lên. Cảm ơn bạn document.writeln
. Tôi biết đó là điều cấm kỵ, nhưng miễn là nó được sử dụng đúng cách thì nó hoạt động tốt. Bạn kết thúc với mã có thể được gỡ lỗi dễ dàng, hiển thị trong DOM chính xác và có thể đảm bảo thứ tự các phụ thuộc được tải chính xác.
Tất nhiên bạn có thể sử dụng $ ("body"). Append (), nhưng sau đó bạn không còn có thể gỡ lỗi chính xác nữa.
LƯU Ý: Bạn phải sử dụng điều này chỉ trong khi trang đang tải, nếu không bạn sẽ có một màn hình trống. Nói cách khác, luôn đặt cái này trước / bên ngoài document . Yet . Tôi chưa thử nghiệm bằng cách này sau khi trang được tải trong một sự kiện nhấp chuột hoặc bất cứ điều gì tương tự, nhưng tôi chắc chắn rằng nó sẽ thất bại.
Tôi thích ý tưởng mở rộng jQuery, nhưng rõ ràng là bạn không cần.
Trước khi gọi document.writeln
, nó kiểm tra để đảm bảo tập lệnh chưa được tải bằng cách đánh giá tất cả các thành phần tập lệnh.
Tôi giả sử rằng một tập lệnh không được thực thi đầy đủ cho đến khi document.ready
sự kiện của nó được thực thi. (Tôi biết việc sử dụng document.ready
là không bắt buộc, nhưng nhiều người sử dụng nó và xử lý việc này là một biện pháp bảo vệ.)
Khi các tệp bổ sung được tải, các document.ready
cuộc gọi lại sẽ được thực hiện theo thứ tự sai. Để giải quyết vấn đề này khi tập lệnh thực sự được tải, tập lệnh đã nhập nó được nhập lại chính nó và việc thực thi bị dừng lại. Điều này khiến cho tệp khởi tạo bây giờ được document.ready
thực hiện gọi lại sau bất kỳ tập lệnh nào mà nó nhập.
Thay vì cách tiếp cận này, bạn có thể cố gắng sửa đổi jQuery readyList
, nhưng đây có vẻ là một giải pháp tồi tệ hơn.
Giải pháp:
$.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;
}
});
Sử dụng:
Tệp 3:
var f3obj = "file3";
// Define other stuff
$(function(){
f3obj = "file3docready";
});
Tệp2:
$.import_js('js/file3.js');
var f2obj = "file2";
$(function(){
f2obj = "file2docready";
});
Tệp1:
$.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"
});
Có một số cách để triển khai các mô-đun trong Javascript, Dưới đây là 2 cách phổ biến nhất:
Các trình duyệt chưa hỗ trợ hệ thống sửa đổi này, vì vậy để bạn sử dụng cú pháp này, bạn phải sử dụng một gói như webpack. Dù sao, sử dụng một gói là tốt hơn bởi vì điều này có thể kết hợp tất cả các tệp khác nhau của bạn thành một tệp (hoặc liên quan đến cặp đôi). Điều này sẽ phục vụ các tệp từ máy chủ đến máy khách nhanh hơn vì mỗi yêu cầu HTTP có một số chi phí liên quan đi kèm với nó. Do đó, bằng cách giảm yêu cầu HTTP quá mức, chúng tôi cải thiện hiệu suất. Dưới đây là một ví dụ về các mô-đun 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
Hệ thống điều chỉnh này được sử dụng trong NodeJS. Về cơ bản, bạn thêm xuất khẩu của mình vào một đối tượng được gọi là module.exports
. Sau đó bạn có thể truy cập đối tượng này thông qua a require('modulePath')
. Điều quan trọng ở đây là nhận ra rằng các mô-đun này đang được lưu trữ, vì vậy nếu bạn require()
một mô-đun nhất định hai lần, nó sẽ trả về mô-đun đã tạo.
// 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
Tôi đã đến với câu hỏi này bởi vì tôi đang tìm kiếm một cách đơn giản để duy trì một bộ sưu tập các plugin JavaScript hữu ích. Sau khi thấy một số giải pháp ở đây, tôi đã nghĩ ra điều này:
Thiết lập một tệp có tên là "plugins.js" (hoặc extend.js hoặc bất cứ điều gì bạn muốn). Giữ các tệp plugin của bạn cùng với một tệp chủ đó.
plugins.js sẽ có một mảng được gọi là pluginNames[]
chúng tôi sẽ lặp lại each()
, sau đó gắn một <script>
thẻ vào phần đầu cho mỗi plugin
//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>
NHƯNG:
Mặc dù tất cả các plugin được thả vào thẻ đầu theo cách chúng nên, chúng không luôn được trình duyệt chạy khi bạn nhấp vào trang hoặc làm mới.
Tôi đã thấy đáng tin cậy hơn khi chỉ viết các thẻ script trong PHP bao gồm. Bạn chỉ phải viết nó một lần và điều đó cũng tương tự như gọi plugin bằng JavaScript.