首页 前端知识 vue3中getCurrentInstance不推荐使用以及在<script setup>中获取全局内容(三种方式)

vue3中getCurrentInstance不推荐使用以及在<script setup>中获取全局内容(三种方式)

2024-11-10 09:11:22 前端知识 前端哥 812 850 我要收藏
在vue3中并没有暴露出一个获取全局方法的的接口
所以我们并不能通过 import {全局方法} from 'vue' 的方法来获取

首先在main.js中定义全局的内容
 const app = createApp(App)
 app.config.globalProperties.$test = '666'
 app.mount('#app')

方法一(不推荐)

vue 中的 getCurrentInstance 方法返回了 ctx 和 proxy,控制台打印 ctx 和 proxy 发现和 vue2.x 中的 this 等同,习惯使用 this 的朋友可以用 proxy 进行替代。

import {defineComponent, getCurrentInstance} from 'vue'
export default defineComponent ({
  setup(){
  
  	//vue3-typescript
    const { proxy, ctx } = (getCurrentInstance() as ComponentInternalInstance)
	//vue3-javascript
	const { proxy, ctx } = getCurrentInstance()
	
    const _this = ctx
    
    console.log('getCurrentInstance()中的ctx:', _this)
    console.log('getCurrentInstance()中的proxy:', proxy)
    
    return {}
  }
})

本例中使用 getCurrentInstance 方法区获取

const ctx = getCurrentInstance() console.log('ctx', ctx)

这时我们就能在控制台中看到我们定义的内容了
在这里插入图片描述


但是不推荐使用,不推荐原因其实在官网中已经说的很明白了

在这里插入图片描述

官方解说: 在 setup() 内部,this 不会是该活跃实例的引用(即不指向vue实例),因为 setup() 是在解析其它组件选项之前被调用的,所以 setup() 内部的 this 的行为与其它选项中的 this 完全不同。这在和其它选项式 API 一起使用 setup() 时可能会导致混淆。因此setup函数中不能使用this。所以Vue为了避免我们错误的使用,直接将setup函数中的this修改成了 undefined)

我理解: 在Vue3中,setup 在生命周期 beforecreate 和 created 前执行,此时 vue 对象还未创建,因此,无法使用我们在 vue2.x 常用的 this。在生产环境内可能会获取不到该实例!!,而且我们确实不应该用该方法去代替this

按照鱿鱼须的原话就是:

Because the instance is an internal instance that exposes non-public APIs. Anything you use from that instance can technically break between any release types, since they are not subject to semver constraints.

同时也给出了应该如何解决问题:

I’m not sure why you need the setup context in nested composables, but explicitly passing arguments to composables make then less coupled to the consuming component, thus easier to understand and test in isolation.

In general a library designed to work with Composition API should expose special variables via its own composables (e.g. useRoute from vue-router) instead of the requiring the user to grab it from the instance.

主要还是 getCurrentInstance 是一个内部的API,并不是公开的API,使用内部API去实现一些业务功能,可能会因为后续 Vue 的版本迭代而造成业务上的 BUG。并且 Vue3 的 Composition API 强调的就是业务的解耦和复用性,依赖组件实例属性并不是一个很好的开发方式。而 vue 相关生态的使用其实就是他们内部的事情了,他们有完善的测试用例可以跑测试,但是我们并没有,如果后续的某一个版本Vue变更了这个API,那么如果没有经过完整测试就部署上去的项目就会出现大规模的BUG反馈了。

vue3 github issu反馈截图
https://github.com/vuejs/docs…
在这里插入图片描述

鱿鱼须反馈截图
在这里插入图片描述

方法二(推荐)

使用 Provide / Inject

v3.cn.vuejs.org/guide/compo…
在main.js中provide
app.provide('$test', '666')

在组件内获取

import { inject } from 'vue'
const test = inject('$test')
console.log('inject的$test', test)
这样就可以获取到了

扩展
挂载方法 在main.js中provide

import dayjs from 'dayjs'
const formatTime = (time, format) => (time ? dayjs(time).format(format || 'YYYY-MM-DD') : '-')
app.provide('dayjs', formatTime)

在组件中获取
const dayjs = inject('dayjs')
const formatResult = dayjs(1639014286)
console.log('dayFormat', formatResult)

方式三(不推荐 只适合应急的时候使用 因为我觉得这样用怪怪的)

使用两个script标签来获取this并保存
首先现在main.js中像之前一样定义全局变量

import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)
// 官方推荐将全局变量写进 globalProperties下
app.config.globalProperties.myOption = 'myOption'
app.mount('#app')
然后在组件中获取
<script>
import HelloWorld from './components/HelloWorld.vue'
import { onBeforeMount, defineComponent } from 'vue'
let that = this
export default defineComponent({
  beforeCreate() {
    that = this
  },
})
</script>
<script setup>
onBeforeMount(() => {
  console.log('that', that.myOption)
})
</script>
这样就可以获取到啦

在setup标签中一定要在 onBeforeMount之后再读取this!!!

一些问题

为什么要创建两个script标签?
因为在setup标签中是不绑定this的 所以只能在另一个script标签中获取
为什么一定要在onBeforeMount之后才能获取呢?
因为setup的生命周期是在beforeCreate,created之前执行的 我们在beforeCreate时保存的this,所以要在beforeCreate之后获取,onBeforeMount是在beforeCreate之后执行的 所以可以获取到 note
如果按这样写了两个script标签那么就不可以在没写setup中再执行setup函数
xml
复制代码

<script>
import HelloWorld from './components/HelloWorld.vue'
import { onBeforeMount, defineComponent } from 'vue'
let that = this
export default defineComponent({
  beforeCreate() {
    console.log('beforeCreate')
    that = this
  },
  setup() {
    // 这里面的内容不会执行
    console.log('非单标签的setup')
  }
})
</script>
<script setup>
console.log('setup')
onBeforeMount(() => {
  console.log('that', that.myOption)
})
</script>

为啥
因为在标签中写setup本身就是一个语法糖 vue会检验是否有

// 这是options方式

<script>
import HelloWorld from './components/HelloWorld.vue'
export default defineComponent({
  setup() {
    // 这里面的内容还是不会执行
    console.log('非单标签的setup')
  }
})
</script>
// 这是<script setup>
<script setup></script>

你可能回想(会不会是因为 setup标签放到下方 所以覆盖了上方的setup方法呢?) 经测试 这个执行方式无关你放置的位置 哪怕将其放到options方式上方他仍然不会执行!

转载请注明出处或者链接地址:https://www.qianduange.cn//article/20147.html
标签
评论
发布的文章
大家推荐的文章
会员中心 联系我 留言建议 回顶部
复制成功!