(11)provide && inject
与 Vue2中的 provide
和 inject
作用相同,只不过在Vue3中需要手动从 vue
中导入
这里简单说明一下这两个方法的作用:
- provide :向子组件以及子孙组件传递数据。接收两个参数,第一个参数是
key
,即数据的名称;第二个参数为value
,即数据的值
- inject :接收父组件或祖先组件传递过来的数据。接收一个参数
key
,即父组件或祖先组件传递的数据名称
假设这有三个组件,分别是 A.vue
、B.vue
、C.vue
,其中 B.vue
是 A.vue
的子组件,C.vue
是 B.vue
的子组件
// A.vue <script> import {provide} from 'vue' export default { setup() { const obj= { name: '前端印象', age: 22 } // 向子组件以及子孙组件传递名为info的数据 provide('info', obj) } } </script> // B.vue <script> import {inject} from 'vue' export default { setup() { // 接收A.vue传递过来的数据 inject('info') // {name: '前端印象', age: 22} } } </script> // C.vue <script> import {inject} from 'vue' export default { setup() { // 接收A.vue传递过来的数据 inject('info') // {name: '前端印象', age: 22} } } </script>
(12)watch && watchEffect
watch
和 watchEffect
都是用来监视某项数据变化从而执行指定的操作的,但用法上还是有所区别
watch:watch( source, cb, [options] )
参数说明:
- source:可以是表达式或函数,用于指定监听的依赖对象
- cb:依赖对象变化后执行的回调函数
- options:可参数,可以配置的属性有 immediate(立即触发回调函数)、deep(深度监听)
当监听 ref
类型时:
<script> import {ref, watch} from 'vue' export default { setup() { const state = ref(0) watch(state, (newValue, oldValue) => { console.log(`原值为${oldValue}`) console.log(`新值为${newValue}`) /* 1秒后打印结果: 原值为0 新值为1 */ }) // 1秒后将state值+1 setTimeout(() => { state.value ++ }, 1000) } } </script>
当监听 reactive
类型时:
<script> import {reactive, watch} from 'vue' export default { setup() { const state = reactive({count: 0}) watch(() => state.count, (newValue, oldValue) => { console.log(`原值为${oldValue}`) console.log(`新值为${newValue}`) /* 1秒后打印结果: 原值为0 新值为1 */ }) // 1秒后将state.count的值+1 setTimeout(() => { state.count ++ }, 1000) } } </script>
当同时监听多个值时:
<script> import {reactive, watch} from 'vue' export default { setup() { const state = reactive({ count: 0, name: 'zs' }) watch( [() => state.count, () => state.name], ([newCount, newName], [oldvCount, oldvName]) => { console.log(oldvCount) // 旧的 count 值 console.log(newCount) // 新的 count 值 console.log(oldName) // 旧的 name 值 console.log(newvName) // 新的 name 值 } ) setTimeout(() => { state.count ++ state.name = 'ls' }, 1000) } } </script>
因为 watch
方法的第一个参数我们已经指定了监听的对象,因此当组件初始化时,不会执行第二个参数中的回调函数,若我们想让其初始化时就先执行一遍,可以在第三个参数对象中设置 immediate: true
watch
方法默认是渐层的监听我们指定的数据,例如如果监听的数据有多层嵌套,深层的数据变化不会触发监听的回调,若我们想要其对深层数据也进行监听,可以在第三个参数对象中设置 deep: true
补充: watch方法会返回一个stop方法,若想要停止监听,便可直接执行该stop函数
接下来再来聊聊 watchEffect
,它与 watch
的区别主要有以下几点:
- 不需要手动传入依赖
- 每次初始化时会执行一次回调函数来自动获取依赖
- 无法获取到原值,只能得到变化后的值
来看一下该方法如何使用:
<script> import {reactive, watchEffect} from 'vue' export default { setup() { const state = reactive({ count: 0, name: 'zs' }) watchEffect(() => { console.log(state.count) console.log(state.name) /* 初始化时打印: 0 zs 1秒后打印: 1 ls */ }) setTimeout(() => { state.count ++ state.name = 'ls' }, 1000) } } </script>
从上述代码中可以看出,我们并没有像 watch
方法一样先给其传入一个依赖,而是直接指定了一个回调函数
当组件初始化时,将该回调函数执行一次,自动获取到需要检测的数据是 state.count
和 state.name
根据以上特征,我们可以自行选择使用哪一个监听器
(13)getCurrentInstance
我们都知道在Vue2的任何一个组件中想要获取当前组件的实例可以通过 this
来得到,而在Vue3中我们大量的代码都在 setup
函数中运行,并且在该函数中 this
指向的是 undefined
,那么该如何获取到当前组件的实例呢?
这时可以用到另一个方法,即 getCurrentInstance
<template> <p>{{ num }}</p> </template> <script> import {ref, getCurrentInstance} from 'vue' export default { setup() { const num = ref(3) const instance = getCurrentInstance() console.log(instance) return {num} } } </script>
我们来看一下其打印结果
因为 instance
包含的内容太多,所以没截完整,但是主要的内容都在图上了,我们重点来看一下 ctx
和 proxy
,因为这两个才是我们想要的 this
的内容
可以看到 ctx
和 proxy
的内容十分类似,只是后者相对于前者外部包装了一层 proxy
,由此可说明 proxy
是响应式的
(14)useStore
在Vue2中使用 Vuex,我们都是通过 this.$store
来与获取到Vuex实例,但上一部分说了原本Vue2中的 this
的获取方式不一样了,并且我们在Vue3的 getCurrentInstance().ctx
中也没有发现 $store
这个属性,那么如何获取到Vuex实例呢?这就要通过 vuex
中的一个方法了,即 useStore
// store 文件夹下的 index.js import Vuex from 'vuex' const store = Vuex.createStore({ state: { name: '前端印象', age: 22 }, mutations: { …… }, …… }) // example.vue <script> // 从 vuex 中导入 useStore 方法 import {useStore} from 'vuex' export default { setup() { // 获取 vuex 实例 const store = useStore() console.log(store) } } </script>
我们来看一下打印结果
然后接下来就可以像之前一样正常使用 vuex
了
(15)获取标签元素
最后再补充一个 ref
另外的作用,那就是可以获取到标签元素或组件
在Vue2中,我们获取元素都是通过给元素一个 ref
属性,然后通过 this.$refs.xx
来访问的,但这在Vue3中已经不再适用了
接下来看看Vue3中是如何获取元素的吧
<template> <div> <div ref="el">div元素</div> </div> </template> <script> import { ref, onMounted } from 'vue' export default { setup() { // 创建一个DOM引用,名称必须与元素的ref属性名相同 const el = ref(null) // 在挂载后才能通过 el 获取到目标元素 onMounted(() => { el.value.innerHTML = '内容被修改' }) // 把创建的引用 return 出去 return {el} } } </script>
获取元素的操作一共分为以下几个步骤:
- 先给目标元素的
ref
属性设置一个值,假设为el
- 然后在
setup
函数中调用ref
函数,值为null
,并赋值给变量el
,这里要注意,该变量名必须与我们给元素设置的ref
属性名相同
- 把对元素的引用变量
el
返回(return)出去
补充:设置的元素引用变量只有在组件挂载后才能访问到,因此在挂载前对元素进行操作都是无效的
当然如果我们引用的是一个组件元素,那么获得的将是该组件的实例对象,这里就不做过多的演示了
三、结束语
本文也是笔者对Vue3的学习与理解。因为在之前学习的过程中也查阅了大量的文档资料,并不断地测试摸索,以及在Vue3项目中的心得体会,都让我对Vue3有了更深的认识,与此同时,我在各个社区或者是社交群里都发现很多小伙伴对Vue3的API都不太熟悉,甚至不知道有这些API,所以我就写下了这篇总结文章,将我所知道、所理解的都分享给大家