vue3中的一些API
shallowRef ( ) 和shallowReactive ( )
shallowRef (浅层响应式)
1.作用:创建一个响应式数据,但只对顶层属性进行响应式处理。
2.用法:
const original=ref(...)
const original2=shallowRef(original)
3.特点:只跟踪引用值的变化,不关心值内部的属性变化。
shallowReactive (浅层响应式)
1.作用:创建一个浅层响应式对象,只会使对象的最顶层属性变成响应式的,对象内部的嵌套属性则不会变成响应式的
2.用法:
const myObj = reactive({...})
const myObj2= shallowReactive({myObj})
3.特点:对象的顶层属性是响应式的,但嵌套对象的属性不是。
总结
通过使用shallowRef()和shallowReactive()来绕开深度响应。浅层式API创建的状态只在其顶层是响应式的,对所有深层的对象不会做任何处理,避免了对每一个内部属性做响应式所带来的性能成本,这使得属性的访问变得更快,可提升性能。
readonly( ) 和 shallowReadonly( )
readonly
1.作用:用于创建一个对象的深只读副本。 (不可修改)
2.用法:
const original = reactive({...})
const original2 = readonly({ original })
3.特点:
对象的所有嵌套属性都将变为只读。
任何尝试修改这个对象的操作都会被阻止(在开发模式下,还会在控制台中发出警告)。
4.应用场景:
创建不可变的状态快照。
保护全局状态或配置不被修改。
shallowReadonly
1.作用:与readonly类似,但只作用于对象的顶层属性。
2.用法:
const original = reactive({...})
const original2 = shallowReadonly({ original })
3.特点:
只将对象的顶层属性设置为只读,对象内部的嵌套属性仍然是可变的。
适用于只需保护对象顶层属性的场景。
toRaw( ) 和 markRaw( )
toRaw
1.作用:用于获取一个响应式对象的原始对象。
2.toRaw返回的对象不再是响应式的,不会触发视图的更新。
场景:
在需要将响应式对象传递给非vue的库或外部系统时,使用toRaw可以确保他们收到的是普通对象
用法:
const original = reactive({...})
//响应式数据
const original2 = toRaw({ original })
//原始数据
markRaw
1.作用:标记一个对象,使其永远不会变成响应式的。
例如:第三方库:mockjs
const mockJs = markRaw({mockjs})
const mockJs2 = reactive({ mockJs })
//mockJs2不是响应式数据
customRef
重点注意:track,trigger
<template>
<h2>信息是:{{msg}}</h2>
<input type="text" v-model="msg">
<!-- 双向绑定 获取响应式数据 -->
</template>
<script setup lang="ts" name="App">
import {ref} from "vue"
const msg=ref("你好")
</script>
结果:
<template>
<h2>信息是:{{msg}}</h2>
<input type="text" v-model="msg">
<!-- 双向绑定 获取响应式数据 -->
</template>
<script setup lang="ts" name="App">
import {customRef,ref} from "vue"
// const msg=ref("你好") //使用ref只能实现基本的响应式数据变化
// 要求:表单中数据变化后1秒之后,h2中的数据发生改变
// 这时用ref来做是不能实现的,所以使用自定义响应式:customRef (customRef是一个函数)
let initValue=""
let timer
const msg=customRef((track,trigger)=>{ //回调函数里有两个参数:track(跟踪)和trigger(触发)
return {
get(){ //读取msg时调用get()
track() //告诉vue数据很重要,需要持续关注,一旦有变化就要更新 (跟踪)
return initValue
},
set(value){ //msg发生变化时调用set()
clearTimeout(timer) //防止重复开启定时器
timer=setTimeout(()=>{
initValue=value
trigger() //通知vue数据改变
},1000)
}
}
})
</script>
封装自定义响应式数据:
App.vue:
<template>
<h2>信息是:{{msg}}</h2>
<input type="text" v-model="msg">
<!-- 双向绑定 获取响应式数据 -->
</template>
<script setup lang="ts" name="App">
import {customRef,ref} from "vue"
// const msg=ref("你好") //使用ref只能实现基本的响应式数据变化
// 要求:表单中数据变化后1秒之后,h2中的数据发生改变
// 这时用ref来做是不能实现的,所以使用自定义响应式:customRef (customRef是一个函数)
import useMsgRef from "./useMsgRef";
const {msg}=useMsgRef("你好啊",2000) //传入两个参数
</script>
useMsgRef.ts:
// 封装自定义ref
import {customRef} from "vue"
export default function(initValue:string,delay:number){ //注意这里的参数
let timer
const msg=customRef((track,trigger)=>{ //回调函数里有两个参数:track(跟踪)和trigger(触发)
return {
get(){ //读取msg时调用get()
track() //告诉vue数据很重要,需要持续关注,一旦有变化就要更新 (跟踪)
return initValue
},
set(value){ //msg发生变化时调用set()
clearTimeout(timer) //防止重复开启定时器
timer=setTimeout(()=>{
initValue=value
trigger() //通知vue数据改变
},delay)
}
}
})
return {msg}
}
Teleport
作用:将组件html结构移动到指定位置的技术
ModalPage.vue:
<template>
<div class="modal">
<h2>我是ModalPage组件</h2>
<button @click="isShow=true">展开弹框</button>
<teleport to="body"> <!-- <teleport to=".app"> -->
<div class="content" v-show="isShow">
<h2>弹框标题</h2>
<h2>弹框内容</h2>
<button @click="isShow=false">关闭弹框</button>
</div>
</teleport>
</div>
</template>
<script setup name="ModalPage">
import {ref} from "vue"
const isShow=ref(false)
</script>
<style scoped>
.modal {
width: 600px;
height: 200px;
background-color: pink;
box-shadow: 0 0 10px;
border-radius: 5px;
margin-top: 50px;
}
.content {
background-color: skyblue;
width: 320px;
height: 200px;
text-align: center;
position:fixed;/* position:fixed;以视口为参照物 */
top:50%;
left:50%;
transform: translate(-50%,-50%);
}
</style>
App.vue:
<template>
<div class="app">
<h2>我是App组件</h2>
<img src="./assets/images/11.png">
<ModalPage/>
</div>
</template>
<script setup lang="ts" name="App">
import ModalPage from "./components/ModalPage.vue"
</script>
<style scoped>
.app {
width: 800px;
height: 600px;
background-color: #ddd;
border-radius: 10px;
box-shadow: 0 0 10px;
}
img {
width: 200px;
height: 130px;
background-size: cover;
/* 对于以前: */
/* 当不加css样式中的filter滤镜时,子组件的position:fixed是可以根据视口来调整大小 */
/* 但当加上这个样式之后,position:fixed失效 */
filter: saturate(200%);
/* saturate是饱和度的意思 */
/* 解决方法:在模板中给需要根据视口调整大小的内容外包上<teleport>标签 并加上to属性(具体见子组件) */
}
</style>
Suspense
等待异步组件时渲染一些额外内容,让应用有更好的用户体验使用步骤:
- 异步引入组件
- 使用Suspense包裹组件,并配置好default与fallback
App.vue:
<template>
<div class="app">
<h2>我是App组件</h2>
<!-- 当子组件里要处理异步任务,网速慢时想要在页面呈现一些东西就可以使用Suspense -->
<Suspense>
<template v-slot:default>
<ModalPage/>
</template>
</Suspense>
<!-- 当网速慢,页面没加载出来时可以显示的内容 -->
<Suspense>
<template v-slot:fallback>
<h2>loading...</h2>
</template>
</Suspense>
</div>
</template>
<script setup lang="ts" name="App">
import ModalPage from "./components/ModalPage.vue"
</script>
ModalPage.vue:
<template>
<div class="modal">
<h2>我是ModalPage组件</h2>
</div>
</template>
<script setup name="ModalPage">
import {ref} from "vue"
import axios from "axios"
// 异步获取数据
let msg=await axios.get("https://api.uomg.com/api/rand.qinghua?format=json")
console.log(msg)
</script>