一、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>