vue3学习教程第三十六节(自定义插件)

一、首先什么是插件

插件 (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) {
        // 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 文件

<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>
  • 7
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

刺客-Andy

努力将爱好变成更有价值的事物

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值