vue3-ref系列

95 阅读1分钟

ref全家桶

vue2写法

<script>
  export default{
    data(){
      return{
        //写在这里才是响应式的
        age:18
      }
    }
  }
</script>

为什么要有ref

<template>
  <div>
    <button @click="changeMsg">change</button>
    <div>{{message}}</div>
  </div>
</template>

<script setup lang="ts">
     let message:string="hello world"

     const changeMsg=()=>{
       message='change msg'
     }
</script>

点击上面的 change 之后,script的数据message会变,视图层里的数据message不会变,说明数据不是响应式的

ref

定义响应式数据 深层次的响应

创建:let 变量名=ref("OldValue") 修改:变量名.value=newValue 使用:{{变量名}}

一般用来定义原始类型的响应式数据

定义复杂类型数据(对象、数组)其实也是调用reactive,源码里有

<template>
  <div>
    <p>{{msg}}</p>
    <p>{{msg2}}</p>
    <button @click="changeMsg">changeMsg</button>
  </div>
</template>

<script setup lang="ts">
import {ref} from 'vue'

//创建 let 变量名=ref("OldValue")
//基本类型
let msg=ref("ref对象")
//引用类型
let msg2=ref({name:"zs"})

const changeMsg=()=>{
  //变量名.value=newValue
  msg.value="change后的ref对象"
  console.log(msg);
  msg2.value.name="ls"//深层
  console.log(msg2)
}
</script>

<style>

</style>

isRef

判断是否是一个ref对象(不常用)

格式:isRef(变量名) 返回一个boolean值:false/true

import {ref,isRef} from 'vue'

let msg=ref("ref对象")
let notRef=123

const changeMsg=()=>{
  console.log(isRef(msg));//true
  console.log(isRef(notRef));//false
}

shallowRef

只处理基本数据类型的响应式, 不进行对象的响应式处理

浅层次的响应

不进行对象的响应式处理(单独使用时),视图层没有变化,后台有变化

<template>
  <div>
    <p>{{ message }}</p>
    <button @click="changeMsg">change</button>
  </div>
</template>
 
<script setup lang="ts">
import { shallowRef } from 'vue'

let message= shallowRef({name: "修改前"})

const changeMsg = () => {
  message.value.name = '修改后'//这种格式不是响应式,无法修改视图层的数据
  //message.value = { name: "ww" }//这种格式可以修改
  console.log(message);
}
</script>
 
<style>
</style>

基本数据类型的响应式可以改变

<template>
  <div>
    <p>{{ msg }}</p>
    <button @click="changeMsg">change</button>
  </div>
</template>
 
<script setup lang="ts">
import { shallowRef } from 'vue'

let msg=shallowRef(111)

const changeMsg = () => {
 msg.value=222
}
</script>
 
<style>
</style>

特殊情况

shallowRef被影响变成响应式

ref和shallowRef不能一起用,不然会影响shallowRef

<template>
  <div>
    <p>{{ message }}</p>
    <p>{{msg}}</p>
    <button @click="changeMsg">change</button>
  </div>
</template>
 
<script setup lang="ts">
import { ref,shallowRef } from 'vue'

let msg=ref(111)
let message= shallowRef({name: "修改前"})

const changeMsg = () => {
  // msg.value=2222
  message.value.name = '被ref影响了'//这种格式无法修改
  //message.value = { name: "ww" }//这种格式可以修改
   msg.value=2222
}
</script>
 
<style>
</style>

源码分析

shallowRef基本数据类型和对象类型一起修改,可以修改

<template>
  <div>
    <p>{{ msg }}</p>
    <p>{{msg1}}</p>
    <button @click="changeMsg">change</button>
  </div>
</template>
 
<script setup lang="ts">
import { shallowRef } from 'vue'

let msg=shallowRef(111)
let msg1=shallowRef({name:'dio'})

const changeMsg = () => {
 msg.value=222
 msg1.value.name="修改后"
}
</script>
 
<style>
</style>

分开也可以改,先改基本再改对象,改不了

先改对象发现改不了,先改对象再改基本可以改

<template>
  <div>
    <p>{{ msg }}</p>
    <p>{{msg1}}</p>
    <button @click="changeMsg">修改msg</button>
    <button @click="changeMsg2">修改msg1对象</button>
  </div>
</template>
 
<script setup lang="ts">
import { shallowRef } from 'vue'

let msg=shallowRef(1)
let msg1=shallowRef({name:'dio'})

const changeMsg = () => {
 msg.value+=4
}
const changeMsg2 = () => {
 msg1.value.name="修改后"
}
</script>
 
<style>
</style>

ref是否有类型限制

triggerRef

强制更新页面DOM

格式:triggerRef(变量名)

<template>
  <div>
    <p>{{ message }}</p>
    <button @click="changeMsg">change</button>
  </div>
</template>
 
<script setup lang="ts">
import { shallowRef, triggerRef } from 'vue'

let message= shallowRef({name: "修改前"})

const changeMsg = () => {
  message.value.name = '修改后'//这种格式不是响应式,无法修改视图层的数据
  triggerRef(message)//强制更新
  console.log(message);
}
</script>
 
<style>
</style>

customRef

自定义ref

customRef 是个工厂函数要求我们返回一个对象 并且实现 get 和 set

<template>
  <div>
    <p>{{message}}</p>
    <button @click="changeMsg">changeMsg</button>
  </div>
</template>

<script setup lang="ts">
import { Ref, shallowRef, triggerRef, customRef } from 'vue'
 
function Myref<T>(value: T) {
  return customRef((track, trigger) => {
    return {
      get() {
        track()
        return value
      },
      set(newVal: T) {
        console.log('set');
        value = newVal
        trigger()
      }
    }
  })
}
 
let message = Myref('前')
const changeMsg = () => {
  message.value = '后'
  console.log(message)
}
</script> 


<style>

</style>

可以用来写防抖

<template>
  <div>
    <p>{{ message }}</p>
    <button @click="changeMsg">change</button>
  </div>
</template>
 
<script setup lang="ts">
import { Ref, shallowRef, triggerRef, customRef } from 'vue'
 
function Myref<T>(value: T) {
  let timer:any
  let count=0
  return customRef((track, trigger) => {
    return {
      get() {
        track()
        return value
      },
      set(newVal: T) {
        //count++
        //console.log('调用了'+count+"次");
        clearTimeout(timer)
        timer=setTimeout(()=>{
           count++
           console.log('调用了'+count+"次");
           value=newVal
           timer=null
           trigger()
        },1000)
        value = newVal
        trigger()
      }
    }
  })
}
 
let message = Myref('前')
const changeMsg = () => {
  message.value = '后'
}
</script> 
 
<style>
</style>

ref获取dom

<template>
  <div>
    <button @click="changeMsg">getDom</button>
    <div ref="dom">I am Dom</div>
  </div>
</template>

<script setup lang="ts">
import { ref,Ref, shallowRef, triggerRef, customRef } from 'vue'
 
const dom=ref<HTMLElement>()

const changeMsg = () => {
  console.log(dom.value?.innerText)
}
</script> 


<style>

</style>