当前位置: 首页 > java >正文

【Vue3】生命周期 hook函数 toRef

目录

一、vue2生命周期钩子

二、Vue3组合式API

三、自定义hook函数

生命周期顺序:

小demo

四、toRef

总结不易~本章节对我有很大的收获,希望对你也是!!!


本章节素材已上传至Gitee:yihaohhh/我爱Vue - Gitee.comhttps://gitee.com/liu-yihao-hhh/i-love---vue/tree/master/11_src3_%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F

一、vue2生命周期钩子

我们先来回顾一下各个生命周期钩子:

App组件:

<template><button @click="isShowDemo = !isShowDemo">切换隐藏/显示</button><Demo v-if="isShowDemo" />
</template><script>
import Demo from './components/Demo'
import {ref} from 'vue'
export default {name: 'App',components: {Demo},setup() {let isShowDemo = ref(true)return {isShowDemo}}
}
</script>

Demo组件:通过配置的形式 来使用生命周期钩子

<template><h2>当前求和为:{{ sum }}</h2><button @click="sum++">点我 + 1</button>
</template><script>
import {ref} from 'vue'
export default {name: 'DemoBox',setup() {let sum = ref(0)console.log('---setup---')return {sum,}},// 通过配置的形式 使用生命周期钩子// 创建前钩子 实例刚被创建,data 和 methods 都还未初始化beforeCreate() {console.log('---beforeCreate---')},// 创建后钩子 实例创建完成,data、methods 已经可以使用created() {console.log('---created---')},// 挂载前钩子 模板编译完成,尚未挂载到 DOMbeforeMount() {console.log('---beforeMount---')},// 挂载后钩子 DOM 挂载完成,页面已渲染mounted() {console.log('---mounted---')},// 	更新前钩子 数据更新时调用,DOM 还未重新渲染beforeUpdate() {console.log('---beforeUpdate---')},// 	更新后钩子 数据更改并 DOM 更新完成后调用updated() {console.log('---updated---')},// 卸载前钩子 组件即将被卸载前调用(Vue 3 中新增)beforeUnmount() {console.log('---beforeUnmount---')},// 卸载后钩子 组件卸载完成后调用(Vue 3 中新增)unmounted() {console.log('---unmounted---')},
}
</script>

可以 看到setup是在所有生命周期钩子中最先执行的,也就是在程序启动的时候,setup跟beforeCreate生命周期钩子是平级的,并且比beforeCreate生命周期钩子先执行

因为Demo组件是靠v-if来显示就是进行组件的删除和创建,可以看到组件的删除是考beforeUnmount 和 unmounted来进行操控

Vue3从Vue2演变过来,生命周期也得到了改变, Vue3为我们提供了组合式API的形式,可以写到setup里面,但是这里要注意,beforeCreate 和 created并没有为我们提供组合式API的形式

也就是说setup就相当于beforeCreate 和 created两个生命周期钩子了

本章节素材已上传至Gitee:yihaohhh/我爱Vue - Gitee.comhttps://gitee.com/liu-yihao-hhh/i-love---vue/tree/master/11_src3_%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F

二、Vue3组合式API

就是把每一个生命周期钩子都加上一个on来进行vue函数的引用,他们都是函数数据类型,他们都可以传递一个回调函数,这个回调函数都是在钩子挂载之前执行,就是相当于你在外面写生命周期一样

import {ref, onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted} from 'vue'
export default {name: 'DemoBox',setup() {let sum = ref(0)console.log('---setup---')// 通过组合式API形式去使用生命周期钩子onBeforeMount(() => {console.log('---onBeforeMount---')})onMounted(() => {console.log('---onMounted---')})onBeforeUpdate(() => {console.log('---onBeforeUpdate---')})onUpdated(() => {console.log('---onUpdated---')})onBeforeUnmount(() => {console.log('---onBeforeUnmount---')})onUnmounted(() => {console.log('---onUnmounted---')})return {sum,}},

如果你同时写了setup外面 和 里面两种生命周期钩子,那么on-生命周期钩子的优先级会更高一点

本章节素材已上传至Gitee:yihaohhh/我爱Vue - Gitee.comhttps://gitee.com/liu-yihao-hhh/i-love---vue/tree/master/12_src3_%E8%87%AA%E5%AE%9A%E4%B9%89hook

三、自定义hook函数

<template><h2>当前求和为:{{ sum }}</h2><button @click="sum++">点我 + 1</button><hr><h2>当前点击时鼠标的坐标为:x:{{ point.x }},y:{{ point.y }}</h2>
</template><script>
import {ref, reactive, onMounted} from 'vue'
export default {name: 'DemoBox',setup() {let sum = ref(0)let point = reactive({x:0,y:0})onMounted(() => {window.addEventListener('click', (e) => {point.x = e.pageXpoint.y = e.pageYconsole.log(e.pageX, e.pageY)})}) return {sum,point}},
}
</script>

生命周期顺序:

beforeCreate → created → beforeMount → mounted
mounted钩子,页面渲染完成了,Vue 组件的 DOM 元素也出现在浏览器上了,此时你可以安全地操作它们。

由于当前组件在被销毁后,但是该组件内部的挂载的各种事件却没有被销毁,还是能够发生,所以我们就要在组件被销毁前进行事件的取消效果!

beforeUnmount组件被销毁前:

  • mounted:演员 上台 了,可以开始表演;

  • beforeUnmount:演员 快下台 了,要把台词稿、话筒、灯光等东西收拾好。

由于这是两个新创建的函数,所以不可取分别在创建和销毁上,所以要单独分离出来同一个函数来进行创建和销毁该事件!

    function savaPoint(e) {point.x = e.pageXpoint.y = e.pageYconsole.log(e.pageX, e.pageY)}// 当组件挂载(即页面加载)完毕后,给 window 绑定了一个 点击事件监听器onMounted(() => {window.addEventListener('click', savaPoint)}) // 在组件即将销毁之前,移除事件监听器;onBeforeUnmount(() => {window.removeEventListener('click', savaPoint)})

但是有没有想过,我们是否能把这个强大的功能给分离出来呢!既然我们能够用,就业想让别人也能够复用这个功能,那么就要引入hook函数了!本质是一个函数,把setup函数中使用的组合式API进行了封装。

我们在src下创建一个hooks文件夹!然后创建该功能的名字一般叫use功能名!

usePoint.js:将demo组件的功能抽离出来!做到,并且进行暴露!但是注意一定要求给返回值!

import { reactive, onMounted, onBeforeUnmount } from 'vue'
export default function () {// 实现鼠标“打点”相关的数据let point = reactive({x: 0,y: 0})// 实现鼠标“打点”相关的方法function savaPoint(e) {point.x = e.pageXpoint.y = e.pageYconsole.log(e.pageX, e.pageY)}// 当组件挂载(即页面加载)完毕后,给 window 绑定了一个 点击事件监听器onMounted(() => {window.addEventListener('click', savaPoint)})// 在组件即将销毁之前,移除事件监听器;onBeforeUnmount(() => {window.removeEventListener('click', savaPoint)})return point
}

Demo组件:来进行函数引入和接受就行!

<template><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: 'DemoBox',setup() {let sum = ref(0)let point = usePoint()return {sum,point}},
}
</script>

小demo

  • 进行函数方法暴露的时候,如果暴露的是已经取好名字的,就需要用别人取好名字的方法{ref,reactive}
  • 但是直接暴露我们自定义的hook函数,就是没有取名字的,我们就可以当场取名字,不需要加{}
  • 什么是hook?—— 本质是一个函数,把setup函数中使用的Composition API进行了封装。

  • 类似于vue2.x中的mixin。

  • 自定义hook的优势: 复用代码, 让setup中的逻辑更清楚易懂。

本章节素材已上传至Gitee:yihaohhh/我爱Vue - Gitee.comhttps://gitee.com/liu-yihao-hhh/i-love---vue/tree/master/13_src3_toRef%E4%B8%8EtoRefs

四、toRef

toRef(想获取的对象, ‘对象中的某个属性值’)

toRef就是定义一个新的变量,来充当对象里面某个属性的本体,就是c++的&引用,这样就不会是属于新建的一个形参,不会对对象本体产生影响!

    let person = reactive({name: '张三',age: 18,job: {j1: {salary: 20}}})// 这个name1 他是字符型 一个新建的常量型const name1 = person.nameconsole.log(name1)// 第一个参数:想取哪个对象// 第二个参数:对象里面的哪个属性名// 此时的name2 就是& 引用类型!const name2 = toRef(person, 'name')console.log('###', name2)

这样就可以返回我们只需要用到的对象,来在模板进行简化写法

<template><h2>姓名:{{ name }}</h2><h2>年龄:{{ age }}</h2><h2>薪资:{{ salary }}k</h2><button @click="name+='~'">修改姓名</button><button @click="age++">增长年龄</button><button @click="salary++">长薪</button>
</template><script>
import {reactive, toRef} from 'vue'
export default {name: 'DemoBox',setup() {let person = reactive({name: '张三',age: 18,job: {j1: {salary: 20}}})// 这个name1 他是字符型 一个新建的常量型const name1 = person.nameconsole.log(name1)// 第一个参数:想取哪个对象// 第二个参数:对象里面的哪个属性名// 此时的name2 就是& 引用类型!const name2 = toRef(person, 'name')console.log('###', name2)return {name:toRef(person, 'name'),age: toRef(person, 'age'),salary:toRef(person.job.j1, 'salary')}}
}
</script>

那么问题就来了,既然toRef目的就是要做到响应式,那么为什么不直接返回ref()数据呢?

    return {person,name:ref(person.name),age: ref(person.age),salary:ref(person.job.j1.salary)}

可以看到,虽然我们同样能够做到响应式的数据变化但是,原本对象里面的值却没有被改变!说明这只是创建了一个新的对象来进行返回进行响应式的!所以这里要对原本的对象进行改变还是需要用到toRef()

总结:toRef()就是引用对象,ref()就是复制对象

那么问题又来了,通过toRef()我们只是一个对象属性的引用来进行,如果有一百个,我们不可能单独写一百个toRef来进行引用对象属性吧!所以这里就引入toRefs()

    const x = toRefs(person)console.log(x)

可以看到x就是通过Proxy进行操控的数据,也就是person对象本身,x就也是一个对象!

那么我们在进行返回的时候,对象里面是不能再次嵌套一个对象的!也就是通过es6语法...toRefs(person)来讲对象里面的内容进行展开,来平铺到该return语句的对象中!

但是toRefs却只能取到对象里面的每个第一层,所以访问后面的深层次对象还是需要手动进行遍历,但是访问第一层就已经很方便了!

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

小结:

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

  • 语法:const name = toRef(person,'name')

  • 应用: 要将响应式对象中的某个属性单独提供给外部使用时。

  • 扩展:toRefstoRef功能一致,但可以批量创建多个 ref 对象,语法:toRefs(person)

总结不易~本章节对我有很大的收获,希望对你也是!!!

http://www.xdnf.cn/news/9215.html

相关文章:

  • 通义智文开源QwenLong-L1: 迈向长上下文大推理模型的强化学习
  • 浅解Vue 数据可视化开发建议与速度优化
  • 【华为云物联网】如何实现在 MQTT.fx 上模拟数据间隔上传一次,并按设定系数变动数据
  • HTML 表单与输入:基础语法到核心应用全解析
  • UBUNTU20.04 配置以QT界面程序代替系统界面启动,以及如何在tty模式下以linuxfb形式启动
  • Halcon 霍夫变换
  • 获取页面上当前激活(获得焦点)的元素
  • Frequent values/gcd区间
  • 行为型:中介者模式
  • C++11 中引入的`final` 关键字作用。
  • ImageMagick 是默认使用 CPU 来处理图像,也具备利用 GPU 加速的潜力
  • 数据库的事务(Transaction)
  • 路桥隧养护决策系统
  • atomic.Value 中存储的数据是否会被 GC
  • vue展示修改前后对比,并显示修改标注diff
  • 四足机器人环境监测系统相关问题
  • Mac 每日磁盘写入量异常高
  • AI如何颠覆财务预测?——用Python打造自动化智能分析系统
  • 基于Java,SpringBoot,Vue,UniAPP宠物洗护医疗喂养预约服务商城小程序管理系统设计
  • SQL Server 简介和与其它数据库对比
  • 联想小新笔记本电脑静电问题导致无法开机/充电的解决方案
  • 远程控制技术全面解析:找到适合你的最佳方案
  • 北京大学肖臻老师《区块链技术与应用》公开课:03-BTC-数据结构
  • 计算机网络的性能指标
  • 网络协议:[0-RTT 认证 ]
  • 在 LangGraph 中集成 Mem0 记忆系统教程
  • 【HarmonyOS5】Stage模型应用程序包结构详解
  • PDF处理控件Aspose.PDF教程:压缩 PDF 文档的完整指南
  • OpenCV CUDA模块图像处理------颜色空间处理之拜耳模式去马赛克函数demosaicing()
  • 网络套接字基础使用和概念