Skip to content

Nuxt 插件

Nuxt 插件是一种机制,允许你在 Vue 应用初始化前后注入自定义功能。它们可以用于:

注意

  1. 注册全局组件

  2. 添加 Vue 插件

  3. 定义全局混入(mixins)

  4. 创建自定义指令

  5. 提供全局工具函数

  6. 集成第三方库

插件系统是 Nuxt 架构的核心部分,许多官方模块(如 Pinia、Auth、i18n)都是通过插件方式集成到 Nuxt 应用中的。

插件基础

创建你的第一个插件

在 Nuxt 项目中,插件存放在 plugins 目录中。创建一个新插件只需几个简单步骤:

  • 在项目根目录下创建 plugins 文件夹(如果不存在)

  • 在 plugins 目录中创建新的 JavaScript 文件,例如 my-first-plugin.js

一个最基本的插件结构如下

js
// plugins/my-first-plugin.js
export default defineNuxtPlugin((nuxtApp) => {
  // 这里可以访问 nuxtApp 实例

  console.log("我的第一个Nuxt插件已加载!");

  // 可以返回一个对象,提供全局可用的功能
  return {
    provide: {
      sayHello: (name) => `你好, ${name}!`,
    },
  };
});

注册到 Nuxt 应用

  • nuxt.config.js

注意

  1. 在 plugins 目录中要是没有二级目录 nuxt3 会自动识别,不用注册

  2. 要是有二级目录 请看我下面的代码

  • 注册插件
ts
    // 安装插件
plugins: [
'~/plugins/rem/flexible.js',
'~/plugins/elementicon/element-plus-icons.js',
'~/plugins/myCustom/myCustom.js',
'~/plugins/myCustom/myCustom.client.js',
'~/plugins/myCustom/myCustom.server.js',
'~/plugins/myCustom/myError.js',
'~/plugins/myCustom/myzhiling.js'
],

使用

js
<div class="textColor">登录页面内容--{{ $sayHelloCustom('李四') }}</div>

插件类型与执行环境

客户端 vs 服务端插件

默认情况下,插件会在客户端和服务端都运行。但在某些情况下,你可能需要指定插件只在特定环境中运行:

  • 仅客户端插件:添加 .client 后缀,如 my-plugin.client.js

  • 仅服务端插件:添加 .server 后缀,如 my-plugin.server.js

js
// plugins/analytics.client.js - 只在客户端运行
export default defineNuxtPlugin((nuxtApp) => {
  // 初始化客户端分析工具
  console.log("初始化分析工具 (仅客户端)");
});

插件执行顺序

插件执行顺序有时很重要,特别是当插件之间存在依赖关系时。Nuxt 提供了几种控制顺序的方法:

注意

  1. 文件名前缀 使用数字前缀加载顺序.比如01-plugin.js02-plugin.js执行顺序靠前

  2. 目录结构:插件按照字母顺序加载,数字前缀拥有更高优先级

  3. 显示顺序: 在 nuxt.config.js 中 plugins 数组中数组顺序

js
// nuxt.config.js
export default defineNuxtConfig({
  plugins: ["~/plugins/01-first-plugin.js", "~/plugins/02-second-plugin.js"],
});

插件的高级用法

集成 Vue 插件

许多 Vue 插件可以轻松集成到 nuxt

js
// plugins/vue-toastification.js
import Toast from "vue-toastification";
import "vue-toastification/dist/index.css";

export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.vueApp.use(Toast, {
    timeout: 2000,
    position: "top-right",
  });
});

注册全局组件

对于在整个应用中频繁使用的组件,全局注册可以简化导入

js
// plugins/global-components.js
import MyButton from "~/components/ui/MyButton.vue";
import MyInput from "~/components/ui/MyInput.vue";

export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.vueApp.component("MyButton", MyButton);
  nuxtApp.vueApp.component("MyInput", MyInput);
});

创建自定义指令

自定义指令是 Vue 的强大功能,可以通过插件全局注册:

js
// plugins/directives.js
export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.vueApp.directive("focus", {
    mounted(el) {
      el.focus();
    },
    updated(el) {
      el.focus();
    },
  });

  nuxtApp.vueApp.directive("animate", {
    mounted(el, binding) {
      el.style.transition = "all 0.3s";
      el.addEventListener("mouseenter", () => {
        el.style.transform = "scale(1.05)";
      });
      el.addEventListener("mouseleave", () => {
        el.style.transform = "scale(1)";
      });
    },
  });
});
  • 使用自定义指令
js
<input type="text":value="valueinput" v-focus ></input>

提供全局的工具函数

通过插件的 provide 选项,可以创建全局可用的工具函数:

js
// plugins/utilities.js
export default defineNuxtPlugin((nuxtApp) => {
  const utilities = {
    formatDate(date, locale = "en-US") {
      return new Date(date).toLocaleDateString(locale);
    },
    truncate(text, length = 100) {
      return text.length > length ? text.substring(0, length) + "..." : text;
    },
    copyToClipboard(text) {
      // 判断是否服务器还是客户端
      if (process.client) {
        navigator.clipboard.writeText(text);
      }
    },
  };

  return {
    provide: {
      utils: utilities,
    },
  };
});

使用这些工具函数

html
<script setup>
  const { $utils } = useNuxtApp();
  const formattedDate = $utils.formatDate(new Date());
  const truncatedText = $utils.truncate("这是一段很长的文本...", 10);
</script>

异步插件

有时你的插件需要执行异步操作,如获取数据或等待某些资源加载。Nuxt 插件完全支持异步操作:

js
// plugins/async-plugin.js
export default defineNuxtPlugin(async (nuxtApp) => {
  // 模拟异步数据获取
  const response = await $fetch("/api/site-settings");

  // 将获取的数据提供给整个应用
  return {
    provide: {
      siteSettings: response.data,
    },
  };
});

插件最佳实践

保持插件轻量

插件在应用启动时运行,应避免执行大量同步操作或复杂的计算,这会拖慢应用启动速度。

合理组织插件

  • 按功能划分插件(如 axios.js、auth.js、ui-components.js)

  • 为插件添加清晰的命名和注释

  • 考虑将大型插件拆分为多个小插件

处理错误

为插件添加适当的错误处理:

js
// plugins/error-handling.js
export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.vueApp.config.errorHandler = (err, vm, info) => {
    // 处理错误
    console.error("全局错误:", err);

    // 可以发送错误到错误跟踪服务
    if (process.client) {
      sendToErrorTrackingService(err);
    }
  };
});

类型安全(TS)

如果你使用 TypeScript,可以为插件提供类型定义:

ts
// plugins/my-plugin.ts
export default defineNuxtPlugin((nuxtApp) => {
  return {
    provide: {
      hello: (name: string): string => `Hello ${name}`,
    },
  };
});

// types/nuxt.d.ts
declare module "#app" {
  interface NuxtApp {
    $hello: (name: string) => string;
  }
}

实际案例

案例 1 集成 axios

ts
// plugins/axios.js
export default defineNuxtPlugin((nuxtApp) => {
  const axios = {
    get: (url) => $fetch(url),
    post: (url, data) => $fetch(url, { method: "POST", body: data }),
    put: (url, data) => $fetch(url, { method: "PUT", body: data }),
    delete: (url) => $fetch(url, { method: "DELETE" }),
  };

  return {
    provide: {
      axios,
    },
  };
});

案例 2: 实现权限检查

ts
// plugins/auth.js
export default defineNuxtPlugin((nuxtApp) => {
  const auth = {
    user: null,

    async login(credentials) {
      const { data } = await $fetch("/api/login", {
        method: "POST",
        body: credentials,
      });
      this.user = data.user;
      return data;
    },

    logout() {
      this.user = null;
    },

    can(permission) {
      return this.user?.permissions?.includes(permission);
    },
  };

  return {
    provide: {
      auth,
    },
  };
});