一、基本概述
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>
复制