文章目录
- 自定义Hook函数
- roRef
- 其它 Composition API
- shallowReactive 与 shallowRef
- readonly 与 shallowReadonly
- toRaw 与 markRaw
- customRef
- provide 与 inject
- 响应式数据的判断
- Composition Api 的优势。
- 新的组件
- .Fragment
- Teleport
- Suspense
- vue3 一些api的转移
自定义Hook函数
什么是hook?
本质是一个函数,把setup函数中使用的Compostion Api 进行了封装,类似于vue2中的mixin.
自定义hook的优势是复用了代码,让setup中的逻辑更清楚易懂。
实例:在多个页面中获取鼠标点击的坐标。
hook/index.ts
import { reactive,onMounted,onBeforeUnmount } from 'vue';
export default function () {
let print = reactive({
x:0,y:0
})
function savePrint(e){
print.x = e.pageX
print.y = e.pageY
console.log(e.pageX,e.pageY)
}
onMounted (){
window.addEventListener("click",savePrint)
}
onBeforeUnmount(){
window.removeEventListener("click",savePrint)
}
return print
}
vue组件中使用
import usePrint from 'hook/index.ts'
export default {
setup(){
let print = usePrint()
console.log(print)
}
}
roRef
- 作用:创建一个ref对象,其value指向另一个对象中的某个属性
- 语法:const name = toRef(person,“name”)
- 应用:要将响应式对象中的某个属性单纯提供给外部使用。
- 扩展:toRefs 与 toRef 功能一致,但可以批量创建多个ref对象,语法 toRefs(person)
例子,将对象中的仅仅两个属性返回在页面
import {reactive,toRef,toRefs} from 'vue'
export default {
setup(){
let per = reactive({
name:"",
age:12,
job:{
jianzhi:{
gongzi:10
}
}
})
let name = per.name
name = "李四";// 这样name脱离了响应式,页面不会更新。
let name2 = toRef(per,'name');//name2 是响应式的
let gongzi = toRef(per.job.jianzhi,"gongzi")
//let per1 = toRefs(per);
return {
name2,
gongzi
}
}
}
其它 Composition API
shallowReactive 与 shallowRef
- shallowReactive :只处理对象最外层属性的响应式(浅响应式)
- shallowRef:只处理基本数据类型的响应式,不进行对象的响应式处理。
- 使用场景:
- 如果有一个对象数据,结构比较深,但变化时只是外层属性变化,就用shallowReactive
- 如果有对象数据,后续功能不会修改对象中的属性,而是生成新的对象来替换,就用 shallowRef
import {reactive,shallowReactive,shallowRef} from 'vue'
export default {
setup(){
// 只处理第一层响应式
let obj = shallowReactive({
a:"",
b:{
c:2, // c 是改变了监听不到,因为不做响应式处理
}
})
let aa = shallowRef({ b: 23}) // 没有处理成响应式,因为shallowRef只处理基本类型。
}
}
readonly 与 shallowReadonly
readonly 让一个响应式数据变为只读的(深只读)
shallowReadonly 让一个响应式数据变为只读的(浅只读)
应用场景:不希望数据被修改时。
toRaw 与 markRaw
-
towRaw
- 作用:将一个由 reactive 生成的响应式对象转为普通对象。
- 使用场景:用于读取响应式对象对应的普通对象,对这个普通对象的所有操作,不会引起页面更新。
-
markRaw:
- 作用:标记一个对象,使其永远不会再成为响应式对象
- 应用场景
- 1.有些值不应被设置为响应式的,例如复杂的第三方类库等
- 2.当渲染具有不可变数据源的大列表时,跳过响应式转换可以提高性能
customRef
创建一个自定义的ref,并对其依赖项跟踪和更新触发进行显式控制。
实例:实现一个防抖的效果
<template>
<input type="text" v-model="keyword"/>
<h3> {{keyword}}</h3>
</template>
imput {customRef} from 'vue'
export default {
setup(){
// 自定义一个ref名为myRef
function myRef(value){
let timer
const x = customRef((track,trigger)=>{ // 函数必须返回一个对象
return {
get(){
track(); // 通知vue追踪value的变化,(提前和get商量一下,让他认为这个value是有用的)
return value
},set(newValue){
clearTimeout()
timer = setTimeout(()=>{
value = newValue;
trigger()// 通知vue去重新解析模板
},500)
}
}
})
return x;
}
let keyword = myRef("");
return {keyword}
}
}
provide 与 inject
作用:实现祖组件与后代组件间(跨级组件)通信,其实父子组件也可以,但是父子组件一般用简单的props就可以了
父组件有一个provide 选项来提供数据,子组件有一个inject 选项来开始使用这些数据
组件A
<template>
<div> 组件A (祖)</div>
<B />
</template>
<script>
import {reactive,toRefs,provide} from 'vue'
import B form 'B.vue'
export default {
name:'A',
setup(){
let car = reactive({
name:"奔驰", price:"40w"
})
provide("car",car)
return {...toRefs(car) }
}
}
</script>
组件B (子组件)
<template>
<div> 组件B (子)</div>
<C />
</template>
<script>
import C form 'C.vue'
export default {
name:'b'
}
</script>
组件C (孙组件)
<template>
<div> 组件C (孙)</div>
<div> 获取到祖组件中数据 {{car.name}} -- {{car.price}} </div>
</template>
<script>
import {reactive,toRefs,inject} from 'vue'
export default {
name:'C',
setup(){
let car = inject("car");
console.log(car)
return {car}
}
}
</script>
响应式数据的判断
- isRef:检查一个值是否为一个ref对象
- isReactive:检查一个对象是否是由reactive 创建的响应式代理
- isReadonly:检查一个对象是否是由readonly 创建的只读代理
- isProxy:检查一个对象是否是由reactive 或者readonly 方法创建的代理
import {ref, reactive,toRefs,readonly,isRef,isReactive,isReadonly,isproxy ) from 'vue
export default (
setup(){
let car = reactive({name:'奔驰',price:'40w'})
let sum = ref(0)
let car2 = readonly(car)
console.log(isRef(sum)) // true
console.log(isReactive(car)) // true
console.log(isReadonly(car2)) // true
console.log(isProxy(car)) // true
console.log(isProxy(sum )) // false
return {...toRefs(car)]
}
}
Composition Api 的优势。
使用传统OptionsAPI中,新增或者修改一个需求,就需要分别在data,methods,computed里修改,
使用Composition Api 我们可以更加优雅的组织我们的代码,函数。让相关功能的代码更加有序的组织在一起。
![在这里插入图片描述](https://img-blog.csdnimg.cn/90b2a0473f144259bf6af975579c2a12.png
新的组件
.Fragment
。在Vue2中:组件必须有一个根标签
。在Vue3中: 组件可以没有根标签,内部会将多个标签包含在一个Fragment虚拟元素中
。好处: 减少标签层级,减小内存占用
Teleport
什么是Teleport?- Teleport 是一种能够将我们的组件html结构移动到指定位置的技术。类似于弹出对话框。
<teleport to="移动位置">
<div v-if="isShow"class="mask">
<div class="dialog">
<h3>我是一个弹窗</h3>
<button @click="isShow = false">关闭弹窗</button>
</div>
</div>
</teleport>
Suspense
等待异步组件时渲染一些额外内容,让应用有更好的用户体验
<template>
<div class="app">
<h3>我是App组件</h3>
<Suspense>
<template v-slot:default>
<Child/>
<template>
<template v-slot:fallback>
<h3>稍等,加载中...</h3>
</template>
</Suspense>
</div>
</template>
<script>
// import Child from./components/Child'//前态引入
import (defineAsyncComponent} from ‘vue’
const Child = defineAsyncComponentexport default(()=>import('./components/Child')) //异步引入
export default {
name : 'App'
components:{Child},
}
</script>
如果是使用Suspense 进行异步引入子组件,那么子组件中setup 是可以返回 async函数或者promise函数。
<template>
<div class="child">
<h3>我是child组件</h3>
({sum))
</div>
</template>
<script>
import (ref} from 'vue‘
export default {
name:'Child'
async setup()[
let sum = ref(0)
let p = new Promise((resolve,reject)=>(
setTimeout(()=>{
resolve({sum))
}, 3000)
return await p
</script>