VUE3照本宣科——响应式与生命周期钩子

news2024/12/23 16:22:23

VUE3照本宣科——响应式与生命周期钩子

  • 前言
  • 一、响应式
    • 1.ref()
    • 2.reactive()
    • 3.computed()
    • 4.watch()
    • 5.代码演示
  • 二、defineProps() 和 defineEmits()
  • 三、生命周期钩子
    • 1.onMounted()
    • 2.onUpdated()
    • 3.onUnmounted()
    • 4.onBeforeMount()
    • 5.onBeforeUpdate()
    • 6.onBeforeUnmount()
    • 7.onErrorCaptured()
    • 8.onRenderTracked()
    • 9.onRenderTriggered()
    • 10.onActivated()
    • 11.onDeactivated()
    • 12.onServerPrefetch()
    • 13.代码演示


前言

👨‍💻👨‍🌾📝记录学习成果,以便温故而知新

“VUE3照本宣科”是指照着中文官网和菜鸟教程这两个“本”来学习一下VUE3。以前也学过VUE2,当时只再gitee留下一些代码,却没有记录学习的心得体会,有时也免不了会追忆一下。

以后出现“中文官网”不做特殊说明就是指:https://cn.vuejs.org/;菜鸟教程就是指:https://www.runoob.com/vue3/vue3-tutorial.html


这一篇是对前篇中<script setup>的扩展,有些虽然zbxk项目中没有涉及,但是属于基本原理性质的,所以捎带介绍一下。

一、响应式

1.ref()

ref 对象是可更改的,也就是说你可以为 .value 赋予新的值。它也是响应式的,即所有对 .value 的操作都将被追踪,并且写操作会触发与之相关的副作用。

2.reactive()

响应式转换是“深层”的:它会影响到所有嵌套的属性。一个响应式对象也将深层地解包任何 ref 属性,同时保持响应性。

3.computed()

1.接受一个 getter 函数,返回一个只读的响应式 ref 对象。该 ref 通过 .value 暴露 getter 函数的返回值。
2.接受一个带有 get 和 set 函数的对象来创建一个可写的 ref 对象。

4.watch()

第一个参数是侦听器的源。这个来源可以是以下几种:

  • 一个函数,返回一个值
  • 一个 ref
  • 一个响应式对象
  • 或是由以上类型的值组成的数组

第二个参数是在发生变化时要调用的回调函数。

第三个可选的参数是一个对象,支持immediate、deep、flush、onTrack及onTrigger

详情参见https://cn.vuejs.org/api/reactivity-core.html

5.代码演示

新建TestView1.vue文件,代码如下:

<script setup>
import { computed, reactive, ref, watch } from 'vue'

// 参数基本类型
const count = ref(0)

// 代码中修改值
count.value = 1

function add(){
    count.value = count.value + 1
}

function sub(){
    count.value = count.value - 1
}

// 参数对象
const user = ref({ 
  'name': 'Tom',
  'age': '18'
})

// 参数是对象
const role = reactive({ 
  'name': '动物',
  'remark': '备注'
})

// 接受一个带有 get 和 set 函数的对象来创建一个可写的 ref 对象
const twiceCount = computed({
  get: () => count.value + 2,
  set: (val) => {
    count.value = val - 1
  }
})


// 接受一个 getter 函数
const helloUser = computed(() => 'Hello,' + user.value.name)

const x = ref(0)
const y = ref(0)

// 单个 ref
watch(x, (newX) => {
  console.log(`x is ${newX}`)
})

// getter 函数
watch(
  () => x.value + y.value,
  (sum) => {
    console.log(`sum of x + y is: ${sum}`)
  }
)

// 多个来源组成的数组
watch([x, () => y.value], ([newX, newY]) => {
  console.log(`x is ${newX} and y is ${newY}`)
})

// 响应式对象
watch(role, (newValue, oldValue) => {
  // 在嵌套的属性变更时触发
  // 注意:`newValue` 此处和 `oldValue` 是相等的
  // 因为它们是同一个对象!
  console.log(newValue)
  console.log(oldValue)
})

</script>

<template>
  <div>
    <div>数量:{{ count }},计算属性加倍:{{ twiceCount }}</div>
    <div><input type="number" v-model="count" /></div>
    <div><button @click="add">增加</button><button @click="sub">减少</button></div>

    <div>姓名:{{ user.name }},年龄;{{ user.age }}</div>
    <div>{{ helloUser }}</div>
    <div>
      <input type="text" v-model="user.name" />
      <input type="number" v-model="user.age" />
    </div>

    <div>角色:{{ role.name }},备注:{{ role.remark }}</div>
    <div>
      <input type="text" v-model="role.name" />
      <input type="text" v-model="role.remark" />
    </div>

    <div>
      X:<input type="text" v-model="x" />
      Y:<input type="text" v-model="y" />
    </div>
  </div>
</template>

添加路由代码:

{
      path: '/test1',
      name: 'test1',
      // route level code-splitting
      // this generates a separate chunk (About.[hash].js) for this route
      // which is lazy-loaded when the route is visited.
      component: () => import('../views/TestView1.vue')
}

运行效果如图:
在这里插入图片描述当如下图修改X或Y中任何值或者角色值,如图:
在这里插入图片描述
有如下输出:
在这里插入图片描述代码中watch响应式对象是role时,修改角色是有效果的,如果改成watch对象user实测没有效果。

二、defineProps() 和 defineEmits()

defineProps()在zbxk项目默认文件“HelloWorld.vue”中出现过,但是不能不完整。现在定义一个父主件与一个子主件来稍微说明一下。
父主件TestParent.vue,代码如下:

<script setup>
import { ref } from 'vue'
import child from '/src/components/TestChild1.vue'

const msg = ref('hello')

const updateMsg = (m) => msg.value = m
</script>

<template>
  <div>
    <div>父主件:{{ msg }}</div>
    <child @update="updateMsg" :msg="msg"></child>
  </div>
</template>

子主件TestChild1.vue代码如下:

<script setup>

const p = defineProps({
  msg: {
    type: String,
    required: true
  }
})

const emit = defineEmits(['update'])

const updateMsg = () => { emit('update', '修改后消息:' + p.msg) }

</script>

<template>
  <div>
    <div>子主件:{{ msg }}</div>
    <div><button @click="updateMsg">修改消息</button></div>
  </div> 
</template>

添加路由代码:

{
      path: '/testParent',
      name: 'testParent',
      // route level code-splitting
      // this generates a separate chunk (About.[hash].js) for this route
      // which is lazy-loaded when the route is visited.
      component: () => import('../views/testParent.vue')
}

运行效果如下图:
在这里插入图片描述点击“修改”消息按钮后,显示如下图:
在这里插入图片描述
先看父主件中的重要代码:

<child @update=“updateMsg” :msg=“msg”></child>

@update相当于是子主件中defineEmits定义的时间,"updateMsg"是父主件中的处理函数;:msg冒号后的msg相当于是defineProps定义的子主件入参,"msg"是绑定的父主件的响应式变量。

再看子主件中的重要带啊

emit(‘update’, ‘修改后消息:’ + p.msg)

这是子主件中触发自定事件“update”。

三、生命周期钩子

VUE3的生命周期钩子与VUE2相比,变化还是挺大的,所以这里罗列一下。

1.onMounted()

注册一个回调函数,在组件挂载完成后执行。

2.onUpdated()

注册一个回调函数,在组件因为响应式状态变更而更新其 DOM 树之后调用。

3.onUnmounted()

注册一个回调函数,在组件实例被卸载之后调用。

4.onBeforeMount()

注册一个钩子,在组件被挂载之前被调用。

5.onBeforeUpdate()

注册一个钩子,在组件即将因为响应式状态变更而更新其 DOM 树之前调用。

6.onBeforeUnmount()

注册一个钩子,在组件实例被卸载之前调用。

7.onErrorCaptured()

注册一个钩子,在捕获了后代组件传递的错误时调用。
错误可以从以下几个来源中捕获:

  • 组件渲染
  • 事件处理器
  • 生命周期钩子
  • setup() 函数
  • 侦听器
  • 自定义指令钩子
  • 过渡钩子

这个钩子带有三个实参:错误对象、触发该错误的组件实例,以及一个说明错误来源类型的信息字符串。

8.onRenderTracked()

注册一个调试钩子,当组件渲染过程中追踪到响应式依赖时调用。

这个钩子仅在开发模式下可用,且在服务器端渲染期间不会被调用。

9.onRenderTriggered()

注册一个调试钩子,当响应式依赖的变更触发了组件渲染时调用。

这个钩子仅在开发模式下可用,且在服务器端渲染期间不会被调用。

10.onActivated()

注册一个回调函数,若组件实例是 缓存树的一部分,当组件被插入到 DOM 中时调用。

11.onDeactivated()

注册一个回调函数,若组件实例是 缓存树的一部分,当组件从 DOM 中被移除时调用。

12.onServerPrefetch()

注册一个异步函数,在组件实例在服务器上被渲染之前调用。

这个系列不涉及服务端渲染。

13.代码演示

新建TestView2.vue文件,代码如下:

<script setup>
import { ref, onMounted, onUpdated, onUnmounted, onBeforeMount,
  onBeforeUpdate, onBeforeUnmount, onErrorCaptured, onRenderTracked,
  onRenderTriggered, onActivated, onDeactivated, onServerPrefetch } from 'vue'

  import child from '/src/components/TestChild.vue'

onMounted(() => {
  console.log("onMounted")
})

//调用两次,证明钩子函数可以重复注册
onMounted(() => {
  console.log("onMounted2")
})

onUpdated(() => {
  console.log("onUpdated")
})

onUnmounted(() => {
  console.log("onUnmounted")
})

onBeforeMount(() => {
  console.log("onBeforeMount")
})

onBeforeUpdate(() => {
  console.log("onBeforeUpdate")
})

onBeforeUnmount(() => {
  console.log("onBeforeUnmount")
})

onErrorCaptured(() => {
  console.log("onErrorCaptured")
})

onRenderTracked(() => {
  console.log("onRenderTracked")
})

onRenderTriggered(() => {
  console.log("onRenderTriggered")
})

onActivated(() => {
  console.log("onActivated")
})

onDeactivated(() => {
  console.log("onDeactivated")
})

onServerPrefetch(() => {
  console.log("onServerPrefetch")
})

const count = ref(0)

const view = ref(true)
</script>

<template>
  <div>
    <div>数量:{{ count }}</div>
    <div><button @click="count++">自增改变状态</button></div>

    <KeepAlive>
      <child v-if="view"></child>
    </KeepAlive>
    <div><button @click="view=!view">改变KeepAlive</button></div>
  </div> 
</template>

新增子组件TestChild2.vue,代码如下:

<script setup>
import {  onActivated, onDeactivated } from 'vue'

onActivated(() => {
  console.log("onActivated")
})

onDeactivated(() => {
  console.log("onDeactivated")
})

</script>

<template>
  <div>
    <div>子组件</div>
  </div> 
</template>

添加路由代码:

{
      path: '/test2',
      name: 'test2',
      // route level code-splitting
      // this generates a separate chunk (About.[hash].js) for this route
      // which is lazy-loaded when the route is visited.
      component: () => import('../views/TestView2.vue')
}

运行效果如下图:
在这里插入图片描述终端输出如下:
在这里插入图片描述
共执行了注册的5个钩子,正如代码注释里所说,钩子函数可以重复注册。点击“自增改变状态”按钮,终端输出如图:
在这里插入图片描述
共执行了注册的3个钩子。再点击“改变KeepAlive”按钮,终端输出如图:
在这里插入图片描述
又执行了注册的4个钩子。再点击一次“改变KeepAlive”按钮,终端输出如图:
在这里插入图片描述
“改变KeepAlive”按钮重点是演示的onActivated与onDeactivated钩子。点击其它有路由跳转的链接,离开TestView2组件,终端输出如图:
在这里插入图片描述
从终端输出来看,除onServerPrefetch()钩子以外,都有调用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1059698.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

公众号突破2个限制技巧

许多用户在注册公众号时可能会遇到“公众号显示主体已达上限”的问题。这是因为在2018年11月16日对公众号注册数量进行了调整&#xff0c;具体调整如下&#xff1a;1、个人主体注册公众号数量上限从2个调整为1个。2、企业主体注册公众号数量上限从5个调整为2个。这意味着&#…

vs2015 执行后出来空白界面的解决

为什么在visual studio上写的代码点击开始执行&#xff0c;出来的是空白界面&#xff1f;(代码没问题)? - 知乎 Visual Studio 2015 - 新建 C/C 项目 (Project)_vs2015创建一个c项目-CSDN博客

微信小程序点单左右联动的效果实现

微信小程序点单左右联动的效果实现 原理解析&#xff1a;   点击左边标签会跳到右边相应位置&#xff1a;点击改变rightCur值&#xff0c;转跳相应位置滑动右边&#xff0c;左边标签会跳到相应的位置&#xff1a;监听并且设置每个右边元素的top和bottom&#xff0c;再判断当…

Linux内存管理 | 一、内存管理的由来及思想

我的圈子&#xff1a; 高级工程师聚集地 我是董哥&#xff0c;高级嵌入式软件开发工程师&#xff0c;从事嵌入式Linux驱动开发和系统开发&#xff0c;曾就职于世界500强企业&#xff01; 创作理念&#xff1a;专注分享高质量嵌入式文章&#xff0c;让大家读有所得&#xff01; …

Linux系统常用指令篇---(一)

Linux系统常用指令篇—(一) 1.cd指令 Linux系统中&#xff0c;磁盘上的文件和目录被组成一棵目录树&#xff0c;每个节点都是目录或文件。 语法:cd 目录名 功能&#xff1a;改变工作目录。将当前工作目录改变到指定的目录下。 (简单理解为进入指定目录下) 举例: cd .. : 返…

maven 初学

1. maven 安装 配置安装 路径 maven 下载位置: D:\software\apache-maven-3.8.6 默认仓库位置: C:\Users\star-dream\.m2\repository 【已更改】 本地仓库设置为&#xff1a;D:\software\apache-maven-3.8.6\.m2\repository 镜像已更改为阿里云中央镜像仓库 <mirrors>…

文件编码格式

一、问题场景 笔者在写controller层出现了一些小问题&#xff1a;测试controller层的一些请求的时候&#xff0c;后端控制台打印的是乱码&#xff0c;网上找了很多说改UTF-8的&#xff0c;但是我去设置里面全部都改为UTF-8了&#xff0c;结果仍然无济于事&#xff0c;甚至还把…

flink自定义窗口分配器

背景 我们知道处理常用的滑动窗口分配器&#xff0c;滚动窗口分配器&#xff0c;全局窗口分配器&#xff0c;会话窗口分配器外&#xff0c;我们可以实现自己的自定义窗口分配器&#xff0c;以实现我们的自己的窗口逻辑 自定义窗口分配器的实现 package wikiedits.assigner;i…

camtasia 2023怎么导出mp4

MP4是常见的视频格式之一&#xff0c;那么使用电脑录屏软件Camtasia完成对视频的剪辑后&#xff0c;如何将其导出为MP4格式保存在我们的电脑中呢&#xff1f; 1.剪辑好视频后&#xff0c;我们找到软件界面右上角的“导出”按钮。 Camtasia Studio- 2023 win-安装包&#xff1a…

【数据结构】布隆过滤器

布隆过滤器的提出 在注册账号设置昵称的时候&#xff0c;为了保证每个用户昵称的唯一性&#xff0c;系统必须检测你输入的昵称是否被使用过&#xff0c;这本质就是一个key的模型&#xff0c;我们只需要判断这个昵称被用过&#xff0c;还是没被用过。 方法一&#xff1a;用红黑…

C/C++学习 -- 分组加密算法(DES算法)

数据加密标准&#xff08;Data Encryption Standard&#xff0c;DES&#xff09;是一种对称密钥加密算法&#xff0c;是信息安全领域的经典之作。本文将深入探讨DES算法的概述、特点、原理&#xff0c;以及提供C语言和C语言实现DES算法的代码案例。 一、DES算法概述 DES算法是…

【网络安全---XSS漏洞(1)】XSS漏洞原理,产生原因,以及XSS漏洞的分类。附带案例和payload让你快速学习XSS漏洞

一&#xff0c;什么是XSS漏洞&#xff1f; XSS全称&#xff08;Cross Site Scripting&#xff09;跨站脚本攻击&#xff0c;为了避免和CSS层叠样式表名称冲突&#xff0c;所以改为了XSS&#xff0c;是最常见的Web应用程序安全漏洞之一&#xff0c;位于OWASP top 10 2013/2017年…

idea配置文件属性提示消息解决方案

在项目文件路径下找到你没有属性提示消息的文件 选中&#xff0c;ok即可 如果遇到ok无法确认的情况&#xff1a; 在下图所示位置填写配置文件名称即可

lv7 嵌入式开发-网络编程开发 06 socket套接字及TCP的实现框架

目录 1 socket套接字 1.1 体系结构的两种形式 1.2 几种常见的网络编程接口 1.3 socket套接字 2 socket常用API介绍 2.1 API 2.2 地址族结构体 2.3 套接字类型 2.4 socket套接字 3 TCP通信的实现过程 4 练习 1 socket套接字 1.1 体系结构的两种形式 网络的体系结构 …

想要精通算法和SQL的成长之路 - 二叉树的判断问题(子树判断 | 对称性 | 一致性判断)

想要精通算法和SQL的成长之路 - 二叉树的判断问题 前言一. 相同的树二. 对称二叉树三. 判断子树 前言 想要精通算法和SQL的成长之路 - 系列导航 一. 相同的树 原题链接 这题目典型的递归题&#xff1a; 如果两个节点都是null&#xff0c;我们返回true。如果两个节点一个nul…

【Linux】—— 详解软硬链接

前言&#xff1a; 本期&#xff0c;我将要给大家讲解的是有关 Linux下软硬链接的相关知识&#xff01;&#xff01;&#xff01; 目录 前言 &#xff08;一&#xff09;理解硬链接 1.什么是硬链接 2.创建硬链接 3.硬链接的使用场景 &#xff08;二&#xff09;理解软链接…

麦田物语学习

设置预设 将对一个物体的操作保存下来&#xff0c;直接用于其他的物体&#xff0c;比较省力 当设置好一个物体后点击箭头所指的地方&#xff0c;保存预设&#xff0c;在其他物体的面板里点击预设使用 sprite renderer 图片渲染顺序参考点 修改游戏的渲染方式 修改为按照 y 轴…

操作系统学习笔记2

文章目录 1、进程管理逻辑图2、进程的由来 参考视频&#xff1a; 操作系统 1、进程管理逻辑图 2、进程的由来

芯驰D9评测(2)--系统环境配置连接

linux开发板的软件开发三件套&#xff1a; 建立连接-->建立交叉编译环境-->建立驱动开发环境。 如果我们不涉及镜像的深度定制&#xff0c;只是平台化应用的话 1. 建立串口连接 查看手册&#xff0c; 获取接口定义说明&#xff1a; 板载一共两个端子&#xff0c;三个…

python二次开发CATIA:文字轮廓草图

CATIA V5 版本的草图中&#xff0c;并没有文字轮廓的创建命令。通常的做法是&#xff0c;再Drawing 文件中创建所需文本-->将 Drawing 文件另存为 dwg / dxf 格式-->打开另存的文件&#xff0c;文字已转为轮廓线条-->复制线条并粘贴到草图中。 本例中&#xff0c;基于…