插件编写

插件需要暴露一个对象或函数,并通过app.use注册到全局,省略注册过程。

Loading/index.ts:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import type { App, VNode } from "vue"
import { createVNode,render } from "vue"
import Loading from "./index.vue"

// vue插件 支持对象形式和函数形式
// 对象形式内必须含有install函数
export default {
install(app: App) {
// 把组件实例转换成VNode
const VNode:VNode = createVNode(Loading)
// 手动给VNode挂载组件
render(VNode,document.body)
VNode.component?.exposed
// 把属性和方法放到全局
app.config.globalProperties.__loading = {
show: VNode.component?.exposed?.show,
hide: VNode.component?.exposed?.hide,
isShow: VNode.component?.exposed?.isShow
}
}
}

Loading/index.vue:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<template>
<div v-if="isShow" class="loading">
<div class="loading-content">Loading...</div>
</div>
</template>

<script setup lang="ts">
const isShow = ref<boolean>(false)

const show = ()=> isShow.value = true
const hide = ()=> isShow.value = false

defineExpose({show,hide,isShow})
</script>

<style scoped lang="scss">
.loading {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.8);
display: flex;
justify-content: center;
align-items: center;

&-content {
font-size: 30px;
color: #fff;
}
}
</style>

App.vue:

1
2
3
4
5
6
7
8
9
10
11
12
<template>
<div></div>
</template>

<script setup lang="ts">
const instance = getCurrentInstance()
instance?.proxy?.__loading.show()

setTimeout(() => {
instance?.proxy?.__loading.hide()
}, 5000)
</script>

源码

手写一个myUse:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import type { App } from "vue"
import { app } from "./main"

interface Use {
install:(app:App,...options:any[])=>void
}

// 缓存策略,防止重复添加
const installList = new Set()

export function MyUse<T extends Use>(plugin:T,...options:any[]) {
// 如果插件已经注册过了,报错
if(installList.has(plugin)) {
console.error("already regist!",plugin)
} else {
// use函数其实就是帮把app传给插件
plugin.install(app,...options)
// 添加到缓存
installList.add(plugin)
}
}

在Vue源码(/package/runtime-core/src/apiCreateApp.ts)中可以看到use的源码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 缓存机制
const installedPlugins = new Set()

// ......省略

use(plugin: Plugin, ...options: any[]) {
// 组件已经注册过了,报错
if (installedPlugins.has(plugin)) {
__DEV__ && warn(`Plugin has already been applied to target app.`)
// plugin是否有值,plugin.install是否是函数
} else if (plugin && isFunction(plugin.install)) {
// 添加到缓存并调用插件
installedPlugins.add(plugin)
plugin.install(app, ...options)
// plugin本身是否是函数
} else if (isFunction(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本身主要是方便做链式调用
return app
},