一、首先什么是插件
插件 (Plugins
) 是一种能为 Vue
添加全局功能的工具代码。
主要应用于以下四个方面
1、通过 app.component()
和 app.directive()
注册一到多个全局组件或自定义指令。
2、通过 app.provide()
使一个资源可被注入进整个应用。
3、向 app.config.globalProperties
中添加一些全局实例属性或方法
4、一个可能上述三种都包含了的功能库 (例如 vue-router
)。
二、插件的书写形式
一个插件可以是一个拥有 install()
方法的对象,也可以直接是一个安装函数本身。安装函数会接收到安装它的应用实例和传递给 app.use()
的额外选项作为参数
比如:
export default {install(app, config) {// app 实例}
}
1、通过 app.component()
注册全局组件
// myConfirm/index.ts
文件
编写myConfirm 插件,通过install() 注册插件主要调用的方法
import { createVNode, App, AppContext } from 'vue'
import myConfirm from './index.vue'
export default {install(app:App, config:AppContext) {const vnode = createVNode(myConfirm)console.log('=confirm==vnode=', vnode, config)app.component('myConfirm', myConfirm)}
}
// plugins/myConfirm/index.vue
文件
与普通组件一样
<template><div class="my-confrim-container" v-if="isShowConfirm"><div class="my-confirm-main"><div class="my-confrim-title"><span v-if="isShowDefaultTitle">{{ title }}</span><slot name="title"></slot></div><div class="my-confrim-content">{{ content }}<slot name="content"></slot></div><div class="my-confrim-footer"><button class="btn" @click="handleCancle">取消</button><button type="primary" class="btn" @click="handleConfirm">确认</button><slot name="footer"></slot></div></div></div>
</template>
<script setup lang="ts">
interface Prop {isShowConfirm: boolean,isShowDefaultTitle?: boolean,title?: string,content?: string
}
const props = withDefaults(defineProps<Prop>(), {isShowConfirm: false,isShowDefaultTitle: true,title: '提示',content: '请确认是否进行此操作!'
})
const emits = defineEmits<{(e: 'cancel'): void,(e: 'confirm'):void
}>()
const handleCancle = () => {emits('cancel')
}
const handleConfirm = () => {console.log('00=confirm=')emits('confirm')
}
</script><style lang="scss" scoped>
.my-confrim-container{position: fixed;top: 0;left: 0;width: 100%;height: 100%;background: rgba(0,0,0,.5);z-index: 9999;display: flex;justify-content: center;align-items: center;
}
.my-confirm-main{width: 460px;height: auto;background: #fff;border-radius: 2px;box-shadow: 0px 4px 12px 4px rgba(0,0,0,0.16);}
.my-confrim-title{height: 46px;border-bottom: 1px solid #efefef;// line-height:46px;box-sizing: border-box;display: flex;align-items: center;justify-content: center;
}
.my-confrim-content{height: 200px;width: 100%;box-sizing: border-box;padding:12px 16px;display: flex;align-items: center;justify-content: flex-start;
}
.my-confrim-footer{height: 46px;width:100%;display:flex;justify-content: flex-end;align-items:center;border-top:1px solid #efefef;box-sizing: border-box;padding:0 12px;.btn{width: auto;height: 32px;line-height:32px;padding:0 20px;font-size:12px;color: #333;background-color:#fff;border:1px solid #efefef;margin-left:12px;cursor: pointer;&[type="primary"]{background: #1890ff;color: #fff;border-color: #1890ff;}}
}
</style>
// 在 main.ts
中
若要全局使用 myConfirm
组件,需要通过app.use()
,使用改插件,此时会自动执行 插件中的install()
方法
import { createApp } from 'vue'
import myConfirm from './plugins/myConfirm/index'
const app = createApp(App)
app.use(myConfirm)
并且 Vue.use
会自动阻止注册相同插件多次,届时只会注册一次该插件。
使用:
<template><div class="my-plugin">This is a demo of the plugin<my-confirm :isShowConfirm="isShowConfirm"@cancel="handleCancle"@confirm="handleConfrim"/><hr/><el-button @click="isShowConfirm = true">open confirm</el-button></div>
</template><script setup>
import { ref, onActivated, inject, getCurrentInstance } from "vue"// 以插件形式组成全局组件
const isShowConfirm = ref(false)
const handleCancle = () => {console.log('==handleCancle==')isShowConfirm.value = false
}
const handleConfrim = () => {const myPromise = new Promise((reslove, reject) => {setTimeout(() => {reslove("成功");}, 300);})console.log('===myPromise==', myPromise)myPromise.then(res => {console.log('===res==', res)isShowConfirm.value = false}).catch(err => {console.log('===err==', err)})
}
</script>
效果如图:
2、通过 app.provide()
使一个资源可被注入进整个应用
// 编写一个全局loading
// plugins/loading/loading.js
文件
import { createVNode, render, provide } from 'vue'
import myLoading from './loading.vue';
export default {install(app, options) {// appconsole.log('加载插件', app)// 使用 createVNode 创建虚拟DOMconst vnode = createVNode(myLoading)console.log('=vnode==', vnode)// 虚拟DOM 渲染至 body下面render(vnode, document.body)const $myLoading = {hidden: () => {vnode?.component?.exposed?.hidden()},show: () => {vnode?.component?.exposed?.show()}}// 由于 vue3 中不建议这种直接挂在全局写法,可以使用依赖注入替代app.config.globalProperties.$myLoading = $myLoadingapp.provide('$myLoading', $myLoading)}
}
// plugins/loading/loading.vue
文件
<template><div class="my-loading" v-if="isShowLoading">loading……</div>
</template>
<script setup>
import { ref } from "vue"
const isShowLoading = ref(false)
const hidden = () => {console.log('===hidden==')isShowLoading.value = false
}
const show = () => {console.log('===show==')isShowLoading.value = true
}
// 通过 defineExpose子组件暴露出属性 方法
defineExpose({show,hidden,isShowLoading
})
</script>
<style lang="scss" scoped>
.my-loading{position:fixed;top:0;left:0;width: 100%;height:100%;background-color: rgba(0,0,0,0.5);font-size: 14px;color: #fff;text-align: center;display: flex;align-items: center;justify-content: center;
}
</style>
同样使用 app.use()
挂载
main.ts
文件中
import { createApp } from 'vue'
const app = createApp(App)
app.use(myLoading)
使用的时候
inject()
对应的是 provide()
getCurrentInstance()
对应的是获取 app.config.globalProperties
中的方法
因:getCurrentInstance()
在 vue 3.3X
以上属于内置方法,所以建议使用依赖注入方案;
<template><div class="my-plugin">This is a demo of the plugin<my-confirm :isShowConfirm="isShowConfirm"@cancel="handleCancle"@confirm="handleConfrim"/><hr/><el-button @click="isShowConfirm = true">open confirm</el-button></div>
</template><script setup>
import { ref, onActivated, inject, getCurrentInstance } from "vue"
// 注册在 body 中组件方法
let $myLoading = inject('$myLoading')
console.log('===', $myLoading)
// 获取
// const conext = getCurrentInstance().appContext.config.globalProperties
// console.log('==conext==', conext)
$myLoading.show()
setTimeout(() => {$myLoading.hidden()
}, 3500)</script>