Skip to content

一文搞懂 vue3 中获取 app 实例、组件实例的方法

一、vue2.0

1、main.js 中

java
import api from './api' // 导入api接口
Vue.prototype.$api = api
Vue.prototype.$abc = 111

2、.vue 中:

注意:在 Vue 2 中,this 关键字在组件内部指向当前组件对象,而不是 Vue 的根实例(app 对象)。当你在 Vue 2 的组件中使用 this,你实际上引用的是当前组件的上下文,包括组件的数据、方法、计算属性等。

java
this.$api.user...

let abc = this.$abc   //111

为什么在全局定义了$abc,在组件里面就可以取到呢?

在 Vue 2 中,当你在 Vue 的原型对象 Vue.prototype 上定义了属性或方法,这些属性或方法会被添加到每个 Vue 组件实例上,因为 Vue 组件是通过构造函数创建的。

所以,当你在 Vue 2 中定义了 Vue.prototype.$abc = 111,这个属性 $abc 就会被添加到每个 Vue 组件实例上。当你在组件内部使用 this.$abc 时,this 指向当前组件实例,因此你可以访问到这个在原型上定义的属性。

这是 Vue 2 提供的一种在全局范围内共享数据、方法的方式,你可以通过原型扩展来在每个组件中共享一些公共的数据或方法。

二、vue3.0

1、main.js 中

java
const app = createApp(App)
//全局配置
app.config.globalProperties.foo = 'bar'

2、.vue 文件中:

2.1 选项式 api:mounted 中(和 2.0 中用法一样)

但是 3.0 中很少使用 mounted

java
let abc = this.foo //bar

2.2 组合式 api:setup 中 (重头戏)

(1)使用 ctx (强烈不推荐!) ——> 获取当前组件实例,相当于 this

js
import { getCurrentInstance } from "vue";
const { ctx } = getCurrentInstance();

经过测试,打包到 dist 以后,ctx 下面的值是拿不到的,但是本地可以!

==(2)使用 proxy (强烈推荐)== ——> 获取当前组件实例,相当于 this

注意:proxy 是当前组件的代理对象,而不是整个 Vue 对象。在 Vue 3 中,组件实例是通过 createComponentInstance 创建的,每个组件实例都有自己的代理对象,这个代理对象是一个响应式的代理,可以通过它访问和操作组件的数据、计算属性、方法等。

java
setup() {
     const { proxy, ctx } = getCurrentInstance()
     const showMessage = () => {
      let m = proxy.foo
      let n = ctx.foo
      ElMessage.success({
        message: 'proxy: '+m, //本地和打包出来都可以拿到
        type: 'success'
      })
      ElNotification({
        title: 'ctx: '+n, //打包出来以后,内容拿不到
      })
    }
    return {
      showMessage
    }
}

==(3)使用 appContext.config.globalProperties(推荐)== ——> 实际上 appContext 就是全局 app 对象!

js
const { appContext } = getCurrentInstance();
const globalProperties = appContext.config.globalProperties;

console.log(globalProperties.foo);

3、proxy、ctx、appContext 三者的区别

在 Vue 3 中,getCurrentInstance是一个用于在组件内部获取当前组件实例的方法。它返回一个对象,该对象包含三个重要的属性:proxyctx、和appContext

  1. proxy: proxy属性是一个代理对象,它暴露了组件实例的属性和方法。你可以通过这个代理对象来访问和操作组件实例的数据、方法、计算属性等。它使你能够在组件内部访问和操作组件的所有内容,而无需直接引用组件实例本身。这有助于提高代码的可维护性和可读性。
  2. ctx: ctx属性是一个上下文对象,它包含了一些常用的属性和方法,可以在组件的生命周期内使用。它包括了以下属性和方法:
    • attrs: 一个包含组件接收的父组件传递的非响应式属性的对象。
    • slots: 一个包含插槽内容的对象。
    • emit: 一个用于触发当前组件的自定义事件的函数。
    • expose: 允许你将一些属性或方法暴露给父组件。
  3. appContext: appContext属性是一个应用程序上下文对象,它包含了与应用程序相关的全局属性和方法。通过这个属性,你可以访问全局配置、组件库、自定义指令、混入等。它通常在组件内部不直接使用,而是在需要访问全局内容时使用。

三者的应用场景:

这三个属性(proxyctxappContext)在 Vue 3 中有不同的应用场景,让我们更详细地探讨一下它们的用途:

  1. proxy 的应用场景:
    • 数据访问与修改: 使用proxy,你可以访问和修改组件的响应式数据、计算属性和方法,而无需直接引用组件实例。这提高了代码的可读性,同时也使得在组件内部进行数据操作更加方便。
  2. ctx 的应用场景:
    • 传递属性和插槽内容: ctx 提供了一种方式来访问父组件传递给当前组件的属性,以及访问插槽内容。这对于自定义组件的封装非常有用,可以在组件内部访问这些数据。
    • 触发自定义事件: 通过 ctx.emit,你可以在组件内部触发自定义事件,这使得组件与其父组件之间能够进行通信。
  3. appContext 的应用场景:
    • 全局配置和组件库: 你可以使用 appContext 来访问全局的配置项,如全局的混入、自定义指令、全局组件等。这允许你在组件内部访问这些全局资源,而不需要在每个组件中重复定义。
    • 扩展插件功能: 如果你在应用中使用了自定义插件,那么这些插件可能会将一些功能添加到 appContext 中,供组件使用。

4、proxy 的实际应用:爱旅游

image-20230404140519401image-20230404140501519

这样就获取了当前 ref 为 detailPanel 的子组件实例对象!

使用 proxy 和使用 ref 的区别:

const myComponentRef = ref(null); 和 getCurrentInstance().proxy.$refs.myComponentRef 的区别?

ref 创建的引用(reference)和通过 getCurrentInstance().proxy.$refs 获取的引用,在某种程度上是相似的。两种方法都可以用来引用组件实例。

主要区别在于,使用 ref 创建的引用需要你自己在组件中设置,而使用 $refs 是 Vue 在底层自动创建和管理的。此外,使用 $refs 会更适合在模板中直接使用,而使用 ref 更适合在组件的 setup 中使用。

无论选择哪种方法,都应该注意不要过度依赖对组件实例的直接引用,因为这可能导致代码的耦合性增加。最好的实践是使用 props 和事件来进行组件之间的通信,以保持组件的独立性和可维护性。

注意:就是写法不同,但是 proxy 除了具有$refs 还有其他的,所以更强大一些!