乐于分享
好东西不私藏

一个完整的VUE3插件代码实例

一个完整的VUE3插件代码实例

一个完整的VUE3插件代码实例

软件老师 罗光宣

        这段代码构建了一个基于Vue 3的动态插件系统,其核心功能是允许用户动态启用和停用插件,并且支持插件之间的事件通信。以下是对代码的详细说明:

整体架构

整个系统包含多个插件,如 analytics(数据分析)和 logger(系统日志),每个插件有自己的功能模块和生命周期方法。系统通过插件管理器来加载、激活和停用这些插件,并使用事件总线来实现插件间的通信。

主要文件及功能介绍

1. 目录结构

src/├── plugins/├── analytics/├── index.js└── analytics.vue│── logger/├── index.js└── logger.vueApp│── exApp├── pluginLoader.js├── pluginBus.js└── App_Ex_Plugins.vue

2. plugins/exApp/App_Ex_Plugins.vue

·模板部分

o提供了一个用户界面,包含插件启用/禁用按钮和插件显示区域。

o有一个“发送测试事件”按钮,用于触发事件。

·脚本部分

o使用 availablePlugins 存储可用插件列表,activePlugins 存储当前激活的插件。

otogglePlugin 方法用于动态加载和卸载插件,通过 loadPlugin 函数实现。

osendTestEvent 方法用于发送 log 和 order-created 事件。

<template>  <divclass="app">    <h1>动态插件系统</h1>    <divclass="button-group">      <button        v-for="plugin in availablePlugins"        :key="plugin"        @click="togglePlugin(plugin)"        :class="{ active: activePlugins.includes(plugin) }"      >        {{ activePlugins.includes(plugin) ? '禁用' : '启用' }} {{ plugin }}      </button>    </div>    <divclass="plugin-container">      <templatev-if="loading">加载插件中...</template>      <templatev-else>        <component          v-for="plugin in activeComponents"          :is="plugin.component"          :key="plugin.name"        />      </template>    </div><button @click="sendTestEvent">发送测试事件</button>  </div></template><scriptsetup>import { ref, shallowRef } from 'vue'import { loadPlugin } from './pluginLoader'import { usePluginBus } from './pluginBus'const bus = usePluginBus()// 可用插件列表const availablePlugins = ['analytics''logger']const activePlugins = ref([])const activeComponents = shallowRef([])const loading = ref(false)const togglePlugin = async (pluginName) => {  loading.value = true  try {    if (activePlugins.value.includes(pluginName)) {      // 停用插件      activePlugins.value = activePlugins.value.filter(name => name !== pluginName)      activeComponents.value = activeComponents.value.filter(p => p.name !== pluginName)    } else {      // 激活插件      const plugin = await loadPlugin(pluginName)      activePlugins.value.push(pluginName)      activeComponents.value = [        ...activeComponents.value,        {          name: pluginName,          component: plugin.component        }      ]      await plugin.install?.()    }  } catch (err) {    console.error(`插件 ${pluginName} 操作失败:`, err)  } finally {    loading.value = false  }}  // 发送测试事件  const sendTestEvent = () => {    bus.emit('log''用户点击了测试按钮')    bus.emit('order-created', { id123amount99.9 })  }</script><style>.app {  font-family: Arial, sans-serif;  max-width800px;  margin0 auto;  padding20px;}.button-group {  margin20px 0;  display: flex;  gap10px;}button {  padding8px 16px;  background#f0f0f0;  border1px solid #ddd;  border-radius4px;  cursor: pointer;}button.active {  background#e0e0ff;  border-color#a0a0ff;}.plugin-container {  min-height100px;  padding15px;  border1px solid #eee;  border-radius4px;}</style>

3. plugins/exApp/pluginLoader.js

·loadPlugin 函数:

o动态导入插件的 index.js 文件和对应的 .vue 组件。

o使用 Map 缓存插件定义,避免重复加载。

import { defineAsyncComponent } from 'vue'const plugins = new Map()export async function loadPlugin(pluginName) {  if (plugins.has(pluginName)) {    return plugins.get(pluginName)  }  try {    // 动态导入插件逻辑(修复路径错误)    const pluginModule = await import(      /* @vite-ignore */      `../${pluginName}/index.js`    )    // 缓存插件定义    plugins.set(pluginName, {      name: pluginName,      componentdefineAsyncComponent(() =>         import(`../${pluginName}/${pluginName}.vue`)      ),      install: pluginModule.install,      uninstall: pluginModule.uninstall    })    return plugins.get(pluginName)  } catch (err) {    console.error(`加载插件 ${pluginName} 失败:`, err)    throw err  }}

4. plugins/analytics 文件夹

·analytics.vue

o展示今日访问量和转化率数据。

o监听 order-created 事件,当事件触发时打印订单信息。

<template>  <divclass="analytics-panel">    <h3>数据分析面板</h3>    <divv-if="data">      <p>今日访问量: {{ data.visits }}</p>      <p>转化率: {{ data.conversion }}%</p>    </div>  </div></template><scriptsetup>import { ref, onMounted } from 'vue'import { usePluginBus } from '../exApp/pluginBus'const data = ref(null)const bus = usePluginBus()onMounted(() => {  // 模拟数据加载  setTimeout(() => {    data.value = {      visits1243,      conversion3.2    }  }, 500)  // 监听其他插件事件  bus.on('order-created'(order) => {    console.log('订单创建事件:', order)  })})</script>

·index.js

o定义了 analytics 插件,包含安装和卸载方法。

o在安装时,向应用程序提供 analytics 服务,用于追踪事件。

//import Analytics from './Analytics.vue'export default {  name'analytics',  component() => import('./Analytics.vue'), // ✅ 正确:动态导入  install(app, options) {    console.log('Analytics插件安装', options)    // 注册全局服务    app.provide('analytics', {      trackEvent(event) => {        console.log('追踪事件:', event)      }    })  },  uninstall() {    console.log('Analytics插件卸载')  }}

5. plugins/logger 文件夹

·logger.vue

o显示系统日志列表。

o监听 log 事件,将日志信息添加到列表中。

<template>  <divclass="logger-panel">    <h3>系统日志</h3>    <ul>      <liv-for="(log, index) in logs":key="index">        [{{ log.time }}] {{ log.message }}      </li>    </ul>  </div></template><scriptsetup>import { ref } from 'vue'import { usePluginBus } from '../exApp/pluginBus'const logs = ref([])const bus = usePluginBus()// 监听全局日志事件bus.on('log'(message) => {  logs.value.push({    timenew Date().toLocaleTimeString(),    message  })})</script>

– **`index.js`**:– 定义了 `logger` 插件,包含安装和卸载方法。– 在安装时,向应用程序全局添加 `$log` 方法。

export default {  name'logger',  component() => import('./Logger.vue'), // 改为动态导入  install(app) {    console.log('Logger插件安装')    app.config.globalProperties.$log = (message) => {      console.log(message)    }  },  uninstall() {    console.log('Logger插件卸载')  }}

事件通信:plugins/exApp/usePluginBus.js

·使用 usePluginBus 创建的事件总线实现插件间的通信。

·App_Ex_Plugins.vue 的 sendTestEvent 方法发送 log 和 order-created 事件。

·analytics.vue 监听 order-created 事件,logger.vue 监听 log 事件。

import { ref } from 'vue'const listeners = ref({})export const usePluginBus = () => {  // 监听事件  const on = (event, callback) => {    if (!listeners.value[event]) {      listeners.value[event] = []    }    listeners.value[event].push(callback)  }  // 触发事件  const emit = (event, ...args) => {    if (listeners.value[event]) {      listeners.value[event].forEach(cb => cb(...args))    }  }  // 移除监听  const off = (event, callback) => {    if (listeners.value[event]) {      listeners.value[event] = listeners.value[event].filter(cb => cb !== callback)    }  }  return {    on,    emit,    off  }}

动态加载

·使用 defineAsyncComponent 和 import() 动态加载插件组件,实现按需加载。

插件生命周期

·每个插件通过 install 和 uninstall 方法管理其生命周期,确保在启用和停用插件时执行相应的操作。

通过这种方式,系统实现了插件的动态加载、管理和通信,提高了系统的可扩展性和灵活性。

运行情况

(1)初始运行界面

(2)点击加载Analytics插件后的运行界面

(3)点击加载Analytics与logger插件,再点击“发送测试事件”按钮后的运行界面

本站文章均为手工撰写未经允许谢绝转载:夜雨聆风 » 一个完整的VUE3插件代码实例

评论 抢沙发

6 + 6 =
  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
×
订阅图标按钮