一、首先什么是插件
插件 (Plugins
) 是一种能为 Vue
添加全局功能的工具代码。
主要应用于以下四个方面 1 、通过 app.component()
和 app.directive()
注册一到多个全局组件或自定义指令。 2 、通过 app.provide()
使一个资源可被注入进整个应用。 3 、向 app.config.globalProperties
中添加一些全局实例属性或方法 4 、一个可能上述三种都包含了的功能库 (例如 vue-router
)。
二、插件的书写形式
一个插件可以是一个拥有 install()
方法的对象,也可以直接是一个安装函数本身。安装函数会接收到安装它的应用实例和传递给 app.use()
的额外选项作为参数
比如:
javascript
export default {
install(app, config) {
// app 实例
}
}
1、通过 app.component()
注册全局组件
// myConfirm/index.ts
文件 编写myConfirm 插件,通过install() 注册插件主要调用的方法
javascript
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
文件 与普通组件一样
xml
<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()
方法
javascript
import { createApp } from 'vue'
import myConfirm from './plugins/myConfirm/index'
const app = createApp(App)
app.use(myConfirm)
并且 Vue.use
会自动阻止注册相同插件多次,届时只会注册一次该插件。 使用:
xml
<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
文件
javascript
import { createVNode, render, provide } from 'vue'
import myLoading from './loading.vue';
export default {
install(app, options) {
// app
console.log('加载插件', app)
// 使用 createVNode 创建虚拟DOM
const 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 = $myLoading
app.provide('$myLoading', $myLoading)
}
}
// plugins/loading/loading.vue
文件
xml
<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
文件中
javascript
import { createApp } from 'vue'
const app = createApp(App)
app.use(myLoading)
使用的时候 inject()
对应的是 provide()
getCurrentInstance()
对应的是获取 app.config.globalProperties
中的方法 因:getCurrentInstance()
在 vue 3.3X
以上属于内置 方法,所以建议使用依赖注入方案;
xml
<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>