重生之我在学Vue--第16天 Vue 3 插件开发

发布于:2025-03-20 ⋅ 阅读:(15) ⋅ 点赞:(0)

重生之我在学Vue–第16天 Vue 3 插件开发

前言

在 Vue 的世界里,插件就像是一把万能钥匙,它能让我们将通用功能封装成可复用的模块,实现 全局能力扩展。今天我们将从零开发一个全局通知插件,让你的 Vue 应用拥有优雅的消息提示能力!

Vue3 官方中文文档传送点: 插件 | Vue.js

插件开发的核心是理解 install 方法全局资源注册 的机制

Vue前端成仙之路:Vue 前端成仙之路_野生的程序媛的博客-CSDN博客

GO后端成神之路:Go 后端成神之路_野生的程序媛的博客-CSDN博客

一、插件的作用与开发思路

1.1 插件能做什么?

场景 实现方式 典型案例
全局组件注册 app.component() Element Plus 组件库
全局指令添加 app.directive() v-loading 指令
全局混入逻辑 app.mixin() 权限校验逻辑
全局属性/方法注入 app.config.globalProperties $axios 实例

1.2 插件开发四部曲

  1. 定义插件对象:包含 install 方法
  2. 注册全局资源:组件/指令/属性等
  3. 注入应用实例:通过 app.use() 安装
  4. 项目中调用:任意组件内使用

二、开发全局通知插件

2.1 插件基础结构

// plugins/notification.js
export default {
  install: (app, options) => {
    // 在这里注册全局资源
  }
}

2.2 完整插件代码(带注释解析)

import { h, render, ref } from 'vue'

// 1. 创建通知容器组件
const NotificationContainer = {
  setup() {
    const notifications = ref([])

    // 添加通知
    const add = (notification) => {
      notifications.value.push(notification)
      
      // 自动关闭
      if (notification.duration > 0) {
        setTimeout(() => {
          remove(notification.id)
        }, notification.duration)
      }
    }

    // 移除通知
    const remove = (id) => {
      notifications.value = notifications.value.filter(n => n.id !== id)
    }

    return { notifications, add, remove }
  },
  render() {
    return h('div', { class: 'notification-container' },
      this.notifications.map(notification => 
        h(NotificationItem, {
          key: notification.id,
          ...notification,
          onClose: () => this.remove(notification.id)
        })
      )
    )
  }
}

// 2. 单个通知项组件
const NotificationItem = {
  props: ['type', 'message', 'onClose'],
  render() {
    return h('div', { class: ['notification', this.type] }, [
      h('span', this.message),
      h('button', { onClick: this.onClose }, '×')
    ])
  }
}

// 3. 插件安装逻辑
export default {
  install(app) {
    // 创建挂载节点
    const mountNode = document.createElement('div')
    document.body.appendChild(mountNode)
    
    // 渲染通知容器
    render(h(NotificationContainer), mountNode)
    
    // 注入全局方法
    app.config.globalProperties.$notify = {
      show: (message, options = {}) => {
        const id = Date.now()
        const notification = {
          id,
          message,
          type: options.type || 'info',
          duration: options.duration || 3000
        }
        
        // 通过事件总线触发添加
        const event = new CustomEvent('add-notification', { detail: notification })
        document.dispatchEvent(event)
      }
    }
    
    // 监听添加事件
    document.addEventListener('add-notification', (e) => {
      const instance = mountNode._vnode.component.ctx
      instance.add(e.detail)
    })
  }
}

2.3 样式文件 notification.css

.notification-container {
  position: fixed;
  top: 20px;
  right: 20px;
  z-index: 9999;
}

.notification {
  padding: 12px 20px;
  margin-bottom: 10px;
  border-radius: 4px;
  background: #f4f4f5;
  color: #909399;
  min-width: 200px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  box-shadow: 0 2px 12px rgba(0,0,0,.1);
}

.notification.success {
  background: #f0f9eb;
  color: #67c23a;
}

.notification.error {
  background: #fef0f0;
  color: #f56c6c;
}

三、插件的安装与使用

3.1 在 main.js 中安装

import { createApp } from 'vue'
import App from './App.vue'
import notification from './plugins/notification'
import './styles/notification.css'

const app = createApp(App)
app.use(notification)
app.mount('#app')

3.2 在组件中使用

<template>
  <button @click="showNotification">触发通知</button>
</template>

<script setup>
import { getCurrentInstance } from 'vue'

const { proxy } = getCurrentInstance()

const showNotification = () => {
  proxy.$notify.show('操作成功!', { 
    type: 'success',
    duration: 2000 
  })
}
</script>

四、插件开发进阶技巧

4.1 支持 TypeScript 类型

// types/notification.d.ts
import { ComponentPublicInstance } from 'vue'

declare module '@vue/runtime-core' {
  interface ComponentCustomProperties {
    $notify: {
      show: (message: string, options?: NotificationOptions) => void
    }
  }
}

interface NotificationOptions {
  type?: 'info' | 'success' | 'error'
  duration?: number
}

4.2 响应式状态管理

// 使用 Pinia 管理通知状态
import { defineStore } from 'pinia'

export const useNotificationStore = defineStore('notification', {
  state: () => ({
    list: []
  }),
  actions: {
    add(notification) {
      this.list.push(notification)
    },
    remove(id) {
      this.list = this.list.filter(n => n.id !== id)
    }
  }
})

五、今日任务:开发并集成通知插件

任务要求

  1. 按照示例代码实现通知插件
  2. 在任务管理系统中添加以下通知场景:
    • 任务创建成功
    • 任务删除确认提示
    • 网络请求失败的报错提示
  3. (扩展)实现通知的渐入渐出动画

代码示例:动画实现

<template>
  <TransitionGroup 
    name="notification"
    tag="div"
    class="notification-container"
  >
    <!-- 通知项 -->
  </TransitionGroup>
</template>

<style>
.notification-enter-active,
.notification-leave-active {
  transition: all 0.5s ease;
}

.notification-enter-from,
.notification-leave-to {
  opacity: 0;
  transform: translateX(100%);
}
</style>

结语

通过开发全局通知插件,我们掌握了 Vue 插件开发的 核心模式:利用 install 方法扩展全局能力。插件开发的关键点在于:

  1. 全局资源隔离:通过 DOM 操作创建独立挂载点
  2. 响应式状态管理:使用 ref/reactive 跟踪通知状态
  3. 架构可扩展性:支持类型扩展、样式定制等功能

网站公告

今日签到

点亮在社区的每一天
去签到