【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组件:

html 复制代码
<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组件:通过配置的形式 来使用生命周期钩子

html 复制代码
<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---')
  },
  // 挂载前钩子 模板编译完成,尚未挂载到 DOM
  beforeMount() {
    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函数的引用,他们都是函数数据类型,他们都可以传递一个回调函数,这个回调函数都是在钩子挂载之前执行,就是相当于你在外面写生命周期一样

javascript 复制代码
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函数

html 复制代码
<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.pageX
        point.y = e.pageY
        console.log(e.pageX, e.pageY)
      })
    }) 

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

生命周期顺序:

beforeCreate → created → beforeMount → mounted

mounted钩子,页面渲染完成了,Vue 组件的 DOM 元素也出现在浏览器上了,此时你可以安全地操作它们。
由于当前组件在被销毁后,但是该组件内部的挂载的各种事件却没有被销毁,还是能够发生,所以我们就要在组件被销毁前进行事件的取消效果!

beforeUnmount组件被销毁前:

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

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

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

javascript 复制代码
    function savaPoint(e) {
        point.x = e.pageX
        point.y = e.pageY
        console.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组件的功能抽离出来!做到,并且进行暴露!但是注意一定要求给返回值!

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

  // 实现鼠标"打点"相关的方法
  function savaPoint(e) {
    point.x = e.pageX
    point.y = e.pageY
    console.log(e.pageX, e.pageY)
  }

  // 当组件挂载(即页面加载)完毕后,给 window 绑定了一个 点击事件监听器
  onMounted(() => {
    window.addEventListener('click', savaPoint)
  })

  // 在组件即将销毁之前,移除事件监听器;
  onBeforeUnmount(() => {
    window.removeEventListener('click', savaPoint)
  })

  return point
}

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

javascript 复制代码
<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++的&引用,这样就不会是属于新建的一个形参,不会对对象本体产生影响!

javascript 复制代码
    let person = reactive({
      name: '张三',
      age: 18,
      job: {
        j1: {
          salary: 20
        }
      }
    })

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

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

javascript 复制代码
<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.name
    console.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()数据呢?

javascript 复制代码
    return {
      person,
      name:ref(person.name),
      age: ref(person.age),
      salary:ref(person.job.j1.salary)
    
    }

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

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

javascript 复制代码
    const x = toRefs(person)
    console.log(x)

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

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

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

javascript 复制代码
    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)

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

相关推荐
年纪轻轻只想躺平6 分钟前
Vue2部分知识点和注意项
前端·javascript·vue.js
多则惑少则明1 小时前
Vue开发系列——Vue 生命周期钩子 及常见知识点
前端·javascript·vue.js·前端框架
菥菥爱嘻嘻2 小时前
JS手写代码篇---Pomise.race
开发语言·前端·javascript
南瓜胖胖2 小时前
【R语言编程绘图-调色】
开发语言·r语言
lanbing3 小时前
非常适合初学者的Golang教程
开发语言·后端·golang
CodeCipher3 小时前
前端Vue3列表滑动无限加载实现
前端·javascript·vue.js·vue
十碗饭吃不饱4 小时前
vue修改配置文件.env.development不生效
前端·javascript·vue.js
stormsha4 小时前
GO语言进阶:掌握进程OS操作与高效编码数据转换
开发语言·数据库·后端·golang·go语言·源代码管理
老神在在0015 小时前
javaEE1
java·开发语言·学习·java-ee
魔道不误砍柴功5 小时前
《接口和抽象类到底怎么选?设计原则与经典误区解析》
java·开发语言