Vue16-API

145 阅读4分钟
Reactive判断的API

图片.png

图片.png

只希望浅层的name进行响应式,对深层的name:kobe不响应 图片.png 图片.png

只对浅层的进行只读,深层的还是可以进行响应式 图片.png 图片.png

toRefs
export default{
    setup(){
        const info = reactive({
            name:"why",
            age:18
        })
        //将name和age从info中结构
        let {name,age} = info
        
        const changeAge = ()=>{
            age++;
        }
        
        return{
            name,
            age,
            changeAge
        }
    }
}

这时,age怎么点都不会++。 因为:let{name,age} = info 实际上等价于

let name = "why",let age = 18

这样就不是响应式的了,此时需要使用toRefs

let {name,age} = toRefs(info)等价于
{name:ref对象,age:ref对象}
结构出来的不是普通值,而是ref

所以在changeAge中: .value
const changeAge =()=>{
    //age.value++
    info.age++  就和age.value等价了
}

图片.png

toRef:只对一个其中一个属性进行转换ref,建立连接

const info = reactive({
        name:"why",
        age:18
    })
只将info里的name进行ref转换,不能再给name加上结构{ }    
let name = toref(info,"name")
ref其他的API(自定义Ref)

图片.png

图片.png

图片.png

<template>
    <div>
        <input v-model = "message"/>
        <h2>{{message}}</h2>
    </div>
</template>

<script>
    import {ref} from 'vue'
    export default{
        setup(){
            const message = ref("Hello World")
            return{
                message
            }
        }
    }
</script>

实际上message是一个ref对象,下面展示的实际上是我的依赖;

防抖:message变化的时候,下面变化的慢一些;需要使用自定义hook

//自定义一个自己的ref,而不是系统的ref
//ref:ref(..),所以需要传入一个value
import {customRef} from 'vue'
export default function(()=>{

//因为我每输入一个字符就要trigger更新一下依赖,如果我输入很多,他就会延迟N秒,但是我的效果是,整体输入完然后总共延迟1秒,所以一旦有输入,我就将上次输入后执行的定时器,清除掉

    let timer = null;

//使用customRef后,返回的就不再是一个普通的Ref对象
    return customRef((track,trigger)=>{
        track:跟踪,收集依赖,调用依赖
        trigger:什么时候触发依赖,进行更新
        //需要返回一个对象,里面有set()和get()
        return{
            get(){
                track();//收集最新依赖,发送
                return value
            },
            set(newValue){
            //取消上一次的定时器
                clearTimeout(timer)
                timer=setTimeout(()=>{
                    value = newValue;
                    trigger();更新所有触发依赖
                },1000);
            }
        }
    })
})

图片.png

computed
<h2>{{fullName}}</h2>

import {ref,computed} from 'vue'
export default{
    setup(){
        const firstName = ref("abc")
        const lastName = ref("cba")
        
        //这样其实不是响应式的,需要计算属性
        const fullName = firstName.value+..
        
        //计算属性的写法:
        //因为firstname是响应式的,当数据发生改变的时候会再执行一次getter回调,就会响应处最新值(响应式)
        //computed返回值是一个ref对象
        const fullName = computed(()=>{
            firstName.value + lastName.value
        })
        
        计算属性完整写法
        const fullName = computed({
            get:()=>{
                firstName.value + lastName.value
            }
            set(newValue){
            
            }
        })
        
        return{
            firstName,
            lastName,
            fullName,
        }
    }
}

图片.png

侦听数据变化(watch)

图片.png

<template>
    <h2>{{name}}--{{age}}</h2>
    <button @click = "changeName"></button>
    <button @click = "changeAge"></button>
</template>
<script>
import {watchEffect,watch} from 'vue'
export default{
    setup(){
      //watchEffect会自动收集响应式依赖
        const name=ref("why")
        const age = ref(18)
        
        const changeName = ()=>
            name.value = "kobe"
        
        const changeAge =() =>
            age.value = 20
        
        //默认打开页面会立马执行一次
        watchEffect(()=>{
            console.log(name.value)
            以后每改变一次name的值,都会触发一次
            如果里面不写,就谁也不会触发
            在这里用谁的值,谁的对应依赖就会被添加,因此就会被监视到
        })
        
        return{
            name,
            age,
            changeName,
            changeAge
        }
    }
}
</script>

图片.png

watchEffect的停止侦听
//watchEffect会返回一个stop函数
const stop = watchEffect(()=>{
    console.log(name.value,age.value)
})

//当我的年龄>25时,我调用 停止侦听
//年龄会继续++,但是不会再侦听了
const changeAge =() =>{
    age.value++
    if(age.value>25){
        stop()
    }
}
watchEffect清除副作用

图片.png

//此时会传入一个形参
const stop = watchEffect((onInvalidate)=>{
//根据name和age两个变量发送网络请求
/*当我的age发送网络请求的过程中,数据还没有请求回来
但是值已经发生了变化,一旦值发生了变化,就得再发一次新的请求。
这样会造成资源浪费。所以我们希望,我们改变值的时候,把上一次发送的请求取消掉,发送最新的请求。
上一次发送的网络请求就称为:副作用*/

    //该形参可以被当成方法调用
    onInvalidate(()=>{
        //在这个函数中清除额外的副作用
        request.cancel()
    })
    console.log(name.value,age.value)
})

const changeAge =() =>{
    age.value++
    if(age.value>25){
        stop()
    }
}

模拟网络请求

图片.png

setup中使用ref
Vue可以在标签中设置`ref = "ref名"`属性.
在Vue中通过`this.$refs.ref名,来获取该标签的dom。
类似于原生dom中的`id = "id名
document.getElementsById("id")`;
<h2 ref="title">哈哈哈</h2>
    setup(){
    //现在我们不写methods,怎么拿到呢?\
    
    //这里的ref会被上方的默认赋值为title
        const title = ref(null);
        
        //这里是null,因为要等到h2被挂载后才可以
        //console.log(title.value)
        
        watchEffect(()=>{
            console.log(title.value)
        },{
        pre:默认值,会提前执行(不写,默认执行这个)
            flush:"pre"
        post:等DOM执行完才会执行    
            flush:"post"
        })
        
        return{
            title
        }
    },

methods:{
    foo(){
    //曾经我拿到哈哈哈,需要先绑定一个ref,然后通过$ref.title才能拿到值,title的值
        this.$ref.title
    }
    
}
Watch的使用

图片.png

Watch可以拿到oldValue,WatchEffect就拿不到

export default{
    setup(){
        const info = reactive({
            name:"why",
            age:18
        });
    //第一种写法,只能侦听对象中的某个属性,传入getter函数写法    
        watch(()=>info.name,(newValue,oldValue)=>{
            
        })
    //第二种写法,传入一个可响应对象:ref对象
    reactive对象获取到的newValue和oldValue的本身都是reactive对象
        watch(info,(newValue,oldValue)=>{
            
        })
    // 如果希望newValue和oldValue是一个普通对象
    // 写成getter函数,把info对象解构,此时这里是一个普通的对象,就会变成newValue和oldValue
        watch(()=> {
            return {...info}
        },(newValue,oldValue)=>{
            console.log
        }
          
     //ref对象获取到的newValue和oldValue是value值的本身
        const name = ref("why")
        watch(name,(newValue,oldValue)=>{
            oldValue是why,newValue是coderwhy
            直接是一个对象值本身,而不是一个对象形式
        })
    
        const changeData=()=>{
        //name.value = "coderwhy"
            info.name = "coderwhy"
        }
        
        return{
            info,
            changeData
        }
    }
}
侦听多个数据源

返回的是reactive对象,就是propx对象 图片.png

不想他是reactive,而是真实的普通对象,那么需要解构一下 图片.png

深度侦听

默认情况下,就是可以深度侦听。是reactive,源码默认开启deep;

图片.png

普通对象就不可以深度侦听,因为他不是reactive

图片.png

但是我就是想给普通对象深度侦听咋办呢?传入第三个参数deep

图片.png