此总结是我看尚硅谷视频总结的,所以可能会有总结不到位或不清楚的情况
适合学过的人回来复习的时候看
一、 ref 创建:响应式数据
ref 可以定义:基本类型、对象类型的响应式数据
1)ref 创建:基本类型的响应式数据
- vue3项目,在setup中创建的变量,例如 let num = 100 中的num默认不是响应式数据
- 利用 ref 可以创建基本类型的响应式数据
2)ref 创建:对象类型的响应式数据
若 ref 接收的是对象类型,内部其实也是调用了 reactive 函数
<script lang="ts" setup name="Person111">
import { ref } from "vue"
// 数据
let car = ref({ brand: '奔驰', price: 100})
let game = ref([
{ id: 10001, name: '原神'},
{ id: 10002, name: '双人成行'},
{ id: 10003, name: '头七怪谈'}
])
// 方法
function changePrice() { // 改变汽车价格
car.value.price += 10
console.log(car.value.price)
}
function changeGame() { // 改变游戏名称
game.value[1].name = '纸嫁衣'
}
function changeCar() { // 更改车数据
// car.value.brand = '小电驴'
// car.value.price = 0.3
// 上面两行的效果等同下面的这个代码,即使把整个对象赋给car.value,car也不会失去响应式
car.value = { '小电驴', price: 0.3 }
}
</script>
3)volar 插件自动添加 .value
vscode左下角点击设置,搜索Dot Value,勾选,如下图
4)customRef 自定义 ref
customRef: 创建一个自定义的ref,并对其依赖项跟踪和更新触发进行逻辑控制
举例: 想要1s后(有延迟效果)响应式数据更新
注意:下例中 clearTimeout(timer)起到防抖效果
useSumRef.ts
import { customRef } from 'vue'
export default function (initValue: string, delay: number) {
// 使用Vue提供的customRef定义响应式数据
// track:跟踪 trigger:触发
let msg = customRef((track, trigger) => {
let timer: number
return {
// get何时调用? -- msg被读取时
get(){
track() // 告诉Vue数据msg很重要,你要对msg进行持续关注,一旦msg变化就去更新
return initValue
},
// set何时调用? -- msg被修改时
set(value){
clearTimeout(timer)
timer = window.setTimeout(() => {
initValue = value
trigger() // 通知Vue数据msg变化了
}, delay)
}
}
})
return { msg }
}
App.vue
<template>
<div class="app">
<h2>{{ msg }}</h2>
<input type="text" v-model="msg">
</div>
</template>
<script setup lang="ts" name="App">
import {ref} from 'vue'
import useMsgRef from './useMsgRef'
// 使用Vue提供的默认ref定义响应式数据,数据一变,页面就更新
// let msg = ref('你好')
// 使用useMsgRef来定义一个响应式数据且有延迟效果
let {msg} = useMsgRef('你好',1000)
</script>
二、 reactive 创建:响应式数据
- reactive 只能创建对象类型的响应式数据
- 在JS中可以直接操作对象类型数据,不需要.value
1)reactive 创建对象类型的响应式数据
<template>
<div class="person">
<h2>汽车信息:一辆{{ car.brand }}品牌的车,价格为{{ car.price }}万</h2>
<button @click="changePrice">改变汽车价格</button>
<h2>游戏信息列表</h2>
<ul>
<li v-for="item in game" :key="item.id">{{ item.name }}</li>
</ul>
<button @click="changeGame">改变游戏名称</button>
<h4>深层次{{ shen.a.b.id }}</h4>
<button @click="changeShen">测试</button>
</div>
</template>
<script lang="ts" setup name="Person111">
import { reactive } from "vue"
// 数据
let car = reactive({ brand: '奔驰', price: 100})
let game = reactive([
{ id: 10001, name: '原神'},
{ id: 10002, name: '双人成行'},
{ id: 10003, name: '头七怪谈'}
])
let shen = reactive({
a: {
b: {
id: 4
}
}
})
// 方法
function changePrice() {
car.price += 10
console.log(car.price)
}
function changeGame() {
game[1].name = '纸嫁衣'
}
function changeShen() {
shen.a.b.id = 100
}
</script>
2)reactive更新对象数据
注意: reactive重新分配对象 ,会失去响应式
场景:
<button @click="changeCar">点击修改车数据</button>
...
let car = ref({ brand: '奔驰', price: 100})
...
function changeCar() {
// { brand: '小电驴', price: 0.3 } ,要更新这个信息给car
}
方法一:手动赋值
function changeCar() {
// { brand: '小电驴', price: 0.3 } ,要更新这个信息给car
// 弊端:从后端返回的数据可以一个对象里有很多属性,一个一个赋值也太麻烦了
Person.name = 'lisi'
Person.age = 20
}
方法二:对象整体赋值
function changeCar() {
// { brand: '小电驴', price: 0.3 } ,要更新这个信息给car
// 下面这个写法页面可以更新, 而且这个写法car不会失去响应式更新
Object.assign(car, { brand: '小电驴', price: 0.3})
// 下面是两种错误写法
// car = { brand: '小电驴', price: 0.3} // 这么写,数据更新了,页面不更新,不是响应式的了
// car = reactive({ brand: '小电驴', price: 0.3}) // 这么写页面不更新的
}
3)toRefs 与 toRef
<template>
<div class="box">
<div>姓名:{{ person.name }}</div>
<div>年龄:{{ person.age }}</div>
<br>
<button @click="changeName">点击修改姓名</button>
<button @click="changeAge">点击修改年龄</button>
<div>叫啥:{{ test }}</div>
</div>
</template>
<script lang="ts" setup name="Person111">
import { ref, reactive, toRefs, toRef } from "vue"
// 数据
let person = reactive({
name: '张三',
age: 18
})
let { name, age } = toRefs(person)
console.log(name) // 转换为了ref基本数据类型的响应式数据
console.log(age) // 相当于是把每一项都拆开了,但是每一项都还是ref响应式的
let test = toRef(person, 'name') // 这个当然也是响应式的
function changeName() {
// person.name = 'zhang-san'
name.value = 'zhang-san'
}
function changeAge() {
// person.age += 1
age.value += 1
}
</script>
<style>
.box {
padding: 20px;
background-color: skyblue;
box-shadow: 0 0 10px;
border-radius: 20px;
}
button {
margin-right: 20px;
}
</style>
三、 ref 和 reactive 的区别
四、其他补充
1)shallowRef、shallowReactive
1. shallowRef
举例:
运行效果:只有 “sum+1” 和 “修改整个人” 的功能能用,另外两个无效
2. shallowReactive
举例:
运行效果:只有 “修改品牌” 和 “修改整个车” 功能能用,另外两个无效
3. 总结
2)readonly 与 shallowReadonly
1. readonly
效果:
- original显示什么,readOnlyCopy就显示什么,original修改,readOnlyCopy也会跟着修改
- original可以修改自己的值,readOnlyCopy什么都不能修改,只能读
2. shallowReadonly
效果:
- original显示什么,shallowReadOnlyCopy就显示什么,original修改shallowReadOnlyCopy也会跟着修改
- original可以修改自己的值,shallowReadOnlyCopy第一层数据不能修改,但是深层次(第二层、第三层…)数据能够修改
举例:
- shallowReadOnlyCopy不能修改“name”和“hobby整体”,但能修改hobby.eat和hobby.sport的值
3)toRaw 与 markRaw
1. toRaw
使用示例: