一、setup文件的认识
特点1:script 中间的内容就是一个对象
特点2:script 在第一层 定义的方法 或者 变量 => 就是这个对象 属性 => 顶层的绑定回被暴露给模板(模板可以直接使用这个变量)
二、什么是响应式api
处理 数据 => 我们把页面写的数据,需要动态改变的数据 => 叫做 响应式数据 => 数据改变视图中使用了这个数据,这个数据回对应的 响应式数据底层实现 => vue3 => Proxy
三、在vue3 中有哪些常用的响应式API?
响应式核心:
1、ref()
作用:将一个基本数据类型的数据变为响应式
语法:let 变量=ref(处理的数据)
<template>
<div>
<h2>响应式api</h2>
<h2>{{age}}</h2>
<button @click="addAge">change</button>
</div>
</template>
<script setup>
import {ref} from 'vue';
// ref 处理的数据
// 1 基本数据类型 => 通过vue2 响应式原理来实现Object.defineProperty()
// 2 处理的复杂的数据类型 => reactive()这个响应式api
let age=ref(29); // 通过ref 处理的数据 => 变成响应式
let data=ref({ages:50});
console.log(data,"data")
const addAge=()=>{
age.value+=1;
console.log(age);
}
</script>
<style>
</style>
2、reactive()
作用:将复杂的数据类型变成响应式数据<template>
<div>
<h2>响应式api</h2>
<h2>{{objP.name}}的年龄{{objP.age}}</h2>
<button @click="changeName">changeName</button>
<button @click="changeLike">changeLike</button>
</div>
</template>
<script setup>
import {reactive} from 'vue';
// 作用将复杂的数据类型变成响应式数据
let objP=reactive({
name:"小明",
age:8,
like:{eat:'🍎',play:['⚽']}
})
// reactive()代理数据类型 对象 特点
// 1 就是 proxy 代理可以将对象中第一层的属性变成响应式,不用递归,提供性能优化
// 2 就是 proxy 代理 数据是对象,这个对象中属性有深层次,他会实现懒代理
// 就是用户只有在使用了这个数据,才会将这个数据变为 响应式数据
console.log(objP);
const changeName=()=>{
objP.name="lisa"
objP.age+=1;
}
const changeLike=()=>{
objP.like.play=['🌏'];
console.log(objP.like); // 使用后深层次数据也变为响应式数据
}
</script>
<style>
</style>
3、readonly()
作用:处理的数据,只能读取不能修改,父组件给子组件数据
语法:let 数据 =readonly(默认数据)
<template>
<div>
<h2>readonly</h2>
<!-- 作用:处理的数据,只能读取不能修改,父组件给子组件数据
语法: let 数据 =readonly(默认数据)
-->
<h2>{{ obj.name }}</h2>
<button @click="change">修改数据</button>
</div>
</template>
<script setup>
import {readonly} from 'vue';
let obj=readonly({name:'lisa'}); // 通过proxy代理
console.log(obj)
const change=()=>{
obj.name="cici"; // 只读的,无法修改
}
</script>
<style>
</style>
4、watchEffect()
作用: 页面更新 就会触发watchEffect 处理函数
语法:watchEffect(( )=>{ })
特点:1 第一次默认执行 处理函数; 2 watchEffect 监听的数据,需要我们写到他的处理函数中,并且 可以监听多个; 3 watchEffect 监听的数据的改变,处理函数就会触发=》获取到最新的数据=》没有旧 的数据
<template>
<div>
<h2>watchEffect 副作用</h2>
<!--
作用: =》 页面更新 就会触发watchEffect 处理函数
语法:watchEffect(()=>{
})
-->
<h2>{{ name }}</h2>
<h2>{{ age }}</h2>
<button @click="addAge">年龄+1</button>
<button @click="changeName">修改name</button>
</div>
</template>
<script setup>
import {ref,watchEffect} from 'vue';
let age=ref(20);
let name=ref("lisa");
// watchEffect 特点
// 1 第一次执行 处理函数
// 2 watchEffect 监听的数据, 需要我们写到它的处理函数中,并且可以监听多个
// 3 watchEffect 监听数据的改变,获取到新的数据,没有旧数据
// watchEffect(()=>{
// console.log("页面更新了");
// console.log(age.value);// 监听 age 值,只要这个值发生改变,这个watchEffect 他的处理函数就是重新执行,获取到的最新的数据
// console.log(name.value);
// })
// 在watchEffect中做数据处理
watchEffect(()=>{
console.log('页面更新');
if(age.value>30){
console.log('200');
}
})
const addAge = ()=>{
age.value = age.value +1
}
const changeName =()=>{
name.value='小明'
}
</script>
<style>
</style>
5、watch()
作用:侦听一个或多个响应式数据源,并在数据源变化时调用所给的回调函数。
语法:watch(数据源,回调函数,配置项)
数据源:监听的数据源、
回调函数:(newVal,oldVal)=>{console.log(newVal,oldVal); // 数据改变会触发次函数的执行 }、
配置项:immediate:true; // 第一次默认监听数据、deep:true; // 监听深度数据
总结watch():1. 首次加载默认不监听,2. 可以监听多个数据源 ,3. 可以处理异步问题
watch() 和 watchEffect() 的区别:
相同点:1. 都是侦听一个或多个响应式数据源,2. 可以处理异步问题
不同点:watchEffect 默认立即监听数据,只能获取到新的数据;而watch 第一次默认不见听数据,可以获取到新旧数据
<template>
<div>
<h2>watch</h2>
<!-- <h2>{{ name }}</h2> -->
<h2>{{ age }}</h2>
<button @click="changeAge">年龄+1</button>
<!-- <button @click="changeName">修改name</button> -->
<h2>{{ state.name }}</h2>
<button @click="changeState">修改 reactive 数据类型</button>
</div>
</template>
<script setup>
import { ref, watch, reactive } from 'vue';
// watch 作用 => 时刻监听数据的改变(响应式数据)
// 语法:watch(数据源,处理函数,配置项)
// 配置项:immediate:true; 首次加载默认监听
// deep:true;监听深度的数据
// // 案例一: 监听数据 ref 类型
// let age=ref(20);
// let name=ref("lisa");
// watch(age,(newVal,oldVal)=>{
// console.log(newVal,oldVal); // 数据改变会触发次函数的执行
// })
// const changeAge = ()=>{
// age.value =age.value +1;
// }
// const changeName =()=>{
// name.value='小明'
// }
// 案例2:通过watch 监听某个数据 首次监听到
//添加配置项 immediate:true =》首次监听到
// 监听的深度的数据 =》 deep:true
// let state = reactive({
// name:'张三',
// age:100,
// like:{eat:'吃'}
// })
// watch( ()=>state.like,(newVal,oldVal)=>{
// console.log(newVal,oldVal);
// },{
// immediate:true,
// deep:true
// })
// const changeState = ()=>{
// state.like.eat='小红'
// }
// const changeAge = ()=>{
// age.value +=1
// }
// 案例3:watch =>监听多个数据
let age = ref(29)
let state = reactive({
name: '张三',
age: 100
})
watch([age, () => state.name], ([newA, newN], [oldA, oldN]) => {
console.log(newA, oldA);
console.log(newN, oldN);
})
const changeState = () => {
state.name = '小红'
}
const changeAge = () => {
age.value += 1
}
//总结 watch
//作用监听 响应式数据
// 特点
// 1默认 第一次不执行,如果需要理解执行添配置项
// 2监听多个数据源
// 3 处理异步问题
//watchEffect 和watch 相同的点和不同点
// 相同点
// 都可以时时刻刻监听某个数据改变,处理异步问题,都可以监听多个数据
//不同点
// watchEffect 默认立即执行 ,watchEffect 只能获取到最新的数据
// watch 默认不立即执行,watch 获取 到新旧数据
</script> <style> </style>
6、computed() 计算属性
作用:后端给的数据不是自己想要的,通过计算属性,把自己数据处理成自己想要的
写法:1. 默认:只用get方法,语法:let 想要的数据=computed({return 计算后的数据 });
2. get 和set 方式:let 想要的数据=computed({get:()=>{return}, set:(value)=>{}})
特点:1. 可以时时刻刻监听数据,根据这个数据,得到我们需要的数据;2. 只能写同步方法
<template>
<div>
<h2>计算属性computed</h2>
<!--
作用:计算属性
1 什么时候使用这个计算属性
后端给的数据,不是自己想要的,通过计算属性,把这个数据处理成自己想要的
2 语法: let 需要的数据=computed(()=>{})
-->
<h2>计算出实际薪资{{total}}</h2>
</div>
</template>
<script setup>
import {ref,computed} from 'vue';
// 后端给的一个数据
let salary=ref(0);
const getData=()=>{
setTimeout(()=>{
// 后端给的数据 没有实际的数据
salary.value=2000;
},500);
}
getData();
// // 计算属性的用法: 1 get 属性
// let total=computed(()=>{
// // 处理逻辑 +200
// return salary.value+200;
// })
// 用法2: 具有set 和 get 属性
// 1 什么时候触发get 方法 => 获取这个计算属性的放回置的时候 触发 get方法
// 2 什么时候触发set 方法 => 修改值得时候触发set方法
let total=computed({
get:()=>{
console.log("获取的时候触发");
return salary.value+1000;
},
set:(value)=>{// 第一个参数:设置的值
console.log("设置值的时候触发",value); // 设置total的时候触发这个方法
// 1 通过计算属性get方法 计算出我们需要的数据
// 2 当这个值为 某个值的时候,有需要进行逻辑处理,得到一个新的计算属性的值
setTimeout(()=>{
if(value>=3200){
salary.value=salary.value-200
}
},1000)
}
})
console.log(total);
total.value=6000;
// 计算属性的特点:
// 1 计算属性不能处理异步数据
// 2 时时刻刻观察 我们需要处理的动态数据
</script>
<style>
</style>
响应式:工具
1、toRefs()
本质:就是将reactive代理对象数据中的属性,属性值 变为 ref处理的数据
语法:toRefs(reactive响应式数据)
<template>
<div>
<h2>{{name}}</h2>
<h2>{{age}}</h2>
<button @click="addAge">addAge</button>
</div>
</template>
<script setup>
import {reactive,toRefs} from 'vue';
// let {age,name}=reactive({
// name:"小明",
// age:8,
// like:{eat:'🍎',play:['⚽']}
// })
// // 直接结构 reactive 响应式数据 => 他的数据不再是响应式数据
// const addAge=()=>{
// age=age+1; // 无法修改
// }
let objP=reactive({
name:"小明",
age:8,
like:{eat:'🍎',play:['⚽']}
})
// 我想在视图中直接使用 name,age 和ref 一样
// 本质就是将reactive 代理,对象数据中的属性,值变成ref处理的数据
// 使用vue3中的响应式api => toRefs
// 语法: toRefs(reactive响应式数据)
let {age,name}=toRefs(objP);
const addAge=()=>{
age.value+=1; // 无法修改
}
</script>
<style>
</style>
2、toRef()
作用:将reactive代理的数据(这个数据必须是一个对象)中的某个属性变为ref代理
语法:let ref值=toRef(目标对象,属性)
toRefs() 和 toRef() 的区别:toRefs()是把对像中的所有的属性,变成ref进行代理; toRef()是把reactive中的某个属性,变成ref 进行代理
<template>
<div>
<h2>toRef</h2>
<!--
作用:就是将reactive代理的数据,这个数据必须是一个对象,中的某个属性变成ref 代理
语法:let ref值=toRef(目标对象,属性)
-->
<h2>{{stateAge}}</h2>
</div>
</template>
<script setup>
import {toRef,reactive} from 'vue'
let state=reactive({ age:20, name:"lisa", }) let stateAge=toRef(state,'age'); console.log(stateAge); </script> <style> </style>
3、isRef()、isReactive()、isReadonly()、isProxy()
作用:判断这个变量是不是被这个isxxx这个方法处理了,返回值为布尔值,是就为true,不是就为false
<template>
<div>
<!-- 响应式api工具
isRef =>
isReactive
isReadonly
isxxx => 判断 这个变量是不是被这个isxxx这个方法处理了,是true,不是false
-->
</div>
</template>
<script setup>
import {ref,isRef,isReadonly} from 'vue'
let money = ref(1000) // ref 代理了
let obj={name:"lisa"}
console.log(isRef(money)); // 判断这个变量是不是ref代理的 // false
console.log(isReadonly(obj)); // false
</script>
<style>
</style>
响应式:进阶
1、shollowRef()、shallowReactive()、shallowReadonly()
作用:第一层有这个方法的 功能,只作用于第一层
shollowRef() 第一层的数据是响应式、shallowReactive()第一层的数据是响应式、shallowReadonly() 第一层的数据是只读
<template>
<div>
<h2>shallowReactive</h2>
<!--
shallowReactive => 第一层的数据是响应式
shallowRef => 第一层的数据是响应式
shallowReadonly => 第一层的数据是只读的
作用:浅的,只作用于数据的第一层
-->
<h2>{{state.name}}</h2>
<h2>{{state.like.eat}}</h2>
<button @click="change">改变state
第一层中的数据</button>
<button @click="changeTwo">改变state
第二层中的数据</button>
<button @click="changeAll">同时改变state
第一层和第二层中的数据</button>
<h3>{{ objs.name }}</h3>
<h3>{{ objs.like.eat }}</h3>
<button @click="changeR">改变state
第二层中的数据</button>
</div>
</template>
<script setup>
import {shallowReactive,reactive,toRefs,shallowReadonly} from 'vue';
let state=shallowReactive({
age:20,
name:"lisa",
like:{eat:"🍎"}
})
const change=()=>{
state.name="andy";
}
const changeTwo=()=>{
state.like.eat= "🍍"; // 单独是无法修改的,因为它不是第一层数据,不是响应式的数据
}
const changeAll=()=>{
state.name="andy";
state.like.eat= "🍍"; // 添加第一层数据,同时改变,第二层也变成了响应式的数据
}
//readonly
let objs = shallowReadonly({
name:'小明',
like:{eat:'🍉'}
})
const changeR =()=>{
// objs.name="cici";//无法修改,因为这里的第一层是只读的
objs.like.eat='🍇'; // 这里是可以改变的,因为shallowReadonly只作用于第一层,但是它不是响应式的,无法同步视图更新
console.log(objs.like.eat); // 🍇
}
// shallowRef() 同理
</script>
<style>
</style>
浙公网安备 33010602011771号