Vue3——自定义hook函数、toRef和toRefs

本文介绍了Vue3中自定义hook的概念和使用方式,通过示例解释了如何创建并复用自定义hook函数,提高代码可读性和复用性。同时,详细讲解了toRef和toRefs的用途,特别是在处理响应式对象属性时如何保持数据响应性,并通过实际案例展示了它们在模板渲染中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

自定义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>
Vue 3中,toreftorefs是两个用于处理响应式对象的方法。 toref方法用于将指定属性从响应式对象中提取出来,创建一个单独的ref对象,以便对该属性进行独立的绑定访问。例如,使用toref可以将一个对象的&#39;name&#39;属性提取出来并创建一个单独的ref对象: ```javascript const name = toRef(obj, &#39;name&#39;); ``` 这样就可以通过name.value来访问修改&#39;name&#39;属性的值。 而torefs方法则是将整个响应式对象转换为带有.value的ref对象集合,以方便对每个属性进行访问。例如,使用torefs可以将一个包含多个属性的对象转换为多个单独的ref对象: ```javascript const refs = toRefs(obj); ``` 这样就可以通过refs.name.valuerefs.age.value来访问修改&#39;name&#39;&#39;age&#39;属性的值。 总结来说,toref用于提取单个属性并创建单独的ref对象,而torefs用于将整个对象转换为一组带有.value的ref对象。这两个方法可以帮助我们更方便地处理响应式对象的属性。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [vue3toReftoRefs](https://blog.csdn.net/qq_52421092/article/details/131085448)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [Vue 3 中,toRefstoRef](https://blog.csdn.net/qq_39034148/article/details/131577670)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [Vue3toRef以及toRefs的基本使用](https://blog.csdn.net/m0_56219678/article/details/122974116)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值