手把手教您编写一个简单的vue3插件
插件是自包含的代码,通常向 Vue 添加全局级功能。你如果是一个对象需要有install方法Vue会帮你自动注入到install 方法 你如果是function 就直接当install 方法去使用.并在文件夹中新建.vue组件和一个index.js文件.vue文件作为自定义插件.组件就是把图形非图形的各种逻辑均抽象为一个统一的概念(组件)来实现开发的模式,在Vue中每一个.vue文件都可以视为一个
插件
插件 (Plugins) 是一种能为 Vue 添加全局功能的工具代码。下面是如何安装一个插件的示例:
import { createApp } from 'vue'
const app = createApp({})
app.use(myPlugin, {
/* 可选的选项 */
})
一个插件可以是一个拥有 install() 方法的对象,也可以直接是一个安装函数本身。安装函数会接收到安装它的应用实例和传递给 app.use() 的额外选项作为参数:
const myPlugin = {
install(app, options) {
// 配置此应用
}
}
插件没有严格定义的使用范围,但是插件发挥作用的常见场景主要包括以下几种:
- 通过
app.component()和app.directive()注册一到多个全局组件或自定义指令。 - 通过
app.provide()使一个资源可被注入进整个应用。 - 向
app.config.globalProperties中添加一些全局实例属性或方法
一个可能上述三种都包含了的功能库 (例如 vue-router)。
编写一个插件
为了更好地理解如何构建 Vue.js 插件,我们可以试着写一个简单的 i18n (国际化 (Internationalization) 的缩写) 插件。
让我们从设置插件对象开始。建议在一个单独的文件中创建并导出它,以保证更好地管理逻辑,如下所示:
// plugins/i18n.js
export default {
install: (app, options) => {
// 在这里编写插件代码
}
}
我们希望有一个翻译函数,这个函数接收一个以 . 作为分隔符的 key 字符串,用来在用户提供的翻译字典中查找对应语言的文本。期望的使用方式如下:
<h1>{{ $translate('greetings.hello') }}</h1>
这个函数应当能够在任意模板中被全局调用。这一点可以通过在插件中将它添加到 app.config.globalProperties 上来实现:
// plugins/i18n.js
export default {
install: (app, options) => {
// 注入一个全局可用的 $translate() 方法
app.config.globalProperties.$translate = (key) => {
// 获取 `options` 对象的深层属性
// 使用 `key` 作为索引
return key.split('.').reduce((o, i) => {
if (o) return o[i]
}, options)
}
}
}
我们的 $translate 函数会接收一个例如 greetings.hello 的字符串,在用户提供的翻译字典中查找,并返回翻译得到的值。
用于查找的翻译字典对象则应当在插件被安装时作为 app.use() 的额外参数被传入:
import i18nPlugin from './plugins/i18n'
app.use(i18nPlugin, {
greetings: {
hello: 'Bonjour!'
}
})
这样,我们一开始的表达式 $translate(‘greetings.hello’) 就会在运行时被替换为 Bonjour! 了。
ypeScript 用户请参考:扩展全局属性
TIP
请谨慎使用全局属性,如果在整个应用中使用不同插件注入的太多全局属性,很容易让应用变得难以理解和维护。
插件中的 Provide / Inject#
在插件中,我们可以通过 provide 来为插件用户供给一些内容。举例来说,我们可以将插件接收到的 options 参数提供给整个应用,让任何组件都能使用这个翻译字典对象。
// plugins/i18n.js
export default {
install: (app, options) => {
app.config.globalProperties.$translate = (key) => {
return key.split('.').reduce((o, i) => {
if (o) return o[i]
}, options)
}
app.provide('i18n', options)
}
}
现在,插件用户就可以在他们的组件中以 i18n 为 key 注入并访问插件的选项对象了。
<script setup>
import { inject } from 'vue'
const i18n = inject('i18n')
console.log(i18n.greetings.hello)
</script>
详细介绍
插件是自包含的代码,通常向 Vue 添加全局级功能。你如果是一个对象需要有install方法Vue会帮你自动注入到install 方法 你如果是function 就直接当install 方法去使用.
使用插件
在使用 createApp() 初始化 Vue 应用程序后,你可以通过调用 use() 方法将插件添加到你的应用程序中。
实现一个Loading
Loading.Vue
<template>
<div v-if="isShow" class="loading">
<div class="loading-content">Loading...</div>
</div>
</template>
<script setup lang='ts'>
import { ref } from 'vue';
const isShow = ref(false)//定位loading 的开关
const show = () => {
isShow.value = true
}
const hide = () => {
isShow.value = false
}
//对外暴露 当前组件的属性和方法
defineExpose({
isShow,
show,
hide
})
</script>
<style scoped lang="less">
.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>
Loading.ts
import { createVNode, render, VNode, App } from 'vue';
import Loading from './index.vue'
export default {
install(app: App) {
//createVNode vue提供的底层方法 可以给我们组件创建一个虚拟DOM 也就是Vnode
const vnode: VNode = createVNode(Loading)
//render 把我们的Vnode 生成真实DOM 并且挂载到指定节点
render(vnode, document.body)
// Vue 提供的全局配置 可以自定义
app.config.globalProperties.$loading = {
show: () => vnode.component?.exposed?.show(),
hide: () => vnode.component?.exposed?.hide()
}
}
}
Main.ts
import Loading from './components/loading'
let app = createApp(App)
app.use(Loading)
type Lod = {
show: () => void,
hide: () => void
}
//编写ts loading 声明文件放置报错 和 智能提示
declare module '@vue/runtime-core' {
export interface ComponentCustomProperties {
$loading: Lod
}
}
app.mount('#app')
使用方法
<template>
<div></div>
</template>
<script setup lang='ts'>
import { ref,reactive,getCurrentInstance} from 'vue'
const instance = getCurrentInstance()
instance?.proxy?.$Loading.show()
setTimeout(()=>{
instance?.proxy?.$Loading.hide()
},5000)
// console.log(instance)
</script>
<style>
*{
padding: 0;
margin: 0;
}
</style>
Vue use 源码手写
import type { App } from 'vue'
import { app } from './main'
interface Use {
install: (app: App, ...options: any[]) => void
}
const installedList = new Set()
export function MyUse<T extends Use>(plugin: T, ...options: any[]) {
if(installedList.has(plugin)){
return console.warn('重复添加插件',plugin)
} else {
plugin.install(app, ...options)
installedList.add(plugin)
}
}
封装一个弹出框插件
它的效果是这样的:

第一步:在项目中创建存放自定义插件的文件夹

并在文件夹中新建 .vue组件和一个index.js文件,.vue文件作为自定义插件.
第二步:在index.js文件中编写下面的代码
// 自写插件
import Toast from './Toast'
import { createApp } from 'vue'
const obj = {}
// 当main.js执行到.use(toast)代码(安装插件)时,会执行obj的install函数
obj.install = (app) => {
/* Vue3的自定义插件 */
// 1.实例化并绑定组件
const toastConstructor = createApp(Toast);
const instance = toastConstructor.mount(document.createElement('div'));
// 2.将挂载的Node添加到body中
document.body.appendChild(instance.$el);
// 3.定义全局($toast即是此插件的名称)
app.config.globalProperties.$toast = instance;
}
export default obj
Toast.vue文件中的代码:
<template>
<div>
<div class="toast" v-show="isShow">
<p>{{ message }}</p>
</div>
</div>
</template>
<script setup>
const message = ref('')
const isShow = ref(false)
const show = (message = '默认文本', duration = 1000) => {
message.value = message
isShow.value = true
// 指定时间后弹框消失
setTimeout(() => {
isShow.value = false;
}, duration);
}
</script>
<style lang="less" scoped>
.toast {
position: fixed;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 140px;
height: 40px;
background-color: black;
opacity: .7;
border-radius: 4px;
text-align: center;
line-height: 40px;
color: white;
z-index: 100;
}
</style>
第三步:在项目的main.js文件中安装此插件
import showToast from './components/Toast'
app.use(showToast)
提示:当Vue执行到use(toast)时,会跳转到index.js中执行obj对象的install函数,在此函数里就可以做声明插件的操作了。
第四步:使用插件
装得有多狼狈,使用起来就有多舒服。这里我们使用插件只需要一句代码即可。
this.$toast.show('添加到购物车成功',1500); // 此步有待商榷
Vue中的插件和组件究竟有什么区别?
一、组件
定义:
组件就是把图形、非图形的各种逻辑均抽象为一个统一的概念(组件)来实现开发的模式,在Vue中每一个.vue文件都可以视为一个组件。
组件的优势:
降低整个系统的耦合度,在保持接口不变的情况下,我们可以替换不同的组件快速完成需求,例如输入框,可以替换为日历、时间、范围等组件作具体的实现调试方便,由于整个系统是通过组件组合起来的,在出现问题的时候,可以用排除法直接移除组件,或者根据报错的组件快速定位问题,之所以能够快速定位,是因为每个组件之间低耦合,职责单一,所以逻辑会比分析整个系统要简单提高可维护性,由于每个组件的职责单一,并且组件在系统中是被复用的,所以对代码进行优化可获得系统的整体升级
二、插件
插件通常用来为 Vue 添加全局功能。插件的功能范围没有严格的限制——一般有下面几种:
添加全局方法或者属性。如: vue-custom-element添加全局资源:指令/过滤器/过渡等。如 vue-touch通过全局混入来添加一些组件选项。如vue-router添加 Vue 实例方法,通过把它们添加到 Vue.prototype 上实现。一个库,提供自己的 API,同时提供上面提到的一个或多个功能。如vue-router
三、两者的区别
两者的区别主要表现在以下几个方面:
编写形式注册形式使用场景
编写形式
编写组件
编写一个组件,可以有很多方式,我们最常见的就是vue单文件的这种格式,每一个.vue文件我们都可以看成是一个组件
<template>
<div>
</div>
</template>
<script setup lang="ts">
</script>
<style scoped>
</style>
也可以这样注册成全局组件
import { createApp } from 'vue'
import App from './App.vue'
export const app = createApp(App)
import CardVue from './components/Card/index.vue'
app.component('Card', CardVue)
app.mount('#app')
编写插件
ue插件的实现应该暴露一个 install 方法。这个方法的第一个参数是 Vue 构造器,第二个参数是一个可选的选项对象
对象类型编写插件
export default {
install(app, options){
console.log('对象类型编写插件',app, options)
app.config.globalProperties.$name="code_lee" //增加全局属性的时候,约定俗成的命名习惯,在属性名前加$符号
}
}
函数类型编写插件
export default (app, options)=>{
console.log('函数类型编写插件',app, options)
}
注册形式
组件注册
vue组件注册主要分为全局注册与局部注册
局注册通过app.component方法,
- 第一个参数为组件的名称,
- 第二个参数为传入的配置项
import CardVue from './components/Card/index.vue'
app.component('Card', CardVue)
局部注册只需在用到的地方通过import一个组件
import layout from './loayout/index.vue'// 定义一个组件
插件注册
插件的注册通过app.use()的方式进行注册(安装),
- 第一个参数为插件的名字,
- 第二个参数是可选择的配置项
注意的是:app.use()会自动阻止多次注册相同插件,只会注册一次
使用场景
具体的其实在插件是什么章节已经表述了,这里在总结一下
- 组件 (Component) 是用来构成你的 App 的业务模块,它的目标是 App.vue
- 插件 (Plugin) 是用来增强你的技术栈的功能模块,它的目标是 Vue 本身
简单来说,插件就是指对Vue的功能的增强或补充
更多推荐


所有评论(0)