Skip to content

vue3插件的编写

  1. 为什么要使用插件?

插件在Vue.js中是一种非常重要的功能扩展方式。使用插件可以帮助我们增加Vue.js的功能,或者改变Vue.js的行为。例如,Vue RouterVuex就是Vue.js的官方插件,它们分别为Vue.js添加了路由和状态管理的功能。此外,还有许多第三方插件可以帮助我们解决各种特定的问题,如表单验证、日期处理等。使用插件可以让我们更好地复用代码,避免重复造轮子,提高开发效率。


  1. 插件与组件的区别?

组件是Vue.js中用于构建用户界面的可复用实例,它是Vue.js的基础。每个组件都是一个独立的视图模块,有自己的模板、数据、方法等。组件可以嵌套使用,通过组件的组合和嵌套,可以构建出复杂的用户界面。

插件则是用来扩展Vue.js的功能。一个插件可以添加全局方法或属性、添加全局资源、混入全局/局部的选项、添加Vue实例方法,或者提供自己的模块。

插件的目的是为了增加全局级别的功能,而组件则是为了封装和复用代码,构建用户界面。

编写并使用插件

  1. 先编写一个loding的组件,代码如下:
vue
<template>
    <div v-if="show" class="loading">
        <p>Loading...</p>
    </div>
</template>

<script setup lang='ts'>
import { ref } from 'vue'

let show = ref<boolean>(false)

const isShow = () => {
    show.value =true
}
// 将isShow方法暴露出去,使得插件可以获取到这个方法
defineExpose({
    isShow
})
</script>
  1. 编写插件代码:
ts
import loading from './index.vue'
import { createVNode, type App,type VNode, render } from 'vue'

// loading插件 通过将loading文件夹下的index.vue挂载到全局,然后其余组件就可以直接使用
export default{
    install(app:App){
        // 要将loading转换为虚拟节点才能获取到需要的属性
        const Vnode:VNode=createVNode(loading)
        // 将虚拟节点挂载到全局body
        render(Vnode,document.body)
        // console.log(Vnode)
        // 访问全局属性,由于vue官方不给使用setupState,所以需要组件将方法暴露出来给全局使用
        app.config.globalProperties.$loadings={
            isShow:Vnode.component?.exposed?.isShow,
        }
        // console.log(Vnode.component?.exposed)
    }
}
  1. 在main.ts注册插件以及声明文件:
ts
import loading from './components/vue插件编写/loading'

export const app = createApp(App)

type Loadings = {
    isShow: () => void
}

// 声明要扩充@vue/runtime-core包的声明.
// 这里扩充"ComponentCustomProperties"接口, 因为他是vue3中实例的属性的类型.
declare module 'vue' {
    export interface ComponentCustomProperties {
        $loadings: Loadings
    }
}

// 注册插件loading
app.use(loading)

app.mount('#app')
  1. 使用插件:
vue
<script setup lang='ts'>
import { ref,getCurrentInstance } from 'vue'

// 获取当前组件的实例
const instance=getCurrentInstance()

instance?.proxy?.$loadings.isShow()

setTimeout(()=>{
    instance?.proxy?.$loadings.isShow()
},2000)
</script>

源码解读

ts
const installedPlugins = new Set()
...
use(plugin: Plugin, ...options: any[]) {
    // 判断是否已经注册过该插件
    if (installedPlugins.has(plugin)) {
        // 已经注册过就返回一个警告
        __DEV__ && warn(`Plugin has already been applied to target app.`)
    } else if (plugin && isFunction(plugin.install)) {
        // 编写插件会实现install函数,在这里进行判断是否为函数
        // 是函数就添加进set中进行缓存,然后调用这个函数将插件注册进app中,以及一些配置属性options
        installedPlugins.add(plugin)
        plugin.install(app, ...options)
    } else if (isFunction(plugin)) {
        // 判断plugin是否为函数模式
        installedPlugins.add(plugin)
        plugin(app, ...options)
    } else if (__DEV__) {
        warn(
            `A plugin must either be a function or an object with an "install" ` +
            `function.`
        )
    }
    // 返回一个app,则可以进行链式的添加插件,例如:app.use(store).use(router).use(ElementUi)
    return app
},

Released under the MIT License.