插件使用

了解如何正确安装、配置和使用 Vue 插件,是开发 Vue 应用的重要技能。

安装插件

npm 安装

npm install vue-router vuex element-ui

CDN 引入

<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue-router@3.5.3/dist/vue-router.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuex@3.6.2/dist/vuex.js"></script>

注册插件

基本注册

import Vue from 'vue'
import VueRouter from 'vue-router'
import Vuex from 'vuex'

Vue.use(VueRouter)
Vue.use(Vuex)

带配置注册

import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'

Vue.use(ElementUI, {
  size: 'small',
  zIndex: 3000
})

插件安装顺序

某些插件有依赖关系,需要注意安装顺序:

import Vue from 'vue'
import Vuex from 'vuex'
import VueRouter from 'vue-router'

Vue.use(Vuex)
Vue.use(VueRouter)

const store = new Vuex.Store({ /* ... */ })
const router = new VueRouter({ /* ... */ })

new Vue({
  store,
  router
})

插件配置

全局配置

import axios from 'axios'
import VueAxios from 'vue-axios'

Vue.use(VueAxios, axios)

Vue.axios.defaults.baseURL = 'https://api.example.com'
Vue.axios.defaults.timeout = 10000
Vue.axios.defaults.headers.common['Authorization'] = 'Bearer token'

环境配置

const isProduction = process.env.NODE_ENV === 'production'

Vue.use(httpPlugin, {
  baseURL: isProduction ? 'https://api.example.com' : 'http://localhost:3000',
  timeout: isProduction ? 10000 : 30000,
  debug: !isProduction
})

动态配置

const config = {
  theme: localStorage.getItem('theme') || 'light',
  locale: navigator.language || 'zh-CN'
}

Vue.use(uiPlugin, config)

常见插件使用示例

Vue Router

import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from './views/Home.vue'
import About from './views/About.vue'

Vue.use(VueRouter)

const routes = [
  { path: '/', component: Home },
  { path: '/about', component: About }
]

const router = new VueRouter({
  mode: 'history',
  routes
})

new Vue({
  router,
  render: h => h(App)
}).$mount('#app')

Vuex

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

const store = new Vuex.Store({
  state: {
    count: 0,
    user: null
  },
  mutations: {
    increment(state) {
      state.count++
    },
    setUser(state, user) {
      state.user = user
    }
  },
  actions: {
    async login({ commit }, credentials) {
      const user = await api.login(credentials)
      commit('setUser', user)
    }
  },
  getters: {
    isLoggedIn: state => !!state.user
  }
})

new Vue({
  store,
  render: h => h(App)
}).$mount('#app')

Element UI

import Vue from 'vue'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
import locale from 'element-ui/lib/locale/lang/zh-CN'

Vue.use(ElementUI, {
  locale,
  size: 'medium'
})

new Vue({
  render: h => h(App)
}).$mount('#app')

按需引入

import Vue from 'vue'
import { Button, Input, Select, Table } from 'element-ui'

Vue.use(Button)
Vue.use(Input)
Vue.use(Select)
Vue.use(Table)

Axios

import Vue from 'vue'
import axios from 'axios'
import VueAxios from 'vue-axios'

Vue.use(VueAxios, axios)

Vue.axios.interceptors.request.use(config => {
  const token = localStorage.getItem('token')
  if (token) {
    config.headers.Authorization = `Bearer ${token}`
  }
  return config
})

Vue.axios.interceptors.response.use(
  response => response.data,
  error => {
    if (error.response?.status === 401) {
      localStorage.removeItem('token')
      window.location.href = '/login'
    }
    return Promise.reject(error)
  }
)

插件封装

统一管理

import Vue from 'vue'
import VueRouter from './router'
import Vuex from './store'
import httpPlugin from './plugins/http'
import toastPlugin from './plugins/toast'
import loadingPlugin from './plugins/loading'

const plugins = [
  { plugin: VueRouter, options: {} },
  { plugin: Vuex, options: {} },
  { plugin: httpPlugin, options: { baseURL: '/api' } },
  { plugin: toastPlugin, options: { duration: 3000 } },
  { plugin: loadingPlugin, options: {} }
]

plugins.forEach(({ plugin, options }) => {
  Vue.use(plugin, options)
})

export default Vue

插件配置文件

export default {
  http: {
    baseURL: process.env.VUE_APP_API_URL,
    timeout: 10000
  },
  toast: {
    duration: 3000,
    position: 'top'
  },
  ui: {
    theme: 'light',
    size: 'medium'
  }
}
import config from './config'

Vue.use(httpPlugin, config.http)
Vue.use(toastPlugin, config.toast)
Vue.use(uiPlugin, config.ui)

最佳实践

插件命名

Vue.prototype.$http = axios
Vue.prototype.$loading = loading
Vue.prototype.$toast = toast
Vue.prototype.$confirm = confirm

避免重复安装

if (!Vue._installedPlugins?.includes(myPlugin)) {
  Vue.use(myPlugin)
}

类型检查

Vue.use = new Proxy(Vue.use, {
  apply(target, thisArg, args) {
    const [plugin, options] = args
    if (typeof plugin.install !== 'function' && typeof plugin !== 'function') {
      console.warn('Invalid plugin: plugin must have an install method')
      return thisArg
    }
    return target.apply(thisArg, args)
  }
})

错误处理

const safePlugin = {
  install(Vue, options) {
    try {
      Vue.prototype.$method = function() {
        // ...
      }
    } catch (error) {
      console.error('Plugin installation failed:', error)
    }
  }
}

插件卸载

const plugin = {
  install(Vue) {
    const originalMethod = Vue.prototype.$destroy
    
    Vue.prototype.$destroy = function() {
      if (this.$pluginCleanup) {
        this.$pluginCleanup()
      }
      originalMethod.call(this)
    }
  }
}

调试插件

开发模式检测

const plugin = {
  install(Vue, options) {
    const isDev = process.env.NODE_ENV !== 'production'
    
    if (isDev) {
      console.log('Plugin installed with options:', options)
    }
  }
}

插件状态检查

const plugin = {
  install(Vue) {
    Vue.prototype.$pluginStatus = function() {
      return {
        installed: true,
        version: '1.0.0'
      }
    }
  }
}

小结

插件使用要点:

  1. 正确安装:使用 Vue.use() 注册插件
  2. 合理配置:根据需求配置插件选项
  3. 注意顺序:有依赖的插件按顺序安装
  4. 按需引入:减少不必要的代码体积
  5. 统一管理:集中管理插件配置