Vue 3源码深度解析之：`Vue`的`global properties`：`app.config.globalProperties`的内部实现。

admin
Fri, 22 Aug 2025 11:24:08 +0000
Vue, global, vue, 源码

呦，各位观众老爷，小的不才，今天就来跟大家聊聊 Vue 3 里头一个挺有意思但又容易被忽略的家伙：app.config.globalProperties。这家伙，可是个“全局变量供应商”，能让你在 Vue 组件里头，像拥有了哆啦A梦的口袋一样，随时随地掏出各种“道具”来用。咱们今天就来扒一扒它的老底，看看它到底是怎么工作的。 开场白：globalProperties的江湖地位 在 Vue 的世界里，组件是构建用户界面的基本砖块。但有时候，我们需要一些通用的东西，比如一个格式化日期的函数，或者一个跟服务器交互的 API 客户端，希望在所有组件里都能方便地使用。难道我们要每个组件都 import 一遍？那也太麻烦了吧！ 这时候，app.config.globalProperties 就闪亮登场了。它可以让你把这些通用的东西“注册”到 Vue 应用的全局，然后每个组件都能像访问自己的属性一样访问它们。简直是懒人必备，效率神器！ 第一幕：globalProperties 的使用方法 先来看看怎么用它。非常简单，只需要在创建 Vue 应用实例之后，修改 app.config.globalProp …

继续阅读“Vue 3源码深度解析之：`Vue`的`global properties`：`app.config.globalProperties`的内部实现。”

The post Vue 3源码深度解析之：`Vue`的`global properties`：`app.config.globalProperties`的内部实现。 first appeared on 智猿学院-前后端，数据库，人工智能，云计算等领域前沿技术讲座.

呦，各位观众老爷，小的不才，今天就来跟大家聊聊 Vue 3 里头一个挺有意思但又容易被忽略的家伙：app.config.globalProperties。这家伙，可是个“全局变量供应商”，能让你在 Vue 组件里头，像拥有了哆啦A梦的口袋一样，随时随地掏出各种“道具”来用。咱们今天就来扒一扒它的老底，看看它到底是怎么工作的。

开场白：globalProperties的江湖地位

在 Vue 的世界里，组件是构建用户界面的基本砖块。但有时候，我们需要一些通用的东西，比如一个格式化日期的函数，或者一个跟服务器交互的 API 客户端，希望在所有组件里都能方便地使用。难道我们要每个组件都 import 一遍？那也太麻烦了吧！

这时候，app.config.globalProperties 就闪亮登场了。它可以让你把这些通用的东西“注册”到 Vue 应用的全局，然后每个组件都能像访问自己的属性一样访问它们。简直是懒人必备，效率神器！

第一幕：globalProperties 的使用方法

先来看看怎么用它。非常简单，只需要在创建 Vue 应用实例之后，修改 app.config.globalProperties 对象即可。

import { createApp } from 'vue';
import App from './App.vue';

const app = createApp(App);

// 添加一个全局属性 $formatDate
app.config.globalProperties.$formatDate = (date) => {
  return new Date(date).toLocaleDateString();
};

// 添加一个全局属性 $apiClient
app.config.globalProperties.$apiClient = {
  get: (url) => fetch(url).then(res => res.json()),
  post: (url, data) => fetch(url, {
    method: 'POST',
    body: JSON.stringify(data),
    headers: { 'Content-Type': 'application/json' }
  }).then(res => res.json())
};

app.mount('#app');

这样，在任何 Vue 组件里，你都可以直接使用 $formatDate 和 $apiClient 了。



Today is: {{ $formatDate(today) }}
Fetch Data
Data: {{ data }}




import { ref } from 'vue';

export default {
  setup() {
    const today = new Date();
    const data = ref(null);

    const fetchData = async () => {
      data.value = await this.$apiClient.get('/api/data'); // 注意这里用 this
    };

    return {
      today,
      data,
      fetchData
    };
  }
};


第二幕：globalProperties 的实现原理 (源码分析)

好了，接下来是重头戏，我们来扒一扒 app.config.globalProperties 的实现原理。这部分需要深入 Vue 3 的源码，但别担心，我会尽量用通俗易懂的语言来解释。

首先，我们要找到 app.config.globalProperties 在哪里被定义和使用。 实际上，它是在 createApp 函数返回的 app 对象上定义的一个属性。

简化的 createApp 函数实现大致如下 (注意，这只是为了说明原理的简化版本，真正的源码要复杂得多)：

import { createComponentInstance, mountComponent } from './renderer'; // 简化后的渲染相关函数

export function createApp(rootComponent, rootProps = null) {
  const app = {
    config: {
      globalProperties: {}, // 关键点：在这里定义了 globalProperties
    },
    mount(rootContainer) {
      // 创建组件实例
      const instance = createComponentInstance(rootComponent, rootProps);

      // 设置全局属性到组件实例上 (关键逻辑)
      for (const key in app.config.globalProperties) {
        instance.appContext.config.globalProperties[key] = app.config.globalProperties[key];
      }

      // 挂载组件
      mountComponent(instance, rootContainer);
    },
  };

  return app;
}

从上面的代码可以看出，app.config.globalProperties 就是一个简单的 JavaScript 对象，用来存储全局属性。 关键在于 mount 函数内部的那段循环，它会将 app.config.globalProperties 里的所有属性，拷贝到组件实例的 appContext.config.globalProperties 上。

那么，组件实例的 appContext.config.globalProperties 又是怎么被组件访问到的呢？ 这就涉及到 Vue 的响应式系统和组件上下文。

在组件渲染的过程中，Vue 会创建一个 render 函数，这个函数会返回组件的虚拟 DOM (VNode)。 在 render 函数内部，可以通过 this 访问组件实例。

Vue 在处理 this 的时候，会做一些特殊处理，使得 this 可以访问到组件实例的各种属性，包括 appContext.config.globalProperties 里的全局属性。

更具体来说，Vue 会通过一个叫做 resolveAssets 的函数，来查找组件实例上的各种资源，包括组件、指令、过滤器等等。 而 resolveAssets 函数也会查找 appContext.config.globalProperties 里的全局属性。

简化的 resolveAssets 函数实现大致如下：

function resolveAssets(instance, type, name) {
  // 1. 先查找组件自身的选项
  const options = instance.type;
  if (options[type] && options[type][name]) {
    return options[type][name];
  }

  // 2. 如果组件自身没有，则查找 app.config.globalProperties
  const globalAssets = instance.appContext.config.globalProperties;
  if (globalAssets && globalAssets[name]) {
    return globalAssets[name];
  }

  // 3. 如果还没有找到，则查找全局的组件、指令等（例如 Vue.component）
  // ... (省略这部分逻辑)

  return undefined;
}

从上面的代码可以看出，resolveAssets 函数会先查找组件自身的选项，如果找不到，才会查找 appContext.config.globalProperties。 这也解释了为什么全局属性可以被组件访问到，但组件自身的属性优先级更高。

第三幕：globalProperties 的注意事项

虽然 globalProperties 很好用，但也有一些需要注意的地方：

1. 命名冲突： 尽量使用 $xxx 格式的命名，以避免和组件自身的属性冲突。这是 Vue 官方推荐的做法。

2. 过度使用： 不要把所有东西都放到 globalProperties 里。只应该放那些真正通用的、需要在多个组件里共享的东西。如果一个属性只在一个组件里使用，那就应该把它定义为组件自身的属性。

3. 响应式问题： globalProperties 里的属性默认不是响应式的。如果你需要让它们是响应式的，可以使用 reactive 或 ref 来创建。 举个例子：

import { createApp, reactive } from 'vue';
import App from './App.vue';

const app = createApp(App);

const state = reactive({
  count: 0
});

app.config.globalProperties.$state = state;

app.mount('#app');

然后在组件里，就可以像这样使用：



Count: {{ $state.count }}
Increment



4. TypeScript 类型提示： 如果你使用 TypeScript，需要手动声明全局属性的类型，才能获得正确的类型提示。 可以通过声明一个全局的 interface 来实现：

// vue.d.ts (或者你自己的类型声明文件)
import { ComponentCustomProperties } from 'vue';

declare module '@vue/runtime-core' {
  interface ComponentCustomProperties {
    $formatDate: (date: Date) => string;
    $apiClient: {
      get: (url: string) => Promise<any>;
      post: (url: string, data: any) => Promise<any>;
    };
    $state: {
      count: number;
    }
  }
}

export {};

总结：globalProperties 的优缺点

特性 | 优点 | 缺点
使用方式 | 简单易用，方便在所有组件中访问全局属性。 | 可能导致全局命名空间污染，容易产生命名冲突。
适用场景 | 适用于需要在多个组件中共享的通用函数、API 客户端、配置信息等。 | 不适合放置组件特定的属性，过度使用会导致代码难以维护。
响应式 | 默认不是响应式的，需要手动使用 reactive 或 ref 来创建响应式属性。 | 需要注意响应式更新的问题，避免不必要的性能开销。
TypeScript | 需要手动声明全局属性的类型，才能获得正确的类型提示。 | 类型声明比较繁琐，需要维护一个全局的类型声明文件。
性能 | 对性能的影响较小，但在组件初始化时会进行属性拷贝，如果全局属性过多，可能会略微增加初始化时间。 | 过多的全局属性可能会影响代码的可读性和可维护性。
代码组织 | 可以将一些通用的逻辑抽离到全局属性中，使组件代码更加简洁。 | 可能会导致代码依赖关系不明确，难以追踪属性的来源。
测试 | 全局属性可能会增加单元测试的难度，需要模拟全局属性才能进行测试。 | 需要注意全局属性的测试覆盖率，确保全局属性的正确性。
替代方案 | 可以使用 provide/inject、Vuex、Pinia 等方式来实现组件间的数据共享。 | 不同的替代方案有不同的适用场景，需要根据具体情况选择。

尾声：globalProperties 的正确打开方式

总而言之，app.config.globalProperties 是一个非常有用的工具，可以让你在 Vue 应用里方便地共享一些通用的东西。但也要注意正确使用，避免滥用，才能让你的代码更加清晰、易于维护。

希望今天的讲解对大家有所帮助。如果有什么问题，欢迎在评论区留言。下次再见！