Vue3的Composition Api有关的知识点

1,803 阅读3分钟

一、响应式的数据

  • 1.1 reactive API 用于创建响应式的对象或者数组,实际上该方法的内部是基于ES6的proxy实现的。
    reactive基本用法如下:
    <template>
        <h3>信息展示组件:</h3>
        <ul>
            <li>姓名: {{ data.name }}</li>
            <li>年龄: {{ data.age }}</li>
        </ul>
    </template>
    <script setup>
        import { reactive } from 'vue'
        // 创建响应式对象
        const data = reactive({
            name: 'pony',
            age: 18
        })
    </script>

Vue3还提供了一个isReactive API用户检测是否是reactive创建的响应式代理。

  • 1.2 ref 我们使用reactive只能对Object或者Array类型的数据进行劫持, 如果我们想要对普通数据类型进行劫持, 可以使用refAPI, 例如以下代码:
    <template>
        <h3>信息展示组件:</h3>
        <ul>
            <li>姓名: {{ name }}</li>
            <li>年龄: {{ age }}</li>
        </ul>
    </template>
    <script setup>
        import { ref } from 'vue'
        // 创建响应式对象
        const name = ref('pony')
        const age = ref(18)
        const handleEditName = () => {
            // 通过ref创建的是一个响应式的对象, 我们需要通过ref定义的变量.value方式来访问或者修改
            name.value = '777'
        }
        
        const handleEditAge = () => {
            age.value = 20
        }
    </script>
  • 1.3 readonly有时候我们希望传递给其他组件的数据时, 往往希望其他组件使用我们传递的内容, 但是不允许它们修改, 这个时候我们需要使用readonly API,该API可以创建一个不可修改的对象。
    示例代码如下:

    import { ref, readonly } from 'vue'
    const name = ref('UK')
    const age = ref(20)
    const readonlyName = readonly(name)
    const handleEditName = () => {
        name.value = 'USA'
    }
    const handleEditAGe = () => {
        age.value = 30
    }

name修改的时候, readonly的值也会随着进行而改变, 但是直接修改readonlyName并不会生效。

  • 1.4toRefs和toRef 用于将reactive创建的响应式代码结构成响应式的数据; 如果直接使用ES6的语法进行解构的话,解构出来的数据就不是响应式的。
    例如下面这段代码:
    import { toRefs, reactive } from 'vue'
    const user = reactive({ name: 'pony', age: 18 })
    // user下的属性通过toRefs与解构后的数据建立了链接, 任何一个修改都会引起另一个的变化,不管是user里面的name或者解构的name变化了两边都能捕捉到。
    const { name, age } = toRefs(user) // toRefs解构整个对象
    const handleEditName = () => {
        name.value = '777'
    }
    const handleEditAge = () => {
        age.value = 19
    }

如果想解构单个数据可以使用toRef,整个对象里面解构用toRefs,示例代码如下:

    const name = toRef(user, 'name')
    const age = toRef(user, 'age') // 解构的对象加名称

二、计算属性

2.1 computed: 在Composition API中定义计算属性通过computed方法实现, 它可以接受两种参数, 一个是getter函数, 另一个是包含getset函数的对象: computed返回一个ref对象。
如下代码展示接收getter函数时, 计算属性用法:

    import { ref, computed } from 'vue'
    const name = ref('pony')
    const age = ref(19)
    // 定义计算属性
    const user = computed(() => {
        return `姓名: ${ name.value }\n年龄:${ age.value }`
    })

上面的代码当中name或者age发生变化时, user也会进行变化。 computed方法接受对象参数时, 常见的场景就是组件实现v-model的功能, 实例代码如下所示:

    <template>
        <input type="text" v-model:value="myName"/>
    </template>
    <script setup>
        // 引入方法
        import { defineProps, defineEmits, computed } from 'vue'
        // 定义props
        const props = defineProps({
            name: String
        })
        // v-model 规定写法 update:name name -> 需要v-model的名称
        const emit = defineEmits(['update:name'])
        // 计算属性
        const myName = computed({
            get() {
                return props.name
            },
            set(val) {
                emit('update:name', val)
            }
        })
    </script>

三、监听器

  • 3.1 watch : Vue3的composition API中提供了两个用于监听数据变化的API, 分别是watchEffect (vue3.2中新增了watchEffectwatchsyncEffect API,这两个都是watchEffect的别名)和 watch, 这两者的区别如下:

    • watchEffect用于自动收集响应数据的依赖;
    • watch 需要手动去监听的数据源;

四、生命周期

  • 4.1 生命周期 Vue3的composition API没有生命周期钩子选项, 但是提供了 onBeforeMountonMounted 等函数来注册声明周期钩子, 提供的声明周期函数如下表示:
选项式APIHook inside setup触发时机
beforeMountonBeforeMount组件挂载之前触发
mounteonMounted组件挂载后触发
beforeUpdateonBeforeUpdate组件更新前触发
updatedonUpdated组件更新后触发
beforeUnmountonBeforeUnmount组件卸载之前触发
unmountedonUnmounted组件卸载后触发

如下代码展示了部分API的用法:

    import { onMounted, onUpdated, onUmounted } from 'vue'
    
    onMounted(() => {
        console.log('onMounted')
    })
    
    onUpdated(() => {
        console.log('onUnmounted')
    })

五、模板ref($refs的替代品)

  • 5.1 由于Vue3的composition API无法使用this, 所以说this.$refs并不可以用, 那我们怎么获取元素或者组件呢?其实很简单, 我们需要定义个 ref 对象, 名称与模板中ref属性的名称一致即可。

    示例代码如下:

      <template>
          <h4 ref="nameRef">加油逍遥子</h4>
      </template>
      <script setup>
          import { ref, onMounted } from 'vue'
          const nameRef = ref(null)
          onMounted(() => {
              console.log(nameRef.value) // <h4>加油逍遥子</h4>
          })
      </script>
    
  • 5.2 补充知识 如果希望像Vue2一样, 直接通过this.$refs['XXX']Vue3 的子组件需要通过内置的 defineExpose 把需要用到的变量和方法全暴露给父组件。示例代码如下:

    // 子组件
    <template>
        <h1>我是子组件</h1>
    </template>
   
    <script setup>
       import { ref } from 'vue'
        const count = ref(0)
        defineExpose({
          count
        })
    </script>
    // 父组件
    <template>
        <div>
            login
            <child ref="newChild"/>
            <h2 ref="myChild">2222</h2>
        </div>
    </template>
    <script setup>
        import { ref, onMounted } from 'vue'
        import child from '@/components/HelloWorld.vue'
        const myChild = ref(null)
        const newChild = ref(null)
        onMounted(() => {
          console.log(myChild.value)
          console.log(newChild.value.count, 'newChild')
        })
    </script>
  • 效果图如下:

image.png