一、基本概述
Vue 3中的ref是一个用于创建响应式引用的API,它是Vue 3引入的Composition API的一部分。ref的作用是包装一个基本类型数据或一个对象,使得该数据或对象的改变能触发视图的更新。需要在页面变化的数据做成响应式的
二、基本类型的响应式数据
对我们之前的代码修改,使其中的名字和年龄为响应式的数据
<template>
<div class="person">
<h2>姓名:{{ name}}</h2>
<h2>年龄:{{age}}</h2>
<h2>地址:{{address}}</h2>
<button @click="showTel">查看联系方式</button>
<button @click="changeName">改名字</button>
<button @click="changeAge">改年龄</button>
</div>
</template>
<script lang='ts'setup name="Person">
import { ref } from 'vue';
//数据
let name=ref("wang-wu")//用ref包装,此时的name是响应式的
let age=ref(18) //用ref包装,此时的age是响应式的
let tel='1388888888'
let address='湖南省长沙市'
console.log(name)
console.log(age)
console.log(tel)
console.log(address)
//方法
function changeName(){
name.value='zhAng-san'
}
function changeAge(){
age.value++
}
function showTel(){
alert(tel)
}
</script>
<style scoped>
.person{
background-color:skyblue;/*设置背景颜色为天蓝色,盒子模糊阴影为10像素,边框圆角为10像素,内边距为20像素 */
box-shadow: 0 0 10px;
border-radius: 10px;
padding: 20px;
}
button{
margin: 0 5px; /*按钮的外边距5px*/
}
</style>
可以看出,通过ref包装后,数据变成响应式数据了
通过控制台输出可以看到,名字和年龄被包装成为了一个RefImpl的对象,在js里面操作年龄和名字的值一定要用.value调用他们的值。
三、对象类型的响应数据(新建了一个car.vue)
快捷键:鼠标选中要包裹的内容,然后shift+圆括号,再在前面加reactive。
非响应式的对象类型:
<template>
<div class="car">
<h2>一辆{{car.brand}}车的价值{{car.price}}万</h2>
<button @click="changPrice">修改汽车的价格</button>
</div>
</template>
<script lang='ts'setup name="car">
let car={brand:'奔驰',price:100} //定义一个汽车对象
function changPrice(){ //修改汽车的价格
car.price+=10
console.log(car.price)
}
</script>
<style scoped>
.car{
background-color: violet;
}
</style>
响应式的对象类型,使用reactive包装对象,用法和基本数据类型的ref类似。
<template>
<div class="car">
<h2>一辆{{car.brand}}车的价值{{car.price}}万</h2>
<button @click="changPrice">修改汽车的价格</button>
</div>
</template>
<script lang='ts'setup name="car">
import { reactive } from 'vue'//导入reactive包,添加这一行
let car=reactive({brand:'奔驰',price:100}) //定义一个汽车对象,用reactive方法把对象包装起来,和基本类型的ref类似
let car2={brand:'宝马',price:450}
console.log(car)
console.log(car2)
function changPrice(){ //修改汽车的价格
car.price+=10
}
</script>
<style scoped>
.car{
background-color: violet;
}
</style>
通过控制台分别打印car和car2两个对象,可以看到,响应式的对象被Proxy包装了,而car2还是单纯的对象。
对象数组类型响应式和对象一样,用reactive包裹对象数组:
<template>
<div class="car">
<h2>汽车信息:一辆{{car.brand}}车的价值{{car.price}}万</h2>
<button @click="changPrice">修改汽车的价格</button>
<h2>游戏列表</h2>
<ul>
<li v-for="g in games" :key="g.id">{{g.name}}</li>
<!--v-for类似后端的遍历,g是形参,games是数据类型,遍历时候需要特殊的key(键),
冒号一定要有,冒号的含义是把后面的东西当作js语句去解析,完整指令是v-bind,可以简写为冒号-->
</ul>
<button @click="changeFirstGame">修改游戏名</button>
</div>
</template>
<script lang='ts'setup name="car">
import { reactive } from 'vue'//导入reactive包,添加这一行
let car=reactive({brand:'奔驰',price:100}) //定义一个汽车对象,用reactive方法把对象包装起来,和基本类型的ref类似
let car2={brand:'宝马',price:450}
let games=reactive([
{id:'01',name:"王者荣耀"},
{id:'02',name:"原神"},
{id:'03',name:"瓦罗兰特"}
])
function changPrice(){ //修改汽车的价格
car.price+=10
}
function changeFirstGame(){
games[0].name="和平精英"
}
</script>
<style scoped>
.car{
background-color: violet;
}
button{
margin: 10px;
}
li{
size: 10px;
}
</style>
点击按钮成功将第一个游戏名改成了和平精英
用reactive包裹的都是响应式的,ref可以定义基本类型、对象类型的响应式数据,reactive只能定义对象类型的响应数据,ref的使用范围更加广泛。
但是使用ref包裹对象时,修改对象的值要麻烦一点,例如car.value.price
用ref包裹的对象打印出来,可以看到里面又是Proxy,ref也是借助reactive来处理对象的响应式的。
ref包裹的响应式要自己去写点value,可以在插件里面设置使得ref包裹的数据系统自动帮我们去加.value,在设置==>用户==>拓展==>Volar
在Volar中找到这个选项打勾,可以自动补全.value。
<template>
<div class="car">
<h2>汽车信息:一辆{{car.brand}}车的价值{{car.price}}万</h2>
<button @click="changPrice">修改汽车的价格</button>
<button @click="changCar">修改汽车</button>
<h2>游戏列表</h2>
<ul>
<li v-for="g in games" :key="g.id">{{g.name}}</li>
<!--v-for类似后端的遍历,g是形参,games是数据类型,遍历时候需要特殊的key(键),
冒号一定要有,冒号的含义是把后面的东西当作js语句去解析,完整指令是v-bind,可以简写为冒号-->
</ul>
<button @click="changeFirstGame">修改游戏名</button>
</div>
</template>
<script lang='ts'setup name="car">
import { reactive } from 'vue'//导入reactive包,添加这一行
import{ref}from 'vue' //导入ref包
let car=reactive({brand:'奔驰',price:100}) //定义一个汽车对象,用reactive方法把对象包装起来,和基本类型的ref类似
let car2=ref({brand:'宝马',price:450})
console.log(car)
console.log(car2)
let games=reactive([
{id:'01',name:"王者荣耀"},
{id:'02',name:"原神"},
{id:'03',name:"瓦罗兰特"}
])
function changPrice(){ //修改汽车的价格
car.price+=10
}
function changCar(){ //修改汽车的价格
//car2=({brand:'奥迪',price:300}),这么写不更新
//car2=reactive({brand:'奥迪',price:300}),这么写不更新
Object.assign(car2.value,{brand:'奥迪',price:300})//这么写可以可以更新
//或者用ref的.value
car2.value={brand:'奥迪',price:300}
}
function changeFirstGame(){
games[0].name="和平精英"
}
</script>
<style scoped>
.car{
background-color: violet;
}
button{
margin: 10px;
}
li{
size: 10px;
}
</style>
Vue中的toRef和toRefs函数是用于处理响应式数据的两种方式。
toRef函数用于将单个属性转换为响应式数据。它接受一个参数,即要转换的属性名,并返回一个ref对象,该对象包含一个value属性,用于获取和设置响应式数据的值。通过在模板中直接使用属性名或通过在JavaScript代码中访问ref对象的value属性,可以获取和更新响应式数据的值。
toRefs函数用于将整个响应式对象转换为普通对象,同时保持每个属性的响应式连接。它接受一个响应式对象作为参数,并返回一个包含多个ref对象的数组,每个ref对象对应原始对象的一个属性。通过访问返回的ref对象的value属性,可以获取和更新响应式数据的值。
总的来说,toRef和toRefs的主要区别在于它们处理响应式数据的方式不同。toRef是针对单个属性进行操作,而toRefs则是将整个响应式对象转换为普通对象。在Vue中,可以根据需要选择使用toRef或toRefs来处理响应式数据。
toRef:
import { reactive, toRef } from 'vue';
const state = reactive({
count: 0
});
const countRef = toRef(state, 'count');
// 在模板中直接使用属性名
<template>
<div>
<p>{{ count }}</p>
<button @click="count++">增加</button>
</div>
</template>
toRefs:
import { reactive, toRefs } from 'vue';
const state = reactive({
count: 0,
name: 'Vue'
});
const refs = toRefs(state);
// 在模板中直接使用属性名
<template>
<div>
<p>{{ count }}</p>
<p>{{ name }}</p>
<button @click="count++">增加</button>
<button @click="name = 'Vue 3'">更改名称</button>
</div>
</template>