簡體   English   中英

如何在另一個 JavaScript 文件中包含一個 JavaScript 文件?

[英]How do I include a JavaScript file in another JavaScript file?

如何在另一個 JavaScript 文件中包含一個 JavaScript 文件,類似於 CSS 中的@import

舊版本的 JavaScript 沒有導入、包含或要求,因此已經開發了許多不同的方法來解決這個問題。

但自 2015 年(ES6)以來,JavaScript 已經有了ES6 模塊標准來在 Node.js 中導入模塊,大多數現代瀏覽器也支持這一點。

為了與舊瀏覽器兼容,可以使用WebpackRollup等構建工具和/或Babel等轉譯工具。

ES6 模塊

從 v8.5 開始, Node.js 支持ECMAScript (ES6) 模塊,帶有--experimental-modules標志,至少從沒有標志的 Node.js v13.8.0 開始。 要啟用“ESM”(與 Node.js 以前的 CommonJS 樣式模塊系統 [“CJS”] 相比),您可以在package.json中使用"type": "module" ,或者為文件提供擴展名.mjs (類似地,如果您的默認值為 ESM,則使用 Node.js 以前的 CJS 模塊編寫的模塊可以命名為.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閱讀更多內容

Node.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 調用加載附加腳本,然后使用eval運行它。 這是最直接的方法,但由於 JavaScript 沙盒安全模型,它僅限於您的域。 使用eval也為錯誤、黑客和安全問題打開了大門。

獲取加載

與動態導入一樣,您可以使用fetch調用加載一個或多個腳本,使用 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>標記,其中src屬性設置為作為第一個參數提供給函數的 URL。

這兩種解決方案都在JavaScript Madness: Dynamic Sc​​ript Loading中進行了討論和說明。

檢測腳本何時執行

現在,有一個大問題你必須知道。 這樣做意味着您遠程加載代碼 現代網絡瀏覽器將加載文件並繼續執行您當前的腳本,因為它們異步加載所有內容以提高性能。 (這適用於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 加載的文章討論了這個問題。

源代碼合並/預處理

如本答案頂部所述,許多開發人員在他們的項目中使用 Parcel、Webpack 或 Babel 等構建/轉換工具,允許他們使用即將推出的 JavaScript 語法,為舊瀏覽器提供向后兼容性,合並文件,縮小,執行代碼拆分等

如果有人在尋找更高級的東西,試試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
});

implementation.js是你的“主要”JavaScript 文件,它依賴於some-dependency.js

require(['some-dependency'], function(dependency) {

    //Your script goes here
    //some-dependency.js is fetched.   
    //Then your script is executed
});

摘自GitHub自述文件:

RequireJS 加載純 JavaScript 文件以及更多定義的模塊。 它針對瀏覽器內的使用進行了優化,包括在 Web Worker 中,但它也可以在其他 JavaScript 環境中使用,例如 Rhino 和 Node。 它實現了異步模塊 API。

RequireJS 使用純腳本標簽來加載模塊/文件,因此它應該允許輕松調試。 它可以簡單地用於加載現有的 JavaScript 文件,因此您可以將其添加到現有項目中,而無需重新編寫 JavaScript 文件。

...

實際上一種方法可以異步加載 JavaScript 文件,因此您可以在加載后立即使用新加載的文件中包含的函數,我認為它適用於所有瀏覽器。

您需要在頁面的<head>元素上使用jQuery.append() ,即:

$("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() main.js一個名為 include.js 的included.js文件,該文件定義了這個函數:

function hello()
{
    alert("Hello world!");
}

included.js include.js 之后,立即調用hello()函數,您會收到警報。

(此答案是對 e-satis 評論的回應)。

另一種在我看來更簡潔的方法是發出同步 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(); 

可以動態生成 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");

有一個好消息要告訴你。 很快您將能夠輕松加載 JavaScript 代碼。 它將成為導入 JavaScript 代碼模塊的標准方式,並將成為核心 JavaScript 本身的一部分。

你只需要寫import cond from 'cond.js'; 從文件cond.js加載名為cond的宏。

因此,您不必依賴任何 JavaScript 框架,也不必顯式地進行Ajax調用。

參考:

語句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;

也許您可以使用我在此頁面上找到的此功能如何在 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)
}

這是一個沒有 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標頭。

我剛剛編寫了這段 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

如果你想在純 JavaScript 中使用它,你可以使用document.write

document.write('<script src="myscript.js" type="text/javascript"></script>');

如果您使用 jQuery 庫,則可以使用$.getScript方法。

$.getScript("another_script.js");

以下是 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,它將適用於您。

我們尋找第一個script元素而不是headbody的原因是因為某些瀏覽器在丟失時不會創建一個,但我們保證有一個script元素 - 這個。 http://www.jspatterns.com/the-ridiculous-case-of-adding-a-script-element/閱讀更多內容。

您還可以使用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

此處顯示的大多數解決方案都意味着動態加載。 我正在尋找一個編譯器,它將所有依賴的文件組裝成一個輸出文件。 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 開頭並以intro.js結尾的outtro.js 這不適合我,因為它沒有為源代碼設計提供靈活性。 看看它是如何與 jsic 一起工作的:

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 文件是使用導入/包含文件中的函數,您還可以定義一個全局對象並將函數設置為對象項。 例如:

global.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>

這應該這樣做:

xhr = new XMLHttpRequest();
xhr.open("GET", "/soap/ajax/11.0/connection.js", false);
xhr.send();
eval(xhr.responseText);

或者,不是在運行時包含,而是在上傳之前使用腳本進行連接。

我用的是Sprockets (不知道有沒有其他的)。 您在單獨的文件中構建 JavaScript 代碼,並包含由 Sprockets 引擎處理的注釋作為包含。 對於開發,您可以按順序包含文件,然后在生產中合並它們......

也可以看看:

我有一個簡單的問題,但我對這個問題的回答感到困惑。

我必須在另一個 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 文件中自動訪問。

這拯救了我的一天。 我希望這有幫助。

用於實現類似 CSS 的 JavaScript 導入的@import語法可以使用諸如 Mixture 之類的工具通過其特殊的.mix文件類型(參見此處)來實現。 我假設應用程序通過上述方法之一執行此操作。

.mix文件的 Mixture 文檔中:

混合文件只是帶有 .mix 的 .js 或 .css 文件。 在文件名中。 混合文件只是擴展了普通樣式或腳本文件的功能,並允許您導入和組合。

這是一個將多個.js文件合並為一個的示例.mix文件:

// 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 樣板中)並對此感到有些困惑時遇到了這個問題(“你可以這樣做嗎?”我心想)。 然后我意識到這是一個特定於應用程序的文件類型(有點令人失望,同意)。 盡管如此,認為這些知識可能對其他人有所幫助。

注意: Mixture 於 2016/07/26 停產(在 2015/04/12 開源之后)。

在檢查腳本是否已經加載的現代語言中,它將是:

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 );
  });
}

用法(異步/等待):

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 => {} );

如果您正在使用Web Worker 並希望在 worker 范圍內包含其他腳本,則提供的有關將腳本添加到head標簽等的其他答案將不適合您。

幸運的是, Web Worker 有自己的importScripts函數,它是 Web Worker 范圍內的全局函數,是瀏覽器本身的原生函數,因為它是規范的一部分

或者,作為對您的問題的第二高投票答案突出顯示RequireJS還可以處理在 Web Worker 中包含腳本(可能會調用importScripts本身,但具有一些其他有用的功能)。

var js = document.createElement("script");

js.type = "text/javascript";
js.src = jsFilePath;

document.body.appendChild(js);

盡管這些答案很棒,但自從腳本加載存在以來就有一個簡單的“解決方案”,它將涵蓋大多數人的 99.999% 的用例。 只需在需要它的腳本之前包含您需要的腳本。 對於大多數項目來說,確定需要哪些腳本以及按什么順序並不需要很長時間。

<!DOCTYPE HTML>
<html>
    <head>
        <script src="script1.js"></script>
        <script src="script2.js"></script>
    </head>
    <body></body>
</html>

如果 script2 需要 script1,這確實是執行此類操作的最簡單方法。 我很驚訝沒有人提出這個問題,因為這是最明顯和最簡單的答案,幾乎適用於每一個案例。

ES6 模塊

的,在腳本標簽(支持)中使用 type="module":

<script type="module" src="script.js"></script>

script.js文件中包含另一個文件,如下所示:

import { hello } from './module.js';
...
// alert(hello());

在“module.js”中,您必須導出要導入的函數/類

export function hello() {
    return "Hello World";
}

一個工作示例是here

我常用的方法是:

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(要加載的內容的狀態)更改為“已加載”時調用回調。

我編寫了一個簡單的模塊,它可以自動執行在 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);
};

此腳本會將 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);
})();

讓它保持美觀、簡短、簡單和可維護! :]

// 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]);
    }
}

此代碼只是一個簡短的功能示例,可能需要額外的特性功能才能在任何(或給定)平台上完全支持。

有幾種方法可以在 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

我來這個問題是因為我正在尋找一種簡單的方法來維護一組有用的 JavaScript 插件。 在這里看到一些解決方案后,我想出了這個:

  1. 設置一個名為“plugins.js”(或 extensions.js 或任何你想要的)的文件。 將您的插件文件與那個主文件保存在一起。

  2. plugins.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>');
});
  1. 手動調用你腦海中的一個文件:
    <script src="js/plugins/plugins.js"></script>

但:

即使所有插件都以應有的方式放入 head 標簽中,但當您單擊頁面或刷新時,它們並不總是由瀏覽器運行。

我發現只在 PHP 包含中編寫腳本標簽更可靠。 您只需編寫一次,這與使用 JavaScript 調用插件一樣多。

是的,有...

繼續閱讀。 ES6中,我們可以將部分或整個 JavaScript 文件exportimport到另一個文件中......

但是等等,並不是所有的瀏覽器都支持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>

還有我應該在這里提到的asyncdefer屬性......

注意:有幾種方法可以執行外部腳本:

  • 如果存在異步:腳本與頁面的其余部分異步執行(腳本將在頁面繼續解析時執行)
  • 如果 async 不存在並且 defer 存在:當頁面完成解析時執行腳本
  • 如果 async 或 defer 都不存在:在瀏覽器繼續解析頁面之前立即獲取並執行腳本

還有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以及在加載完成時需要回調的任何其他解決方案的問題是,如果您有多個文件使用它並且相互依賴,您將無法知道何時加載了所有腳本(一次它們嵌套在多個文件中)。

例子:

文件 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時,您是對的,但目前的趨勢似乎是棄用同步請求,因此您現在或將來可能無法獲得完整的瀏覽器支持。

您可以嘗試使用$.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="relative/path/to/MyClass.js.html"/>

<script>
   var myClass = new MyClass();
   // Your code here..
</script>

編輯:HTML 導入將被刪除

HTML 導入被刪除,有利於 ES6 模塊。 您應該使用 ES6 模塊。

僅適用於 Node.js,這對我來說效果最好!

我在這里嘗試了大多數解決方案,但沒有一個能幫助我在不改變范圍的情況下加載另一個文件。 最后我用了這個。 這保留了范圍和一切。 它與您的代碼在這一點上一樣好。

const fs = require('fs');
eval(fs.readFileSync('file.js') + '');

我創建了一個函數,允許您使用與 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="/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);
}

最好使用jQuery方式。 要延遲就緒事件,首先調用$.holdReady(true) 示例(來源):

$.holdReady(true);
$.getScript("myplugin.js", function() {
    $.holdReady(false);
});

我基本上是這樣做的,創建一個新元素並將其附加到頭部:

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.
});

這是一個Grunt插件,允許您使用@import "path/to/file.js"; 任何文件中的語法,包括 JavaScript 文件。 它可以與 uglify 或 watch 或任何其他插件配對。

可以使用 npm install 安裝: https ://npmjs.org/package/grunt-import

我需要異步加載 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); });

在第一個腳本完全加載之前,第二個腳本不會加載,所以......

結果:

結果

這可能是另一種方式!

在 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();

參考

http://requirejs.org/docs/node.html

如果你使用 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' ]);

使用 ES6 導入和導出與 Node.js 一起使用的模塊

使用.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

在過去的一個項目中,我使用ajile導入可重用的 JavaScript 文件取得了相當大的成功。 我一直希望 JavaScript 本身有一個內置的功能。

不要忘記查看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)
};

這很簡單。 假設您要在文件 B.js 中導入文件 A.js。

現在可以確定您已將 B.js 鏈接到 HTML 文件中,然后只需在該 HTML 文件中將 A.js 鏈接到 B.js 之前。 然后 A.js 的公共變量將在 B.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="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);
}

腳本A.js

myExpo = {
    hello: function () {
        console.log('From\tBBBBB');
        return "Hello";
    }
}

結果

From    AAAAA
From    BBBBB
Hello
Step 1: Declare the function in another class.

    export const myreport = (value) => {
    color = value.color;
    name = value.name;
    
    var mytext = name + " | " + color;
    return mytext;
    }

Step 2:- Import that function which is needed to be used.

    import {myreport} from '../../Test'

Step 3:- Use that function.

let val = { color: "red", name: "error" }
var resultText = myreport(val)
console.log("resultText :- ", resultText)

不能導入,但可以參考。

PhpShtorm IDE。 要引用,在一個.js文件到另一個.js ,只需將其添加到文件的頂部:

<reference path="../js/file.js" />

當然,您應該使用自己的 PATH 指向 JavaScript 文件。

我不知道它是否適用於其他 IDE。 可能是的,試試吧。 它也應該在 Visual Studio 中工作。

另一種方法是使用 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 Imports了解更多詳細信息。

不幸的是,這只適用於 Chrome。

按順序動態加載多個腳本

如果您只加載一個腳本或者您不關心多個腳本的加載順序,則上述功能可以正常工作。 如果你有一些腳本依賴於其他的,你需要使用Promise來指定加載的順序。 這背后的原因是 Javascript 異步加載腳本和圖像等資源。 加載順序不依賴於異步調用的順序,這意味着即使在調用dynamicallyLoadScript("scrip1")之前調用 dynamicLoadScript dynamicallyLoadScript("scrip2") "scrip1") 也不能保證 script1 在 script2 之前加載

所以這是另一個版本的動態加載腳本,它保證加載順序:

// 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);
    });

有關 Promises 的更多信息,請參閱這個出色的頁面

這個新的 dynamicLoadScript 的使用非常簡單:

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...

處理加載錯誤

要顯示未處理的承諾拒絕(錯誤加載腳本等),請將此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);

腳本將按照它們在數組中出現的順序加載。

請注意,我們通常使用靜態腳本 所以我們希望盡可能多地從緩存中取出。

這樣可以節省網絡流量並加快登陸速度。

用法

$.cachedScript( "ajax/test.js" ).done(function( script, textStatus ) {
  console.log( textStatus );
});

cache: true選項已添加到 Ajax 方法中。

如果調用時發現有兩個或多個腳本占用同一個函數,而我們不能同時包含它們,我們需要通過用戶選擇來動態地包含它們。

使用$.getScript在 jQuery 中包含另一個文件是可行的,因為 默認情況下不會緩存該腳本。 所以我們可以安全地調用其他腳本。 呼叫可以這樣安排:

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
      });
    }

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';
}));
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

您可以使用我的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, [options] )

異步加載 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 );
            },
        } );

使用示例

所以這是一個邊緣案例。 但是,如果您需要從遠程源加載 JavaScript,大多數現代瀏覽器可能會由於 CORS 或類似原因而阻止您的跨站點請求。 太正常了

<script src="https://another-domain.com/example.js"></script>

不會工作。 並且執行document.createElement('script').src = '...'也不會削減它。 相反,您可以做的是通過標准GET請求將 java 腳本作為資源加載,然后執行以下操作:

<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>

通過自己抓取內容,瀏覽器不會注意到惡意意圖並允許您執行請求。 然后將其添加到<script>innerHTML中。 這仍然會導致瀏覽器(至少在 Chrome 中測試過)解析/執行腳本。

同樣,這是一個邊緣案例用例。 而且您可能沒有向后兼容性或瀏覽器合規性。 但是有趣/有用的事情要知道。

發出fetch請求並eval結果。

我的通用解決方案取自EdgeS (我創作的)efekt.js.st庫。

無恥的插件警報- 我在其他 stackexchange 網絡站點上。 這是https://codereview.stackexchange.com/questions/263764/dynamic-load-css-or-script的重新鏈接。

您將使用什么代碼或設計來支持cssscripts的動態加載?

要求

  • 支持promise-await-async包括錯誤處理
  • 支持一次加載緩存,包括重新加載
  • 支持在headbody或當前script-element中加載
  • 支持加載cssjsmjs模塊或其他腳本類型
  • 支持其他標簽crossorigin ,如noncecrossorigin
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);
}

因此,如果您想要快速、簡單...試試這個:

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);

要在 JavaScript 中導入另一個腳本,請使用import關鍵字:

import '/src/js/example.js';

// both types of quotes work
import "/src/js/example2.js";

我沒有看到一個答案,您可以在文件中創建所有函數和變量的對象,然后將該對象作為參數以在另一個文件中引用它。

例如,您有名為“jsMod.js”、“jsView”和“jsContr.js”的文件:


    //jsMod.js file
    JSMODOBJ = {};
    JSMODOBJ.valueAddition = function(/* element value 1 */ val1,
                                          /* element value 2 */ val2) {
        return val1 + val2;
    }


    //jsView.js file
    JSVIEWOBJ = {};
    JSVIEWOBJ.elementColour = function(/* element id to change colour */ id,
                                          /* css colour classname */ col) {
        document.getElementById(id).className = col;
    }


    //jsContr.js file
    JSCONTROBJ = {};
    var jsMod = JSMODOBJ;
    var jsView = JSVIEWOBJ;

    JSCONTROBJ.changeColourByValue = function (val1, val2, id, clss) {
        if (jsMod.valueAddition(val1,val2) !== 0) {
            jsView.elementColour(id, clss);
        }
    }

然后,您可以通過將scripts回顯到 .html 或 .php 文件中來動態設置 .js 文件:

<?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>標記中調用控制函數。 當然,這在開始時會花費很多時間來設置,但從長遠來看,它可以節省您的時間。

我以稍微不同的方式使用它,但這種方式也有效。

您還可以使用gulpgulp-concatgulp-typescript/// <reference path=包括:

包.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;

這個main的 gulp 任務(在gulpfile.js上)僅針對src/main.js文件,解析其所有/// <reference path=...包含引用。 這些包括被稱為Triple-Slash Directives ,它們僅用於編譯器工具來組合文件。 在我們的例子中,它們由.pipe(resolveDependencies({和 typescript 本身在檢查文件是否缺少類型、變量等時顯式使用。

  1. https://www.typescriptlang.org/docs/handbook/triple-slash-directives.html
  2. 我什么時候需要三斜杠引用?

如果您想自定義var tsProject = ts.createProject調用而不使用tsconfig.json文件或覆蓋其參數,請參閱https://github.com/ivogabe/gulp-typescript#api-overview

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/"));
});

如果您想定位所有類型腳本項目文件,而不僅僅是src/main.ts ,您可以替換它:

  return gulp
    .src(["src/main.ts"])
    .pipe(resolveDependencies({
    ...
// -->
  return tsProject
    .src()
    .pipe(resolveDependencies({
    ...

如果您不想使用typescript ,可以使用這個簡化gulpfile.js並從package.json中刪除所有typescript包含:

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/"));
});

包.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;

在提供build目錄文件之后,這允許我將它與script標記一起包含在瀏覽器中:

<html>
    <head>
        <script src="main.js"></script>
    </head>
    <body>
        <script type="text/javascript">
            console.log(someclass.delay);
        </script>
    </body>
</html>

相關問題:

  1. https://www.typescriptlang.org/docs/handbook/gulp.html
  2. 我可以在沒有 requireJS 的情況下使用打字稿嗎?
  3. 需要另一個 JS 文件的主文件的 Gulp 簡單連接
  4. 節點上的客戶端:未捕獲的 ReferenceError:未定義要求
  5. 如何使用 gulp 編譯 typescript 瀏覽器節點模塊?
  6. 使用 babel 連接文件
  7. 如何在瀏覽器中要求 CommonJS 模塊?
  8. Browserify有替代品嗎?

在 JavaScript 中,可以使用import關鍵字將一個 JavaScript 文件包含在另一個文件中。 例如,如果你有一個名為myScript.js的文件,你想將它包含在另一個名為main.js的文件中,你可以在main.js中使用以下代碼:

import * as myScript from './myScript.js';

這會將所有函數和變量從myScript.js導入到main.js中,讓您可以像在main.js本身中定義它們一樣使用它們。

有趣的事實:這個答案是由 AI 生成的,我已經檢查過它並且有效。

如果你想擁有指向位於不同文件中的所有 javascript 函數的單一鏈接,你可以使用 php 執行類似的操作:

創建一個 php 文件,它將存儲所有 javascript 函數/觸發器javascript.php並確保它是一個.php文件:

在你的<head>部分

 <script src="/directory/javascript.php"></script>

假設您有一個名為/functions的文件夾,其中包含所有 javascript 文件。 在您的javascript.php中,創建內容類型為application/javascriptheader ,並使用 php glob包含所有 javascript 文件/腳本,如下所示:

javascript.php

<?php 
header("content-type:application/javascript");
foreach(glob("/functions/*.js") as $filename){include($filename);}
?> 

現在您可以創建單獨的 javascript 文件並將它們添加到您的/functions文件夾,或者您可以命名的任何文件夾。 這些將自動包含到javascript.php文件中,該文件實際上是一個功能正常的 js 文件,您可以在<head>部分鏈接該文件。

在后端,您可以使用 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);

但是最簡單的解決方案呢? 我很驚訝沒有人提到這個,所以我發布它! 使用像 Vite.js 這樣的打包工具,然后簡單地執行以下操作:

import "./path/to/js/file";

而已! OP 已經要求像“ @import in CSS”這樣的東西,這就是那樣。 它也不像一些舊方法那樣復雜 它至少無疑是對初學者最友好的方法,但我相信非初學者也喜歡它。

要開始使用 Vite 進行 Vanilla JavaScript 項目,只需安裝 Node 和 NPM,然后執行以下操作:

npm create vite@latest <your-vanilla-js-app-name> --template vanilla

例如:

npm create vite@latest my-js-app --template vanilla

現在添加此答案開頭提到的導入並收工。

順便說一句:您可能想到的另一件事是命名空間問題,例如,如果您在包含的文件中使用的名稱與您在當前文件中已有的名稱相似怎么辦? 但這就是 JavaScript 的本質,對吧? 這不是此方法特有的問題。 因此,您需要制定單獨處理的策略。 如果您想了解更多信息,可以在 Addy Osmani 的博客上找到一篇綜合文章:在 JavaScript 中處理全局命名空間的設計模式

您可以只使用 require(); 標簽。

例如,如果我有一個要添加到 math.js 的addition.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;
}

你應該使用這個:

<script src="your_file.js"></script>

簡單的!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM