Vue3 学习总结补充(一)

news/2024/11/8 18:46:05/

文章目录

      • 1、Vue3中为什么修改变量的值后,视图不更新?
      • 2、使用 ref 还是 reactive?
      • 3、reactive 为什么会有响应性连接丢失情况?
      • 4、watch的不同使用方法
      • 5、watchEffect和 watch 的区别
        • 区别1:数据源的区别
        • 区别2:获取新值和旧值的区别
        • 区别3:惰性执行和非惰性(立即)执行的区别
      • 6、watchEffect和 watch 使用注意点
      • 7、使用ref修改DOM元素

1、Vue3中为什么修改变量的值后,视图不更新?

<template><div>app</div><div class="container">{{ msg1 }}{{ msg2 }}</div><button @click="say()">按钮</button>
</template><script setup>
import { reactive, ref } from 'vue'let msg1 = 'hi'
let msg2 = ref('hello')
const say = () => {console.log(msg1) // himsg1 = 'hi vue3' // 这里修改 msg1的值,console.log('msg1', msg1) // 这里可以获取到修改后的值,hi vue3,但是视图中的 msg1 没有更新,原因是 msg1不是响应式的。msg2.value = 'hello vue3 ' // 这里修改 msg2的值console.log('msg2', msg2) // 这里可以获取到修改后的值,hello vue3,视图中的 msg2 也会更新,原因是 msg2是响应式的。
}
</script>

2、使用 ref 还是 reactive?

  • reactive 可以转换【复杂数据类型】(例如:对象、数组等) 成为响应式数据,但是不支持简单数据类型(例如:字符串、数值、布尔值);
  • ref 可以转换【简单数据类型】或【复杂数据类型】 为响应式数据,但是操作的时候需要 .value

如果能确定数据是复杂数据类型,并且定义的属性也是知道的,则可以使用 reactive 转成响应式数据,如果不满足以上条件,则使用 ref

代码如下:

    // 1. 明确login对象有两个字段,需要使用 reactiveconst login = reactive({username: '',password: ''})// 2. 后台返回的数据对象const data = ref(null)const res = await axios.get('/login')data.value = res.data // 把不是响应式的 res 赋值给 响应式data中的value,data仍然是响应式的。// 3. 思考:为什么以下方式不可行?const data = reactive({ })const res = await axios.get('/login')data = res // 由于res 不是响应式的,然后把不是响应式的 res 赋值给 响应式的data ,那么data就不是响应式的了。

3、reactive 为什么会有响应性连接丢失情况?

响应性连接丢失的意思是:一个响应式对象原本是响应式的,但随意通过 “赋值”操作,把一个非响应式的数据,赋值给响应式的数据对象,这个响应式对象就变成了非响应式数据对象了。

reactive API有两个限制性情况:

  • 情况1:reactive 仅支持复杂数据类型(对象、数组等),对简单数据类型(字符串、数值、布尔值)等原始类型不支持。

  • 情况2:因为Vue 的响应式系统是通过属性访问进行跟踪的,必须始终保持对该响应式对象的相同引用。所以不可以随意地“替换(赋值)”一个响应式对象,因为这将导致对初始引用的响应性连接丢失。

    也就是说:如果重新赋值或解构赋值,就会丢失原来响应式对象的引用地址,然后变成了一个新的引用地址,因为这个新的引用地址指向的对象是没有经过 reactive 处理的,所以就是一个普通对象,而不是响应式对象。

❌ 响应性连接丢失 代码举例1:

    const data = reactive({ })const res = await axios.get('/login')data = res // 由于res 不是响应式的,然后把不是响应式的 res 赋值给 响应式的data ,那么data就不是响应式的了

❌ 响应性连接丢失 代码举例2:

// 将响应式对象的属性直接赋值或解构赋值时,或是将该属性传入一个函数时,也会失去响应性连接let dataCount = reactive({ count: 0 })// 响应式对象的属性直接赋值时,响应式对象的属性响应性连接丢失,也就是说:dataCount.count 失去响应式连接,但不会影响 dataCount (dataCount仍然是响应式数据对象)
let num = dataCount.count // 响应式对象的属性值 直接赋值给了 num
num++// 响应式对象属性解构时,响应式对象属性(dataCount.count)响应性连接丢失,但不会影响 dataCount
let { count } = dataCount // 响应式对象的属性解构赋值
count++// change函数接收一个普通数字,将无法跟踪 dataCount.count 的变化, dataCount.count失去响应性连接
const change = (item) => {console.log(item)
}
change(dataCount.count)

4、watch的不同使用方法

watch 第一个参数:不同形式的数据源,

  • 可以是 ref(含计算属性)
  • 一个getter函数
  • 一个响应式对象
  • 或多个数据源组成的数组。

注意: watch不能侦听到响应式对象的属性值,比如:watch(data.count,()=>{ }),可以提供一个getter函数进行返回响应式对象的属性值。

watch 第二个参数:回调函数,当数据源发生变化时,执行回调函数

watch 第三个参数【可选】:是一个配置项,

  • deep 用于强制深度遍历
  • immediate 用于立即执行第二个参数中的回调函数
  • flush 用于调整回调函数的刷新时机
  • onTrack / onTrigger 调试侦听器的依赖

watch 的五种不同使用方法如下:

<template><div>app</div><div>{{ count }}</div><button @click="count++">累加</button>
</template><script setup>
import { ref, reactive, watch } from 'vue'const count = ref(0)
const obj = reactive({name: 'xiaozhu',age: 18,info: {height: 180,weight: 70,},
})// 使用方法1:第一个参数为 ref
watch(count, (newVal, oldVal) => {console.log('newVal', newVal) // 累加后 新的值console.log('oldVal', oldVal) // 累加前 旧的值
})// 使用方法2:第一个参数为 getter函数
watch(() => obj.age,(newVal, oldVal) => {console.log('newVal', newVal) // 20console.log('oldVal', oldVal) // 18}
)
setTimeout(() => {obj.age = 20
}, 1000)// 使用方法3:第一个参数为 一个响应式对象中的 简单数据类型
watch(() => obj.name, // name为obj对象中的一个字符串类型(newVal, oldVal) => {console.log('改变了')console.log('obj.name', obj.name) // 筱竹console.log('newVal', newVal) // 筱竹console.log('oldVal', oldVal) // xiaozhu}
)
setTimeout(() => {obj.name = '筱竹'
}, 1000)// 使用方法4:第一个参数为 一个响应式对象中的 复杂数据类型时,需要开启深度监听(设置deep选项)
watch(() => obj.info, // info 为obj对象中的一对象类型(newVal, oldVal) => {console.log('obj.info.height', obj.info.height) // 筱竹console.log('newVal', newVal) // 筱竹console.log('oldVal', oldVal) // xiaozhu},{ deep: true } // 开启深度监听
)
setTimeout(() => {obj.info.height = 175
}, 1000)// 使用方法5:第一个参数为 多个数据源组成的数组
watch([count, obj], () => {console.log('count.value', count.value) // 点击 累加按钮后,count+1console.log('obj.info.weight', obj.info.weight) // 65
})
setTimeout(() => {obj.info.weight = 65
}, 1000)
</script>

5、watchEffect和 watch 的区别

区别1:数据源的区别

  • watch 是需要侦听一个数据源(ref、响应式对象等),当依赖数据更新时执行回调函数;
  • watchEffect 不需要设置侦听的数据源,而是自动收集依赖数据,当依赖数据更新时会立即执行回调函数
<template><div>app</div><div>{{ count }}</div><button @click="count++">累加</button>
</template><script setup>
import { ref, reactive, watch, watchEffect } from 'vue'const count = ref(0)//  watchEffect 和 watch 区别1:// watchEffect 不需要设置侦听的数据源,就可以自动收集依赖(以下可以自动收集 ref 数据源)
watchEffect(() => {console.log('count.value', count.value) 
})// watch 需要设置侦听的数据源,只有设置了数据源,才能侦听数据源的变化
watch(count, (newVal, oldVal) => {console.log('newVal', newVal) console.log('oldVal', oldVal) 
})
</script>

区别2:获取新值和旧值的区别

  • watch 在回调函数中获取到 新值(变化后的值)和 旧值(变化之前的值);
  • watchEffect 在回调函数中 只可以获取到新值(变化后的值),不能获取到 旧值(变化之前的值);
//  watchEffect 和 watch 区别2:// watchEffect 只能拿到 新值
watchEffect(() => {console.log('count.value', count.value) // 只能拿到 新值
})// watch 可以获取到 新值和 旧值
watch(count, (newVal, oldVal) => {console.log('newVal', newVal) // 累加后 新的值console.log('oldVal', oldVal) // 累加前 旧的值
})

区别3:惰性执行和非惰性(立即)执行的区别

  • watch 的回调函数具有一定的惰性 当第一次页面展示的时候不会执行,只有数据变化的时候才会执行(设置immediate 选项为true时可以变为非惰性(可以立即执行),页面首次加载就会执行;
  • watchEffect 的回调函数可以立即执行,没有惰性,页面的首次加载就会执行;
//  watchEffect 和 watch 区别3:
const todoId = ref(1)
const data = ref(null)// watchEffect 中的回调函数会立即执行,不需要指定 immediate: true
watchEffect(async () => {const response = await fetch(`https://jsonplaceholder.typicode.com/todos/${todoId.value}`)data.value = await response.json()
})// 在 watch 中想要立即执行回调函数,就需要 设置 immediate: true
// watch 默认是惰性的:仅当数据源变化时,才会执行回调。但在某些场景中,我们希望在创建侦听器时,立即执行一遍回调。举例来说,我们想请求一些初始数据,然后在相关状态更改时重新请求数据。
watch(todoId,async () => {const response = await fetch(`https://jsonplaceholder.typicode.com/todos/${todoId.value}`)data.value = await response.json()},{ immediate: true }
)

6、watchEffect和 watch 使用注意点

【注意点1】: 侦听器必须用同步语句创建:如果用异步回调创建一个侦听器,那么它不会绑定到当前组件上,必须手动停止侦听,以防止内存泄漏。例如:

// 它会自动停止 ( watch同理 )
watchEffect(() => {})// 这个则不会! ( watch同理 )
setTimeout(() => {watchEffect(() => {})
}, 100)// 要手动停止一个侦听器,请调用 watch 或 watchEffect 返回的函数:
const unwatch = watchEffect(() => {})// 当该侦听器不再需要时
unwatch()

【注意点2】: 需要异步创建侦听器的情况很少,请尽可能选择同步创建,如果需要等待一些异步数据,你可以使用条件式的侦听逻辑:

// 需要异步请求得到的数据
const info = ref(null)watchEffect(() => {if (info.value) {// 数据加载后执行某些操作...}
})

7、使用ref修改DOM元素

<template><div ref="ref_item">app</div><input type="button" value="修改DOM元素" @click="change()" />
</template><script setup>
import { ref, onMounted } from 'vue'const ref_item = ref(null)// 注意: 获取元素需要在Vue3 生命周期钩子 onMounted中获取,如果在 setup 中是获取不到的,因为setup中类似Vue2声明周期钩子函数中的beforeCreate和 created ,此时DOM还没生成,所以获取不到DOM。
onMounted(() => {// 获取DOM元素console.log('ref_item.value.innerText', ref_item.value.innerText) // app
})const change = () => {// 修改DOM元素的值ref_item.value.innerText = '你好 Vue3'console.log('ref_item.value.innerText', ref_item.value.innerText) // 你好 Vue3
}
</script>

http://www.ppmy.cn/news/34610.html

相关文章

第十三届蓝桥杯省赛 python B组复盘

文章目录前言主要内容&#x1f99e;试题 A&#xff1a;排列字母思路代码&#x1f99e;试题 B&#xff1a;寻找整数思路代码&#x1f99e;试题 C&#xff1a;纸张尺寸思路代码&#x1f99e;试题 D&#xff1a;数位排序思路代码&#x1f99e;试题 E&#xff1a;蜂巢思路代码&…

day74【代码随想录】二刷链表

文章目录前言一、重排链表&#xff08;力扣143&#xff09;二、旋转链表&#xff08;力扣61&#xff09;三、删除排序链表中的重复元素 II&#xff08;力扣82&#xff09;四、重复的DNA序列&#xff08;力扣187&#xff09;【滑动窗口】前言 1、重排链表 2、旋转链表 3、删除排…

第十四届蓝桥杯三月真题刷题训练——第 21 天

目录 第 1 题&#xff1a;灭鼠先锋 问题描述 运行限制 代码&#xff1a; 思路&#xff1a; 第 2 题&#xff1a;小蓝与钥匙 问题描述 答案提交 运行限制 代码&#xff1a; 思路 : 第 3 题&#xff1a;李白打酒加强版 第 4 题&#xff1a;机房 第 1 题&#xff1…

Java基础知识之HashMap的使用

一、HashMap介绍 HashMap是Map接口的一个实现类&#xff08;HashMap实现了Map的接口&#xff09;&#xff0c;它具有Map的特点。HashMap的底层是哈希表结构。 Map是用于保存具有映射关系的数据集合&#xff0c;它具有双列存储的特点&#xff0c;即一次必须添加两个元素&#xf…

JavaScript传参的6种方式

JavaScript传参的方式1. 传递基本类型参数2. 传递对象类型参数3. 使用解构赋值传递参数4. 使用展开运算符传递参数5. 使用可选参数6. 使用剩余参数JavaScript是一门非常灵活的语言&#xff0c;其参数传递方式也同样灵活。在本篇文章中&#xff0c;会详细介绍JavaScript中的参数…

传输层协议----UDP/TCP

文章目录前言一、再谈端口号端口号的划分认识知名端口号(Well-Know Port Number)两个问题nestatpidof二、UDP协议UDP协议端格式UDP的特点面向数据报UDP的缓冲区UDP使用注意事项基于UDP的应用层协议二、TCP协议TCP协议段格式可靠性问题确认应答(ACK)机制流量控制六个标志位PSHUG…

Vue趣味【Vue3+Element Plus+Canvas实现一个简易画板;支持导出为图片】

目录&#x1f31f;前言&#x1f31f;粉丝先看&#x1f31f;创建Vue3项目&#x1f31f;引入Element Plus&#x1f31f;实现代码&#xff08;详细注释&#xff09;&#x1f31f;写在最后&#x1f31f;JSON包里写函数&#xff0c;关注博主不迷路&#x1f31f;前言 哈喽小伙伴们&a…

Java开发一年不到,来面试居然敢开口要20K,面完连8K都不想给~

前言 我的好朋友兼大学同学老伍家庭经济情况不错&#xff0c;毕业之后没两年自己存了点钱加上家里的支持&#xff0c;自己在杭州开了一家网络公司。由于公司不是很大所以公司大部分的开发人员都是自己面试的&#xff0c;近期公司发展的不错&#xff0c;打算扩招也面试了不少人…