Vue3 customRef自定义ref 实现防抖

防抖就是防止在input 框中每输入一个字符就要向服务器请求一次,只要在用户输入完成过一段时间再读取用户输入的内容就能解决这个问题,减小服务器的压力。

**1.**自定义ref是一个函数,可以接受参数。

比如我们自定义一个myRef:

javascript 复制代码
setup() {
  let text = myRef("初始化");

  // 配置自定义的myRef
  function myRef(value) {}

  return { text };
},

**2.**在这个函数中,我们有一个返回值,这个返回值是customRef 函数。

在使用customRef 函数之前,我们需要先对其进行引入:

import { customRef } from "vue";

javascript 复制代码
setup() {
  let text = myRef("初始化");

  function myRef(value) {
    return customRef()
  }

  return { text };
},

**3.**customRef 函数的参数是一个函数。

该函数中又返回一个对象。

对象中有get函数和set函数。

javascript 复制代码
setup() {
  let text = myRef("初始化");

  function myRef(value) {
    return customRef(() => {
      return {
        get() { },
        set() { }
      }
    })
  }

  return { text };
},

**4.**当我们在模板中读取使用自定义ref 定义的数据时就会调用get 函数,修改数据时就会调用set 函数。原理和Proxy 对象中的get、set 差不多。

我们将get 函数中的返回值作为解析模板后数据的值。

而set 函数中,参数newValue为value修改后的值,我们需要将新的值赋值给传入的value值,才能实现页面的响应式。

javascript 复制代码
setup() {
  let text = myRef("初始化");

  function myRef(value) {
    return customRef(() => {
      return {
        // 读取value 调用get
        get() {
          return value;
        },
        // 修改value 调用set
        set(newValue) {
          value = newValue;
        }
      }
    })
  }

  return { text };
},

**5.**以上代码实现后,其实并没有真正实现响应式。至少说我们改变text数据,页面其他用到text的地方并没有改变。

原因就在于我们改变value值后触发get 函数后并没有去重新解析模板,set 也没有收到解析模板的命令。

因此customRef 函数中又有两个参数,track 函数和trigger 函数。

track函数用于通知vue追踪value的变化;trigger函数用于通知vue重新解析模板。

javascript 复制代码
setup() {
  let text = myRef("初始化");

  function myRef(value) {
    return customRef((track, trigger) => {
      return {
        get() {
          track();  // 通知vue追踪value的变化
          return value;
        },
        set(newValue) {
          value = newValue;
          trigger();  // 通知vue重新解析模板
        }
      }
    })
  }

  return { text };
},

**6.**最后我们加上定时器,就能实现防抖的效果。

javascript 复制代码
setup() {
  let text = myRef("初始化", 1000);

  function myRef(value, delay) {
    let timer;  // 定时器
    return customRef((track, trigger) => {
      return {
        get() {
          track();
          return value;
        },
        set(newValue) {
          // 如果定时器已经开启了,就清除当前定时器,新开一个定时器
          clearTimeout(timer);  
          timer = setTimeout(() => {
            value = newValue;
            trigger();
          }, delay);
        },
      };
    });
  }

  return { text };
},
相关推荐
愈努力俞幸运2 分钟前
chrome 扩展(插件)开发入门教程
前端·chrome
练习前端两年半18 分钟前
【Vue3 高级技巧】函数重载+Watch:打造类型安全的通用事件监听 Hook
前端·javascript·vue.js
一只小鸟儿30 分钟前
门户短信发送验证码及验证功能
前端·javascript·jquery
elangyipi12332 分钟前
pnpm :下一代包管理工具的原理与实践
前端·npm
代码的奴隶(艾伦·耶格尔)42 分钟前
Sentinel限流熔断
java·前端·sentinel
talenteddriver44 分钟前
mysql: MySQL中between子句和limit子句的区别
前端·javascript·数据库
A24207349301 小时前
深入浅出理解AJAX:核心原理与POST/GET区别详解
前端·ajax·okhttp
LYFlied1 小时前
【每日算法】LeetCode 300. 最长递增子序列
前端·数据结构·算法·leetcode·职场和发展
张较瘦_1 小时前
前端 | 代码可读性 + SEO 双提升!HTML 语义化标签实战教程
前端·html
似水流年QC1 小时前
前端国际化实战指南:i18n 工程化最佳实践总结
前端