Vue学习记录之十六 自定义Vue插件

时间:2024-10-21 10:13:39

一、创建目录

在components的Loading文件夹下建立 index.ts 和 index.vue两个文件。ts文件是一个 TypeScript 文件,通常用于编写逻辑、功能模块或导出一些工具函数、类、接口等。

二、编写插件内容

index.ts

/*
支持两种格式:
1、是对象形式: 对象形式必须包含一个install函数。他会回传一个app,这个app就是我们main.ts中的app
2、是函数形式
*/
import type {App,VNode} from 'vue'
import Loading from './index.vue' //引入自定义插件
import { createVNode,render } from 'vue'  //将内容转化为vnode格式,方便阅读
export default{
    install(app:App){
        const Vnode:VNode = createVNode(Loading)
        render(Vnode,document.body)  //挂载,第一个是挂载的内容,第二个是挂载点(因为是全局的,我们挂载到document.body上)
        //通过Vnode.component?.exposed 读取插件中的属性和方法
        //设置为全局变量
        app.config.globalProperties.$loading={
            show: Vnode.component?.exposed?.show,
            hide: Vnode.component?.exposed?.hide,
        }
        //调用,下面操作会在每个页面上都显示show().
        //app.config.globalProperties.$loading.show()
        //console.log(app,123,Vnode.component?.exposed)
    }
}

index.vue

<template>
    <div v-if="isShow" class="loading">
      Loading...
    </div>
</template>
<script setup lang='ts'>
import { ref,reactive } from 'vue'
const isShow = ref<boolean>(false)

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

//函数和方法都必须放在defineExpose,否则挂载的时候无法读取到。
defineExpose({
    show,
    hide,
    isShow
})
</script>
<style scoped>
.loading{
  background: black;
  opacity: 0.8;
  font-size: 30px;
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100vh;
  color: white;
}
</style>

三、在main.ts文件中引入和注册

//import './assets/main.css'

import { createApp } from 'vue'
import { createPinia } from 'pinia'

import App from './App.vue'
import router from './router'
/*
1、导入插件
./components/Loading
优先引入index.ts,如果没有index.ts,那么就会自动寻找index.vue
同时存在 index.ts 和 index.vue,则通常会优先解析 index.ts,除非项目配置中有特殊的解析规则。
*/
import Loading from './components/Loading'
const app = createApp(App)
//2、注册插件。只要是vue的插件,都必须通过这个方法注册
app.use(Loading) 
app.use(createPinia())
app.use(router)
app.mount('#app')

四、使用

在要使用的页面先获取实例

<template>
    <div>我是主页面</div>
</template>
<script setup lang='ts'>
import { ref,reactive,getCurrentInstance } from 'vue'
//获取实例
const instance = getCurrentInstance()
//获取实例中自定义插件(可以正常使用,但是报错,可以在main.ts中做类型声明。)
instance?.proxy?.$loading.show()
setTimeout(()=>{
  instance?.proxy?.$loading.hide()  //5秒钟之后关闭
},5000)
</script>
<style scoped>
</style>

在main.ts中 做类型声明,阻止报错。

//import './assets/main.css'

import { createApp } from 'vue'
import { createPinia } from 'pinia'

import App from './App.vue'
import router from './router'

import Loading from './components/Loading'
const app = createApp(App)
app.use(Loading) 
//做类型声明
/*
在 Vue 3 中,如果你只是想对组件实例或全局属性进行扩展,
建议使用 declare module '@vue/runtime-core',因为它更符合 Vue 3 的内部结构。
如果没有安装会报错,可以使用pnpm install @vue/runtime-core @types/node。进行安装。
如果你需要扩展 Vue 整体的公共 API(如 Vue 全局属性),
可以使用 declare module 'vue'。
有时候,二者可以随便选择使用。
*/
type Lod ={
    show: () => void,
    hide: () => void
}
declare module '@vue/runtime-core'{
    export interface ComponetCustomProperties {
        $loading:Lod
    }
}

app.use(createPinia())
app.use(router)
app.mount('#app')