Vue3的组合API——自定义hook函数、toRef和toRefs

自定义hook函数

自定义hook函数概念

  • 什么是hook?
    ——本质是一个函数,把setup函数中使用的Composition APl进行了封装。类似于vue2.x中的mixin。

自定义hook的使用

就是把setup中具有一定逻辑功能的代码提取出去,放在hooks的函数中,以后哪个组件需要使用该功能,就直接调用该hook函数即可。
hook函数一般放在src文件夹下的hooks中。

eg:
在这里插入图片描述
hooks/usePoint.js(定义hooks函数:获取鼠标点击坐标)

import {
    
    onBeforeUnmount, onMounted, reactive} from 'vue'
export default function () {
    
    
        // 实现鼠标打点的数据
        let point = reactive({
    
    
            x: 0,
            y:0
        })

        // 实现鼠标打点的函数
        function savePoint(event){
    
    
            point.x = event.pageX
            point.y = event.pageY
        }

        // 实现鼠标打点的相关方法
         // 哪个组件调用,onMounted就是指的是那个组件的挂载
        onMounted(() => {
    
    
            console.log("---onMounted---")
            // 监视整个页面所以给windown绑定
            window.addEventListener('click', savePoint)
        })

        onBeforeUnmount(() => {
    
    
            window.removeEventListener('click', savePoint)
        })
    
    return point
}

Demo.vue (调用hooks函数)

<template>
    <h1>Demo组件</h1>
    <h2>当前求和为:{
   
   {sum}}</h2>
    <button @click="sum++">点我+1</button>
    <hr/>
    <h2>当前点击时鼠标的坐标为:(x:{
   
   {point.x}},y:{
   
   {point.y}})</h2>
</template>

<script>
import {
      
       ref } from 'vue'
import usePoint from "../hooks/usePoint"
export default {
      
      
    name: 'DemoVue',
    setup() {
      
      
        console.log("---setup---")
        //  数据
        let sum = ref(0)
        let point = usePoint()

        return {
      
      
            sum,
            point 
        }
    },
}
</script>

效果:
在这里插入图片描述

自定义hook的优势

复用代码,让setup中的逻辑更清楚易懂。

toRef和toRefs

引出

需求:
在这里插入图片描述
实现如上功能,代码如下:

<template>
    <h2>姓名:{
   
   { person.name }}</h2>
    <h2>年龄:{
   
   { person.age }}</h2>
    <h2>薪资:{
   
   { person.job.j1.salary }}</h2>
    <button @click="person.name += '~'">修改姓名</button>
    <button @click="person.age += 1">增长年龄</button>
    <button @click="person.job.j1.salary++">涨薪</button>
</template>

<script>
import {
      
       reactive,} from 'vue'
export default {
      
      
    name: 'DemoVue',
    setup() {
      
      
        //  数据
        let person = reactive({
      
      
            name: 'yang',
            age: 18,
            job: {
      
      
                j1: {
      
      
                    salary: 20
                }
            }
        })
        return {
      
      
            person
        }
    }
}
</script>

模板中使用属性的时候必须person.属性
但是我不想这样写了,太麻烦了,能不能直接使用属性在模板中进行渲染呢?

  • 尝试不直接暴露person,而是将属性暴露出去:
        return {
    
    
            name: person.name,
            age: person.age,
            salary:person.job.j1.salary
        }

产生问题,person是响应式数据,但是person.name获取到的就是一个字符串的值,使用name: person.name,就相当于暴露出去一个基本类型的字符串,没有响应式。所以不能这样写。

  • 尝试使用ref对属性进行封装
        return {
    
    
            name: ref(person.name) ,
            age: ref(person.name),
            salary: ref(person.job.j1.salary)
        }

产生问题,这样确实是实现了响应式,但是使用ref就代表新创建出了一个响应式的对象,和person就脱节了,也就是说,当暴露出去的name发生变化的时候,ref所包装的数据确实是发生变化了,但是person的name属性就不会改变了。

  • 解决——使用toRef

toRef

(1)作用:创建一个ref对象,其value值指向另一个对象中的某个属性

(2)toRef与ref最大的区别是:

  • ref:创建一个ref对象,value的值就是创建对象时传过来的值了
  • toRef:创建一个ref对象,value的值可以指向另一个对象中的某个属性,即实现桥接效果。当toRef所管理的对象的值发生了变化,其value的值指向的对象的属性的值也发生变化。

(3)语法:const name = toRef(指向的对象 , '对象的属性')
(4)应用: 要将响应式对象中的某个属性单独提供给外部使用时。

(5)使用
eg:上述例子的toRef实现

<template>
    <h2>姓名:{
   
   { person.name }}</h2>
    <h2>年龄:{
   
   { person.age }}</h2>
    <h2>薪资:{
   
   { person.job.j1.salary }}</h2>
    <button @click="person.name += '~'">修改姓名</button>
    <button @click="person.age += 1">增长年龄</button>
    <button @click="person.job.j1.salary++">涨薪</button>
</template>

<script>
import {
      
       reactive, toRef } from 'vue'
export default {
      
      
    name: 'DemoVue',
    setup() {
      
      
        //  数据
        let person = reactive({
      
      
            name: 'yang',
            age: 18,
            job: {
      
      
                j1: {
      
      
                    salary: 20
                }
            }
        })
        return {
      
      
            name: toRef(person,'name') ,
            age: toRef(person, 'age'),
            salary: toRef(person.job.j1,'salary')
        }
    }
}
</script>

toRefs

toRefs与toRef功能一致,但可以批量创建多个ref对象,toRefs可以将整个响应式对象以属性的形式暴露出去
语法: toRefs(对象)

eg:上述例子的toRefs实现

<template>
    <h2>姓名:{
   
   {name }}</h2>
    <h2>年龄:{
   
   {age }}</h2>
    <h2>薪资:{
   
   {job.j1.salary }}</h2>
    <button @click="name += '~'">修改姓名</button>
    <button @click="age += 1">增长年龄</button>
    <button @click="job.j1.salary++">涨薪</button>
</template>

<script>
import {
      
       reactive, toRefs } from 'vue'
export default {
      
      
    name: 'DemoVue',
    setup() {
      
      
        //  数据
        let person = reactive({
      
      
            name: 'yang',
            age: 18,
            job: {
      
      
                j1: {
      
      
                    salary: 20
                }
            }
        })
        return {
      
      
            ...toRefs(person)
        }
    }
}
</script>

猜你喜欢

转载自blog.csdn.net/mantou_riji/article/details/125971752