Vue3中自定义ref

使用ref

  • main.js
import { createApp } from 'vue'
import App from './App.vue'

createApp(App).mount('#app')
  • App.vue
<template>
  <input type="text" v-model="keyWord">
  <h3>{{keyWord}}</h3>
</template>

<script>
import {ref} from "vue";
export default {
  name: 'App',
  setup() {
    let keyWord = ref("hello");
    return {
      keyWord
    }
  }
}
</script>
  • 启动应用,测试效果
    在这里插入图片描述

使用customRef自定义ref

自定义ref,本质是一个函数。

  • main.js
import { createApp } from 'vue'
import App from './App.vue'

createApp(App).mount('#app')
  • App.vue
<template>
  <input type="text" v-model="keyWord">
  <h3>{{keyWord}}</h3>
</template>

<script>
import {customRef} from "vue";
export default {
  name: 'App',
  setup() {
    //自定义ref,本质是一个函数
    function myRef(value){
      return customRef(() => {
        return {
          get(){
            console.log("正在读取value,当前值为:",value);
            return value;
          },
          set(newValue){
            console.log("正在修改value,新值为:",newValue);
            value = newValue;
          }
        }
      })
    }

    let keyWord = myRef("hello");

    return {
      keyWord
    }
  }
}
</script>
  • 启动应用,测试效果
    在这里插入图片描述
    初始化没有问题,但是改变输入框中的文本值时,下面h3标签中的内容并没有同时更新。

针对以上问题,修改Demo.vue中的myRef

<template>
  <input type="text" v-model="keyWord">
  <h3>{{keyWord}}</h3>
</template>

<script>
import {customRef} from "vue";
export default {
  name: 'App',
  setup() {
    //自定义ref,本质是一个函数
    function myRef(value){
      return customRef((track,trigger) => {
        return {
          get(){
            console.log("正在读取value,当前值为:",value);
            //通知Vue追踪value的变化
            track();
            return value;
          },
          set(newValue){
            console.log("正在修改value,新值为:",newValue);
            value = newValue;
            //通知Vue重新解析模板
            trigger();
          }
        }
      })
    }

    let keyWord = myRef("hello");

    return {
      keyWord
    }
  }
}
</script>

customRef的回调中接收两个参数:tracktrigger,它们都是函数。
调用trigger函数,通知Vue重新解析模板;调用track函数,通知Vue追踪目标数据的变化。
在setter中调用trigger,在getter中调用track,自定义ref(myRef)的功能就和ref类似了。如下图所示。
在这里插入图片描述


现在需求是这样的:输入框中的文本发生改变,下面h3标签中的内容延迟500ms更新。
既然已经用customRef实现了自定义ref,即myRef,延迟更新就变得很简单了:在setter中加入setTimeout延迟即可,如下。

<template>
  <input type="text" v-model="keyWord">
  <h3>{{keyWord}}</h3>
</template>

<script>
import {customRef} from "vue";
export default {
  name: 'App',
  setup() {
    //自定义ref,本质是一个函数
    function myRef(value){
      return customRef((track,trigger) => {
        return {
          get(){
            console.log("正在读取value,当前值为:",value);
            track();
            return value;
          },
          set(newValue){
            console.log("正在修改value,新值为:",newValue);
            setTimeout(() => {
              value = newValue;
              trigger();
            },500)
          }
        }
      })
    }

    let keyWord = myRef("hello");

    return {
      keyWord
    }
  }
}
</script>

在这里插入图片描述


但是有一个小问题:当输入框中文本改变过快时,h4标签中内容更新时会出现抖动,见下图。
在这里插入图片描述
采用防抖的方式解决以上问题(当然,这是js范畴的知识点哈,并不是Vue的哈)。修改后的Demo.vue如下所示。

<template>
  <input type="text" v-model="keyWord">
  <h3>{{keyWord}}</h3>
</template>

<script>
import {customRef} from "vue";
export default {
  name: 'App',
  setup() {
    //自定义ref,本质是一个函数
    function myRef(value,delay){
      return customRef((track,trigger) => {
        let timer;
        return {
          get(){
            console.log("正在读取value,当前值为:",value);
            track();
            return value;
          },
          set(newValue){
            console.log("正在修改value,新值为:",newValue);
            clearTimeout(timer);
            timer = setTimeout(() => {
              value = newValue;
              trigger();
            },delay)
          }
        }
      })
    }

    let keyWord = myRef("hello",500);

    return {
      keyWord
    }
  }
}
</script>

测试效果如下,ok。
在这里插入图片描述