JavaScript >> Javascript 文檔 >  >> JavaScript

如何在 JavaScript 中動態加載第三方腳本

如何通過編寫腳本自動將標籤注入您的頁面來動態加載 Google 地圖等 JavaScript 庫。

開始

在本教程中,我們將使用 CheatCode 的全棧 JavaScript 框架 Joystick。 Joystick 將前端 UI 框架與用於構建應用的 Node.js 後端結合在一起。

首先,我們要通過 NPM 安裝 Joystick。確保在安裝之前使用 Node.js 16+ 以確保兼容性(如果您需要學習如何安裝 Node.js 或在計算機上運行多個版本,請先閱讀本教程):

終端

npm i -g @joystick.js/cli

這將在您的計算機上全局安裝操縱桿。安裝好之後,接下來我們新建一個項目:

終端

joystick create app

幾秒鐘後,您將看到一條消息已註銷到 cd 進入你的新項目並運行 joystick start

終端

cd app && joystick start

在此之後,您的應用應該可以運行了,我們可以開始了。

創建動態腳本加載器

在 JavaScript 中,一種常見的做法是將其他包和庫加載到您的應用程序中。傳統上,這是通過像 NPM(Node Package Manager)這樣的包管理器來完成的,但有時,我們需要動態地加載 JavaScript .

“動態”也可以理解為“動態”或“來自第三方服務器”。通常我們這樣做的原因是,有問題的腳本在加載腳本之前需要 API 密鑰或某種其他形式的身份驗證(或者,出於安全目的遠程託管腳本以避免被篡改)。

雖然我們可以 添加一個 <script></script> 標記直接進入我們的主 index.html 文件,這可能是多餘的,因為您只需要某些頁面上的某些腳本。為了解決這個問題,我們可以編寫一個動態腳本加載器,可以從需要腳本的頁面按需調用。

/lib/loadScript.js

const urls = {
  googleMaps: `https://maps.googleapis.com/maps/api/js?key=${joystick.settings.public.googleMaps.apiKey}&libraries=places`,
};

export default (name = '', callback = null) => {
  const url = name && urls[name];

  if (!name || !url) {
    throw new Error(`Must pass the name of a supported script: ${Object.keys(urls).join(', ')}`);
  }
};

從我們的腳本開始,我們的目標是創建一個函數,我們可以在代碼中需要它的任何地方導入它。為了使這成為可能,在這裡,我們創建了一個文件,我們在其中 export default 一個接受兩個參數的函數:

  1. name - 我們嘗試加載的腳本的名稱。
  2. callback - 一個回調函數來調用之後 我們的腳本已加載。

對於 name ,我們希望這是一個我們創建的名字 .在我們的示例中,我們將加載 Google Maps JavaScript API。在頂部,我們可以看到正在創建的對象 urls 它有一個屬性 googleMaps 在其上定義,設置為 Google 為我們提供的 JavaScript 庫的 URL。

在此處的 URL 中,我們替換了 apiKey Google Maps 期望的查詢參數,其中包含指向我們應用程序設置文件中的全局值的指針:joystick.settings.public.googleMaps.apiKey .

這裡,joystick.settings 是瀏覽器中的全局值,自動填充位於 /settings.development.json 中的設置文件的內容 在我們應用程序的根目錄。在這裡使用這個約定,我們說我們希望在位於 apiKey 的設置文件中有一個值 嵌套在 public.googleMaps 對象,像這樣:

/settings.development.json

{
  "config": {
    "databases": [
      {
        "provider": "mongodb",
        "users": true,
        "options": {}
      }
    ],
    "i18n": {
      "defaultLanguage": "en-US"
    },
    "middleware": {},
    "email": {
      "from": "",
      "smtp": {
        "host": "",
        "port": 587,
        "username": "",
        "password": ""
      }
    }
  },
  "global": {},
  "public": {
    "googleMaps": {
      "apiKey": "apiKey1234"
    }
  },
  "private": {}
}

所以很明顯,行 https://maps.googleapis.com/maps/api/js?key=${joystick.settings.public.googleMaps.apiKey}&libraries=places 上面的內容將被 JavaScript 讀取為 https://maps.googleapis.com/maps/api/js?key=apiKey1234&libraries=places .關鍵是在 ${} 中傳遞的變量 部分將被我們設置文件中的值替換(這稱為 JavaScript 字符串插值)。

/lib/loadScript.js

const urls = {
  googleMaps: `https://maps.googleapis.com/maps/api/js?key=${joystick.settings.public.googleMaps.apiKey}&libraries=places`,
};

export default (name = '', callback = null) => {
  const url = name && urls[name];

  if (!name || !url) {
    throw new Error(`Must pass the name of a supported script: ${Object.keys(urls).join(', ')}`);
  }
};

回到我們的代碼,嵌入我們的 API 密鑰,假設我們的 urls 對象具有與 name 匹配的屬性 參數傳遞給我們的 loadScript() 函數,就在該函數內部,我們嘗試獲取要使用 name && urls[name] 加載的腳本的 URL .這說“如果 name 已定義,您可以在 urls 上找到一個屬性 與此 name 匹配的對象 ,將其值返回給我們。”

在 JavaScript 中,這個 urls[name] 被稱為“括號符號”。這允許我們使用某個變量或值從對像中動態檢索值。需要明確的是,如果我們的 urls 對像有一個屬性 pizza 設置為 https://marcospizza.com 在上面定義,我們通過了 'pizza' 作為 name 對於我們的腳本,我們期望 url 此處的變量要設置為 https://marcospizza.com .

在此下方,為了安全起見,我們快速檢查一下“如果我們沒有 name 已定義,或者,我們沒有 url defined` 拋出錯誤。”這將阻止我們的腳本加載並在瀏覽器控制台中警告我們,以便我們解決問題。

/lib/loadScript.js

const urls = {
  googleMaps: `https://maps.googleapis.com/maps/api/js?key=${joystick.settings.public.googleMaps.apiKey}&libraries=places`,
};

export default (name = '', callback = null) => {
  const url = name && urls[name];

  if (!name || !url) {
    throw new Error(`Must pass the name of a supported script: ${Object.keys(urls).join(', ')}`);
  }

  const existingScript = document.getElementById(name);

  if (!existingScript) {
    const script = document.createElement('script');
    script.src = url;
    script.id = name;
    document.body.appendChild(script);

    script.onload = () => {
      if (callback) callback();
    };
  }

  if (existingScript && callback) callback();
};

構建我們的其餘功能,現在我們進入有趣的東西。假設一個 name 已通過並匹配我們的 urls 上的屬性 對象(意味著我們得到了一個 url ),接下來我們需要做的是確保我們之前沒有加載過有問題的腳本。

這個很重要!因為我們動態加載 JavaScript,一般來說,我們的函數可能會被多次調用(有意或無意)。因為我們的腳本要追加 或添加 <script></script> 標記到我們的 HTML 中,我們希望防止創建它的重複項。在這裡,我們尋找一個現有的 <script></script> 帶有 id 的標籤 屬性等於 name 我們傳入 loadScript .

如果我們找到它,我們跳到函數的底部,假設我們有一個 callback 定義函數,調用該函數(表示“是的,此腳本已加載並可使用”)。

如果我們 找到一個 existingScript ,我們要動態加載它。為此,首先,我們創建一個新的 <script></script> 標籤元素在內存中 (這意味著它還沒有呈現到頁面上,只是在瀏覽器的內存存儲中)。我們希望這會創建一個 DOM 元素(就我們的代碼而言是一個對象),我們將其存儲在變量 script 中 .

在該對像上,我們可以在新的 <script></script> 上設置屬性 動態標記。在這裡,我們要設置為 src url 的屬性 我們從 urls 獲得 上面的對象和 id name 的屬性 我們傳入 loadScript() .

設置了這些屬性後,我們的 script 已準備好附加或“渲染”到我們瀏覽器的 HTML 中。為此,我們調用 document.body.appendChild() 傳入我們的 script 變量(JavaScript 會將對象的格式識別為有效的 DOM 元素並根據請求附加它)。因為我們說的是 document.body 在這裡,我們可以期待這個 <script></script> 標記作為我們 HTML <body></body> 內的最後一個元素添加 標籤:

最後,在我們的腳本被附加後,我們分配一個 onload 當文件位於 url 時,我們的瀏覽器將調用它的函數 我們設置為 src 已加載。在裡面,如果我們的 callback 被定義了,我們稱之為。

這對我們的加載程序的定義是有效的。接下來,我們來看看它的使用,看看它是如何工作的。

調用動態腳本加載器

為了使用我們的加載器,我們將利用本教程開始時我們開始使用的操縱桿框架中內置的組件功能。當我們運行 joystick create app ,我們在 /ui/pages/index/index.js 處自動獲得了一個組件 在我們的項目中。讓我們打開那個文件並拉入我們的 loadScript() 功能。

/ui/pages/index/index.js

import ui, { get } from "@joystick.js/ui";
import Quote from "../../components/quote";
import loadScript from "../../../lib/loadScript";

const Index = ui.component({
  lifecycle: {
    onMount: (component) => {
      loadScript('googleMaps', () => {
        new google.maps.Map(document.getElementById("map"), {
          center: { lat: -34.397, lng: 150.644 },
          zoom: 8,
        });
      });
    },
  },
  methods: { ... },
  events: { ... },
  css: `
    div p {
      font-size: 18px;
      background: #eee;
      padding: 20px;
    }

    #map {
      width: 100%;
      height: 300px;
    }
  `,
  render: ({ component, i18n }) => {
    return `
      <div>
        <p>${i18n("quote")}</p>
        ${component(Quote, {
          quote: "Light up the darkness.",
          attribution: "Bob Marley",
        })}
        <div id="map"></div>
      </div>
    `;
  },
});

export default Index;

在頂部,我們 import loadScript 來自 /lib/loadScript.js 我們創建它的路徑(省略 .js 最後在這裡很好,因為我們的構建工具會自動嘗試加載 .js 作為導入過程的一部分,此 URL 中的文件)。

我們要注意的部分是lifecycle.onMount 函數被定義在我們組件的頂部附近。如果我們查看該函數的內部,我們正在調用我們的 loadScript() 函數首先傳遞 name 我們要加載的腳本,然後是我們的 callback 功能。仔細查看回調。請記住:我們的目標是加載 Google 地圖庫,以便在加載後立即使用它。在這裡,因為我們的 callback 在我們的腳本加載後觸發,我們可以假設谷歌地圖是可用的。

按照這個假設,我們調用 new google.maps.Map() 方法,傳入我們要加載地圖的 DOM 節點(如果我們往下看 render() 我們組件的函數,我們可以看到一個 <div id="map"></div> 被渲染為我們的地圖應該被渲染的佔位符。在這裡,我們說 document.getElementById() 得到那個 <div></div> 瀏覽器中元素的 DOM 節點。

而已。如果我們在瀏覽器中查看我們的應用程序 http://localhost:2600 幾毫秒後,我們應該會看到我們的 Google Map 加載(如果沒有,請仔細檢查您的 API 密鑰並關閉所有廣告攔截器)。

總結

在本教程中,我們學習瞭如何編寫函數來幫助我們動態創建和注入 <script></script> 標記到我們的 HTML 中。為此,我們獲取腳本的名稱並將其映射到該腳本位於對像上的 URL,然後使用 document.createElement() 從 JavaScript 函數創建一個腳本標記,然後將其附加到 <body></body> 在我們的 DOM 中添加標籤。最後,我們學會瞭如何調用我們的 loadScript() 將 Google Maps 地圖呈現到頁面的函數。


Tutorial JavaScript 教程
  1. 如何使用 React + Supabase Pt 2:使用數據庫

  2. HTML 中的 JavaScript 聯繫表單驗證 |示例代碼

  3. 從 Javascript 對像中選擇隨機屬性

  4. ⏲️使用 AWS 在 5 分鐘內為您的靜態網站實施 CI-CD。

  5. 如何使用 Ajax 在 PHP 和 MySQL 中使用 Bootstrap Datepicker

  6. React - 認識虛擬 DOM

  7. JavaScript 的第三個時代

  1. Angular 開發模擬外部調用

  2. 🤷‍♀️神秘谷的同名🙋‍♂️🌄

  3. React Hooks - 如何安全地使用狀態

  4. 為什麼我們停止使用 npm start 來運行我們的區塊鏈核心子進程

  5. 使用 JavaScript 獲取全局變量

  6. 投票:你知道在 JavaScript 中,`a ==null` 到底是乾什麼用的嗎?

  7. 解決方案:交換鍊錶中的節點

  1. 在 Red Hat Mobile Node.js 應用程序中使用 New Relic

  2. QZ 托盤:通過瀏覽器打印到熱敏打印機

  3. Vue.js 101 - 事件對象,v-for 和 v-bind

  4. React v17.0 有什麼新功能?