Skip to content

Vue3定义全局函数和变量

globalProperties

由于Vue3 没有 Prototype 属性,使用 app.config.globalProperties 代替,然后去定义变量和函数

Vue2

js
// 之前 (Vue 2.x)
Vue.prototype.$http = () => {
}

Vue3

ts
// 之后 (Vue 3.x)
const app = createApp({})
app.config.globalProperties.$http = () => {
}

过滤器

在Vue3 移除了

我们正好可以使用全局函数代替Filters

案例: main.ts

ts

app.config.globalProperties.$filters = {
  format<T extends any>(str: T): string {
    return `$${str}`
  }
}

app.config.globalProperties.$env = 'dev'
type Filter = {
  format<T>(str: T): string
}

// 声明要扩充@vue/runtime-core包的声明.
// 这里扩充"ComponentCustomProperties"接口, 因为他是vue3中实例的属性的类型.
declare module '@vue/runtime-core' {
  export interface ComponentCustomProperties {
    $filters: Filter,
    $env: string
  }
}

setup中使用

vue

<script>
import {getCurrentInstance} from "vue";

const app = getCurrentInstance()
console.log(app?.proxy?.$env)
</script>

编写Vue3插件

插件

插件是自包含的代码,通常向 Vue 添加全局级功能。 你如果是一个对象需要有 install 方法, Vue 会帮你自动注入到 install 方法 你如果是function 就直接当install 方法去使用

使用插件

在使用 createApp() 初始化 Vue 应用程序后,你可以通过调用 use() 方法将插件添加到你的应用程序中。

实现一个Loading

  • src/components/loading/Loading.vue
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>
  • src/components/loading/index.ts
ts
import {App, createVNode, render, VNode} from "vue";
import Loading from './index.vue'
// 需要将Loading转成vNode 挂载
// 可以导出对象或者函数(导出对象,必须得有install函数)
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()
    }
    // app.config.globalProperties.$_loading.show()
  }
}
  • src/main.ts
ts
import {createApp} from 'vue'
// @ts-ignore
import App from './App.vue'

import Loading from "./components/loading/index.ts";
// createApp(App).mount('#app')
const app = createApp(App)
app.use(Loading)
type Load = {
  show: () => void
  hide: () => void
}

//编写ts loading 声明文件放置报错 和 智能提示
declare module '@vue/runtime-core' {
  export interface ComponentCustomProperties {
    $_loading: Load
  }
}

app.mount('#app')
  • 调用插件
vue

<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 源码手写

在 src/main.ts 中注册,需要使用 app.use()

ts

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)
  }
}