#EO羿欧值不值得买#
为什么需要全局变量?
在深入方法之前,我们先明确一下,什么情况下你需要思考使用全局变量。
- 用户登录状态:用户是否登录、用户ID、用户名、头像等信息,几乎每个页面都可能用到。
- 应用主题配置:列如当前是亮色模式还是暗色模式,这个设置会影响整个应用的样式。
- 全局的加载状态:在发起网络请求时,你可能希望在全应用范围显示一个加载动画。
- 一些不变的配置信息:列如后端的API基础地址、应用的版本号、第三方服务的Key等。
- 需要在多个无关联组件间共享的数据:两个组件既不是父子关系,也不是兄弟关系,但需要同步数据。
如果你的项目里有上面这些需求,那么设置全局变量就是一个好选择。
使用 app.config.globalProperties
这是Vue3官方提供的一种方式,超级直接。你可以把任何变量或方法挂载到Vue应用的全局实例上,这样在任何组件里都能通过 this 来访问。
怎么用?
假设我们在 main.js 或 main.ts 文件里创建Vue应用。
// main.js
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)
// 定义你想全局使用的变量或方法
const globalData = {
apiBaseUrl: 'https://api.yoursite.com/v1',
siteName: '我的Vue应用',
showToast(message) {
// 假设这里有一个显示提示框的逻辑
console.log('Toast:', message)
}
}
// 将它们挂载到 app.config.globalProperties 上
app.config.globalProperties.$global = globalData
app.mount('#app')
这样设置之后,在你的组件模板和 <script setup> 以外的选项式API中,就可以这样用了:
<template>
<div>
<h1>欢迎来到 {{ $global.siteName }}</h1>
<button @click="fetchData">获取数据</button>
</div>
</template>
<script>
export default {
methods: {
fetchData() {
// 使用全局的api地址
const url = this.$global.apiBaseUrl + '/user'
console.log('请求地址:', url)
// 调用全局方法
this.$global.showToast('开始获取数据')
}
}
}
</script>
需要注意的地方
- 类型支持:如果你用TypeScript,需要扩展全局类型声明,不然 $global 会报错。你可以在项目根目录的 env.d.ts 或 shims-vue.d.ts 文件里添加:
- declare module '@vue/runtime-core' {
interface ComponentCustomProperties {
$global: {
apiBaseUrl: string;
siteName: string;
showToast: (msg: string) => void;
}
}
} - Composition API 中的使用:在 <script setup> 语法糖里,没有 this。你需要用 getCurrentInstance 来获取:
- <script setup>
import { getCurrentInstance } from 'vue'const instance = getCurrentInstance()
const globalData = instance?.appContext.config.globalProperties.$globalconst handleClick = () => {
globalData?.showToast('来自setup的消息')
}
</script> - 看起来有点麻烦,对吧?所以这种方法更推荐在选项式API或模板中直接使用。
优点:设置简单,符合Vue2升级用户的习惯(类似 Vue.prototype)。 缺点:在Composition API中使用不太方便,类型声明需要额外处理。
使用“依赖注入”(Provide / Inject)
这是Vue3更推荐的一种方式,尤其适合Composition API。它的思想是,在应用顶层“提供”数据,在任何深层的子组件里都可以“注入”并使用这些数据。
怎么用?
我们还是在 main.js 里,用 app.provide 来提供全局数据。
// main.js
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)
// 准备全局数据
const globalData = {
apiBaseUrl: 'https://api.yoursite.com/v1',
siteName: '我的Vue应用',
}
// 使用 app.provide 提供出去
// 第一个参数是“钥匙”(key),第二个参数是“值”(value)
app.provide('globalData', globalData)
app.mount('#app')
然后,在任何子组件里,你都可以用 inject 来获取这个数据。
<!-- 某个深层子组件 ChildComponent.vue -->
<template>
<div>
<p>网站名称:{{ siteName }}</p>
<button @click="testApi">测试API地址</button>
</div>
</template>
<script setup>
import { inject } from 'vue'
// 使用 inject 注入,参数就是之前提供的 key
const globalData = inject('globalData')
// 目前你可以使用 globalData 了
const siteName = globalData.siteName
const testApi = () => {
console.log('API基础地址是:', globalData.apiBaseUrl)
}
</script>
它的好处
- 响应性:如果你提供的是一个 ref 或 reactive 创建的响应式数据,那么注入的地方也会是响应式的。一处修改,所有注入的地方都会更新。
- 更清晰的依赖关系:组件明确声明了它需要注入什么数据,依赖关系一目了然。
- 超级适合Composition API:和 setup 函数结合得天衣无缝。
一个响应式的例子
让全局数据变成响应式的,这样所有组件都能同步更新。
// main.js
import { createApp, reactive } from 'vue'
import App from './App.vue'
const app = createApp(App)
// 使用 reactive 创建响应式全局对象
const globalState = reactive({
user: {
name: '访客',
isLogin: false
},
theme: 'light'
})
// 提供一个修改用户登录状态的方法
function login(userInfo) {
globalState.user.name = userInfo.name
globalState.user.isLogin = true
}
// 可以同时提供多个
app.provide('globalState', globalState)
app.provide('login', login)
app.mount('#app')
在组件中使用:
<script setup>
import { inject } from 'vue'
const globalState = inject('globalState')
const login = inject('login')
const handleLogin = () => {
// 调用全局方法,修改全局状态
login({ name: '张三' })
// 此时,所有注入了 globalState 的组件,都会看到 user.name 变成了'张三'
}
</script>
<template>
<div>当前用户:{{ globalState.user.name }}</div>
<button @click="handleLogin">登录</button>
</template>
优点:响应式支持好,是Vue3的官方推荐模式,与Composition API集成度高。 缺点:需要稍微理解“提供”和“注入”的概念。数据流向依然是自上而下的,不适合跨越多层“兄弟组件”的通信。
使用“状态管理”(Pinia)
在Vue3的生态里,Pinia 是官方推荐的状态管理库,它比之前的Vuex更简单、更强劲,也完美支持TypeScript。
你可以把Pinia理解为一个专业的、响应式的“全局变量仓库”。
怎么用?
第一,安装Pinia。
npm install pinia
然后,在 main.js 中创建Pinia实例并挂载到Vue应用上。
// main.js
import { createApp } from 'vue'
import { createPinia } from 'pinia' // 导入createPinia
import App from './App.vue'
const app = createApp(App)
const pinia = createPinia() // 创建Pinia实例
app.use(pinia) // 使用Pinia
app.mount('#app')
接下来,我们定义一个“仓库”(Store)。我们在 src/stores 目录下创建一个 global.js(或 global.ts)。
// src/stores/global.js
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
// defineStore 定义仓库,第一个参数是仓库的唯一ID
export const useGlobalStore = defineStore('global', () => {
// 状态 - 相当于你的全局变量
const siteName = ref('我的Vue应用')
const apiBaseUrl = ref('https://api.yoursite.com/v1')
const user = ref({ name: '访客', isLogin: false })
const theme = ref('light')
// 计算属性 - 基于状态衍生出的值
const welcomeMessage = computed(() => {
return user.value.isLogin ? `欢迎回来,${user.value.name}` : '请先登录'
})
// 动作 - 修改状态的方法
function login(userInfo) {
user.value.name = userInfo.name
user.value.isLogin = true
// 这里一般还会做一些异步操作,列如调用登录接口
}
function logout() {
user.value.name = '访客'
user.value.isLogin = false
}
function toggleTheme() {
theme.value = theme.value === 'light' ? 'dark' : 'light'
}
// 最后,返回所有需要在组件中使用的东西
return {
siteName,
apiBaseUrl,
user,
theme,
welcomeMessage,
login,
logout,
toggleTheme
}
})
目前,你可以在任何组件中使用这个仓库了。
<!-- 任意组件 -->
<template>
<div :class="`app-${globalStore.theme}`">
<h1>{{ globalStore.siteName }}</h1>
<p>{{ globalStore.welcomeMessage }}</p>
<button @click="handleLogin">登录</button>
<button @click="globalStore.toggleTheme">切换主题</button>
</div>
</template>
<script setup>
// 导入仓库定义函数,并执行它,得到仓库实例
import { useGlobalStore } from '@/stores/global'
const globalStore = useGlobalStore()
const handleLogin = () => {
globalStore.login({ name: '李四' })
}
</script>
Pinia的优势
- 类型安全:TypeScript支持超级好,所有状态和方法都有完整的类型推断。
- 模块化:你可以定义多个不同的仓库(列如用户仓库、商品仓库、设置仓库),而不是把所有东西堆在一个全局对象里。
- 开发工具支持:有Vue Devtools的专门插件,可以方便地跟踪状态变化和时间旅行调试。
- 灵活的:可以在组件、甚至其他仓库中自由使用。
- 服务端渲染友善:对SSR有很好的支持。
优点:功能强劲,适合管理复杂、大型的全局状态,是Vue3现代项目的标配。 缺点:需要额外学习一个库的概念,对于超级简单的全局变量来说有点“杀鸡用牛刀”。
使用纯粹的JavaScript模块
有时候,你的全局变量超级简单,可能只是一些配置常量,或者一些纯工具函数。它们不需要响应式,也不会改变。这种情况下,一个最简单的ES模块就足够了。
怎么用?
创建一个 .js 或 .ts 文件,导出你的常量或函数。
// src/config/constants.js
export const API_BASE_URL = 'https://api.yoursite.com/v1'
export const SITE_NAME = '我的Vue应用'
export const APP_VERSION = '1.0.0'
export const MAX_UPLOAD_SIZE = 5 * 1024 * 1024 // 5MB
// 一些纯函数
export function formatDate(date) {
// 格式化日期的逻辑
return new Date(date).toLocaleDateString()
}
然后在任何需要的地方导入使用。
<script setup>
// 直接导入即可
import { API_BASE_URL, SITE_NAME, formatDate } from '@/config/constants'
console.log(`正在访问 ${SITE_NAME},API地址:${API_BASE_URL}`)
const today = formatDate(new Date())
</script>
什么时候用?
- 应用发布后就不会改变的配置项。
- 纯工具函数库(列如日期处理、字符串格式化、数学计算等)。
- 第三方服务的静态配置。
优点:极其简单,零依赖,性能最好,Tree-shaking友善(没用到的常量不会被打包进去)。 缺点:不是响应式的,不能用来存储会变化的应用状态。
希望这篇文章能帮你理清在Vue3中设置全局变量的思路。不同的场景选择不同的工具,才能写出更清晰、更易维护的代码。





