🏅 Day 16 - Nuxt3 插件 ( Plugins )  - provide

今日學習目標

  • 學習建立插件的基本結構
  • 學習使用插件的 provide 方法建立全域的輔助函式 ( helper )
  • 理解插件的執行環境設置 ( client / server )

前言

在開發的過程中,經常需要將第三方套件整合到專案中以節省開發時間。Nuxt 官方提供了一些與 Nuxt3 整合的模組,例如 PiniaTailwind CSS。如果我們需要使用的套件沒有被整合進 Nuxt3 模組,就可以利用 Nuxt 的 Plugin 功能來將這些外部套件添加到 Nuxt 中。

Nuxt3 插件功能提供了 providedirectiveuse 三種建立方式。今天將專注於介紹插件的基本結構和 provide 的實作,未來將會進一步探討 directiveuse 的使用。

建立插件的基本結構

Nuxt3 插件必需放置在 plugins/ 資料夾內。Nuxt 會在應用程式啟動時,自動掃描並註冊該資料夾中第一層的所有插件。可以使用 npx nuxi add plugin 插件檔案名稱 指令建立插件,產生一個包含 defineNuxtPlugin() 方法的檔案。defineNuxtPlugin() 會接收一個傳入 nuxtApp 參數的函式,我們可以透過這個參數來實現插件的功能。

export default defineNuxtPlugin(nuxtApp => {
  // 使用 nuxtApp 參數實作功能
  console.log(nuxtApp);
})

nuxtApp 參數

nuxtApp 參數是 Nuxt 的 實體 (Instance) ,允許我們操作 Nuxt 的全域功能 ( 如下圖 ) ,例如 Vue 的全域實體 vueAppnuxtApp.provide() 等功能。

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

插件目錄

Nuxt 只會自動註冊 plugins/ 資料夾第一層的插件,位於子目錄中的插件不會被自動註冊。例如下方檔案結構中只有 pluginA.js 會被自動註冊,而 admin/pluginB.js 則不會。

plugins/
├── admin/
│   └── pluginB.js
└── pluginA.js

如果希望註冊子目錄的 admin/pluginB.js 插件,需要在 nuxt.config.ts 中使用 plugins 屬性明確指定:

export default defineNuxtConfig({
  plugins: [
    "~/plugins/admin/pluginB", // ~ 路徑指向 /<srcDir>
  ]
})

插件的執行環境

插件預設在伺服器端和客戶端都可以被執行。如果需要限制插件的執行環境,可以在檔案名稱中加入後綴 .client 或 .server

plugins/
├── pluginC.js           // 在伺服器和客戶端均執行
├── pluginD.client.js    // 僅在客戶端執行 
├── pluginE.server.js    // 僅在伺服器端執行

建立輔助函式

學習完插件的建立方式、nuxtApp 參數的用法以及執行環境之後,接下來將介紹如何使用 nuxtApp.provide() 方法來實作全域輔助函式

建立方式

輔助函式的建立方式有兩種。第一種方式是使用 nuxtApp.provide() 方法在第一個參數放入字串格式的名稱,第二個參數放入函式並回傳自定義的資料格式。第二種方式是回傳一個包含 provide 屬性的物件,provide物件內的屬性名稱為輔助函式的名稱,屬性值放入執行的函式。例如下方的範例,使用了 nuxtApp.provide() 或是 return provide 物件的方式建立名稱為 'example' 的輔助函式。

// plugins/example.js

export default defineNuxtPlugin(nuxtApp => {
  // 方法一 : nuxtApp.provide(輔助函式名稱,執行的輔助函式);
  // 如果只需要在插件中定義一個輔助函式,nuxtApp.provide() 更方便的方式。
  nuxtApp.provide('example', (date) => `${date} | 使用 Nuxt3 plugin 功能實作全域helper`);

  // 方法二. 
  // 若需要定義多個輔助函式,或想要方便管理可以使用 return 方式,將所有輔助函式放入 `provide` 物件內
  return {
    provide: {
      // 輔助函式的功能都放在 provide 物件內
      
      // 建立名稱為 example 的輔助函式
      example: (date) => `${date} | 使用 Nuxt3 plugin 功能實作全域 helper`
    }
  };
})

使用方式

執行時會將 defineNuxtPlugin() 定義的輔助函式寫入全域 NuxtApp 的執行環境,在所有元件的<script setup></script> 中都能夠透過 useNuxtApp() 函式 取出。接續上方建立的 'example' 插件,在 /pages/index.vue 頁面中可以使用 const { $example } = useNuxtApp() 的方式解構出函式,然後在 <template></template> 或是 <script setup></script> 內執行。

// /pages/index.vue
<script setup>
const { $example } = useNuxtApp()

// 也可以在 JS 區塊執行
console.log($example('Day16'))
</script>

<template>
  <h1>在模板內執行</h1>
  <div>
    {{ $example('Day16')  }}
  </div>
</template>

❗ 注意 : 所有使用插件定義的輔助函式在元件中取用都需要加上錢字符號 $ ,例如 $example()

實作 : 第三方套件加入輔助函式

除了自訂的輔助函式以外,也可以把外部套件的方法加入全域的輔助函式。以 sweetAlert2 為例,在 plugins/sweetalert2.js 加入了 showAlert 函式。

// plugins/sweetalert2.js

import Swal from "sweetalert2";

function showAlert({
  title = "Good job!",
  text = "You clicked the button!",
  icon = "success",
  showCloseButton = true,
  showCancelButton = true,
  ...otherParameters
} = {}) {
  Swal.fire({
    title,
    text,
    icon,
    showCloseButton,
    showCancelButton,
    ...otherParameters,
  });
}

export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.provide("showAlert", showAlert);
});

然後在頁面元件的模板或是 JavaScript 都可以執行 $showAlert 開啟提示視窗 :

<script setup>
const { $showAlert } = useNuxtApp();
</script>

<template>
  <h2>開啟 sweetAlert2</h2>
  <button
    @click="$showAlert({ showDenyButton: true, denyButtonText: `Don't save` })">
    開啟
  </button>
</template>


今日學習的範例 Code - 資料夾: day16-plugin-provide-example

題目

請 fork 這一份 模板 ,完成以下條件 :

  • 使用 Nuxt3 Plugin 功能在 /plugins/bootstrap.js 引入 bootstrap5 v5.3.3 版本OffcanvasModal 元件的 JavaScript 功能,並將 new bootstrap.Offcanvas()new bootstrap.Modal() 提供為全域輔助函式。( Modal 官方文件Offcanvas 官方文件)
// 加入全域輔助函式

 new bootstrap.Offcanvas(element, options);
 new bootstrap.Modal(element, options);
  • /pages/index.vue 中,從 Plugin 取出 OffcanvasModal 並在 onMounted 生命週期初始化元件。使用 <template> 中的按鈕,透過 @click 事件來操作元件的 .show().hide() 方法,以控制元件的開啟與關閉。
  • bootstrap5 SCSS 在模板中已經有提供,不需額外設定。
  • 請根據下圖 bootstrap5 v5.3.3 Modal 功能的 原始碼 判斷 Plugin 是否需要限制插件的執行環境(伺服器端或客戶端,或是無需限制)。

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

回報流程

將答案上傳至 GitHub 並複製 GitHub repo 連結貼至底下回報就算完成了喔 !
解答位置請參考下圖(需打開程式碼的部分觀看)

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

回報區

# Discord Github / 答案
1 眼睛 Github
2 LinaChen Github
3 Steven Github
4 Rocky Github
5 MY Github
6 hsin yu Github
7 dragon Github
8 Jim Lin Github
9 tanuki狸 Github
10 Ariel Github
11 Johnson Github
12 阿塔 Github