Vue3:搜索框输入防抖实现整理笔记

news2024/11/16 20:47:14

目录

场景需求

前言

防抖 & 节流

防抖

节流

输入防抖存在的问题

指令实现

总结


在Vue开发中,遇到了搜索框输入防抖处理,算是防抖的使用场景之一吧,抽象其逻辑记录下来以备后用

场景需求

作为开发人员,一定要先搞清楚场景需求是什么

  • 场景需求:
    • 搜索输入时 ,判断用户在输入完成后 实现即时的自动搜索
    • 并且要防止过度自动搜索消耗性能

想想如何才能在vue中实现

前言

「搜索」这个场景在各种业务的系统中都是是非常常见的,比如电商平台的商品搜索、百度搜索、掘金搜索、google搜索......,只要是有内容呈现给用户的,都少不了搜索功能。

按照触发搜索动作的不同可分为:

  1. 输完关键字后手动触发搜索
  2. 输入字符自动搜索

第一种是由用户去决定何时进行搜索,没啥问题。

第二种是通过监听用户录入的事件自动搜索,自动搜索能在一定程度上提升用户体验(比如在用户输入时关键词联想提示),同时也可能会带来问题,因为input事件触发是非常频繁的,比如下面这个示例:

打开百度的搜索,找到输入框的dom,然后绑定一个input事件,看看我们录入一个telephone会触发多少次input事件:

temp1.addEventListener('oninput', (val) => console.log(val))

触发了10次:

 

那如果每触发一次都会调用后台接口查询,那当用户量足够大,就会给后台服务器带来很大的压力,导致接口响应慢,甚至引起服务器宕机,也会给用户带来不好的体验。

为了不引起过多请求给服务端造成压力,我们期望在用户在输入完以后再发起请求,那怎么判断用户是否输入完了❓

可以认为当用户在一个固定的时间内都没有录入字符是输入完成/暂时输入完成。这个是老生常谈的知识点了————「防抖」和「节流」。掘金有很多文章专门写这个的,笔者在此不过多描述,简单一笔带过说下笔者的看法。

防抖 & 节流

防抖

防抖的函数在调用后,如果在防抖时间内没有再次触发,就会在过了 防抖时间 后执行;如果在防抖时间内再次触发,不论触发多少次,执行的时机会一直往后延迟,直到满足最后一次调用时间 小于 当前时间减去防抖时间才会执行。

function debounce(fn, time) {
  let timer
  return function (...argu) {
    if (timer) {
      clearTimeout(timer)
      timer = null
    }
    timer = setTimeout(() => {
      fn(...argu)
      clearTimeout(timer)
      timer = null
    }, time)
  }
}

节流

节流函数在调用后,在设置的节流时间后执行一次,在此期间,不论触发多少次,都直接return了。

function throttle(fn, time) {
  let flag = true
  return function (...argu) {
    if (!flag) {
      return
    }
    flag = false
    let timer = setTimeout(() => {
      fn(...argu)
      flag = true
      clearTimeout(timer)
      timer = null
    }, time)
  }
}

再来看下加了防抖 & 节流 处理的input事件执行情况:

  • 防抖:

  • 防抖 + 节流:

从上面的两个图不难看出防抖 和节流的区别,节流的函数如果一直被触发,每隔一段时间执行一次。而防抖则是一直延迟,最后执行一次。

输入防抖存在的问题

上面的防抖函数执行貌似没啥问题,前提是我们输入的是英文,如果是中文输入就出问题了

当中文输入的时候,即使已经防抖处理了,还可能会执行多次。接下来咱们进入正题了,如何实现输入防抖Vue3指令(并解决中文输入触发多次的问题)。

指令实现

为什么要以指令的方式实现❓我能想到的有以下两点:

  • 将防抖处理的逻辑封装在指令内部重用,更易用。
  • 指令要支持input输入框,也要支持封装input的组件,也就是说需要进行底层 DOM 访问的逻辑,而这一点恰好是指令提供的能力之一。

需要补充Vue 指令相关知识的同学点这里自定义指令

期望使用方式:

<template>
  <input v-model="val" v-debounceInput:600="onInput" />
</template>
 
<script setup lang="ts">
import { ref } from 'vue'
 
const val = ref('')
function onInput(e: Event): void {
  console.log(e)
}
</script>

即指令的绑定值为 执行逻辑,指令参数为 防抖时长。

指令实现:

import { debounce, isFunction } from '../../utils/index'
 
let inputFunction: (event: Event) => {}
 
// 由于要同时支持 input 输入框和封装 input 的组件,因此需要去找到input这个元素。
function findInput(el: HTMLElement): HTMLElement | null {
  const quene: HTMLElement[] = []
  quene.push(el)
  while (quene.length > 0) {
    const current = quene.shift()
    if (current?.tagName === 'INPUT') {
      return current
    }
    if (current?.childNodes) {
      quene.push(...current.childNodes)
    }
  }
  return null
}
 
export default {
  mounted(el: HTMLElement, binding: any) {
    const { value, arg } = binding
    if (value && isFunction(value)) {
      let timeout = 600
      if (arg && !Number.isNaN(arg)) {
        timeout = Number(arg)
      }
      inputFunction = debounce(value, timeout) // 执行函数防抖处理
      const input = findInput(el)
      el._INPUT = input
      if (input) {
        input.addEventListener('input', inputFunction)
      }
    }
  },
  beforeUnmount(el: HTMLElement) {
    if (el._INPUT) {
      el._INPUT.removeEventListener('input', inputFunction)
      el._INPUT = null
    }
  }
}

接着处理中文输入可能会触发多次的问题。可借助compositionstart和compositionend来实现。

  • 输入法编辑器开始新的输入合成时会触发 compositionstart 事件。例如,当用户使用拼音输入法开始输入汉字时,这个事件就会被触发。
  • 当文本段落的组成完成或取消时,compositionend 事件将被触发 (具有特殊字符的触发,需要一系列键和其他输入,如语音识别或移动中的字词建议)。

在一开始拼音输入法时就设置composing为true,因此在compositionEnd没有调用之前都不会执行函数,等compositionEnd调用,通过dispatchEvent派发一个input事件出去,保证逻辑一定会执行。

function compositionStart(event: CompositionEvent) {
  event.target.composing = true
}
function compositionEnd(e: CompositionEvent) {
  e.target.composing = false
  const event = new Event('input', { bubbles: true })
  e.target?.dispatchEvent(event)
}

export default {
  mounted(el: HTMLElement, binding: any) {
    //...
      if (input) {
        input.addEventListener('input', inputFunction)
        input.addEventListener('compositionstart', compositionStart)
        input.addEventListener('compositionend', compositionEnd)
      }
    //...
  },
  beforeUnmount(el: HTMLElement) {
    if (el._INPUT) {
      el._INPUT.removeEventListener('input', inputFunction)
      el._INPUT.removeEventListener('compositionstart', compositionStart)
      el._INPUT.removeEventListener('compositionend', compositionEnd)
    }
  }
}

防抖实现 & 判断是 function

export function debounce(input: (event: Event) => any, timeout: number): (this: HTMLElement, ev: Event) => any {
  let timer: string | number | NodeJS.Timeout | undefined
  return (event: Event) => {
    // @ts-ignore
    if (event.target.composing === true) {
      return
    }
    if (timer) {
      clearTimeout(timer)
      timer = undefined
    }
    timer = setTimeout(() => {
      input(event)
      clearTimeout(timer)
      timer = undefined
    }, timeout)
  }
}

export function isFunction(param: any): boolean {
  return Object.prototype.toString.call(param) === '[object Function]'
}

注册指令(全局注册):

createApp(App).directive('debounceInput', debounceInput).mount('#app')

写个案例测试一下:

<template>
  <div>防抖</div>
  <input v-model="val" v-debounceInput="onInput" />
  <div>普通</div>
  <input v-model="count" type="text" @input="onInput" />
</template>
 
<script setup lang="ts">
import { ref } from 'vue'
 
const val = ref('')
const count = ref('')
function onInput(e: Event): void {
  console.log('调用了onInput')
}
</script>

差别还是非常明显的。指令已发布npm仓库,有需要可自取。

总结

🌹感谢浏览,通过本文你可以了解到以下内容:

  • 防抖
  • 节流
  • Vue3指令开发
  • compositionstart 事件 (需要注意浏览器兼容性)
  • compositionend 事件(需要注意浏览器兼容性)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/130390.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Android---Material Design

目录 一、什么是Material Design Z轴 Material Design 的一些 theme 一、什么是Material Design Material Design 中文名&#xff1a;材料设计语言&#xff0c;是由 Google 推出的全新的设计语言。Google 表示&#xff0c;这种设计语言旨在为手机、平板、台式机和“其它平台”…

标签平滑(Label Smoothing)详解

一、什么是label smoothing&#xff1f; 标签平滑&#xff08;Label smoothing&#xff09;&#xff0c;像L1、L2和dropout一样&#xff0c;是机器学习领域的一种正则化方法&#xff0c;通常用于分类问题&#xff0c;目的是防止模型在训练时过于自信地预测标签&#xff0c;改善…

spring6笔记2( ioc、bean的作用域、工厂模式、bean的四种实例化方式,生命周期)

第四章、Spring对ioc的实现 4.4 p命名空间注入 目的&#xff1a;简化配置。 使用p命名空间注入的前提条件包括两个&#xff1a; 第一&#xff1a;在XML头部信息中添加p命名空间的配置信息&#xff1a;xmlns:p"http://www.springframework.org/schema/p"第二&…

wanglinrong 程序 环境配置

1、总体要求 我的matlab版本是 r2020b、matconvnet-1.0-beta25、visual studio 2022。笔记本安装&#xff0c;没考虑GPU。建议vs的版本尽量比matlab版本低。 1.1 完美解决方案&#xff1a; 低版本Visual Studio与高版本Matlab&#xff0c;先装vs 后装matlab&#xff01; 比如…

windows下PyTorch安装教程(1.10)

文章目录一.pytorch 1.10版本安装教程一.pytorch 1.10版本安装教程 PyTorch官网 pytorch与cuda版本关系 官网 从官网选择自己对应的conda,python,cuda版本&#xff0c;复制conda命令 在windows搜索框中搜索CMD&#xff0c;选择以管理员身份运行 使用conda新建虚拟环境pyt…

arthas离线包使用说明

arthas离线包使用说明 基于私有化全内网场景&#xff0c;打包了一套arthas离线包&#xff0c;方便后续对服务进行调试和问题的定位。 首先将arthas-bin.zip导入到服务器中 下载连接&#xff1a;https://download.csdn.net/download/Decembetion/87347459 将zip包解压 #解压 unz…

c4d导入大模型以及给建筑上贴图笔记

快捷键普及 h定位 o 鼠标中键 切换视图 鼠标左键移动视图 坐标轴反了&#xff0c;按w切换 alt左键 旋转 alt中键移动 alt右键 缩放 导入超大模型 导入后什么都看不到需要在工程属性里面修改为极大 image.pngshiftf2弹出材质编辑器 点四条杠可以移动选项卡 image.png点新建材质之…

基于GUI界面的yolov5人脸口罩检测项目

文章目录 前言 一、运行环境 二、环境配置 三、yolov5网络结构图介绍 四、 损失函数 五、数据集 六、实验内容 1.实验框架 2.实验环境 3.实验结果 前言 佩戴口罩可以有效降低在和感染者有接触时可能被感染者感染的风险。目前&#xff0c;在一些公共场所&#xff0c…

c++结构体数组sort排序出错?(关于sort排序comp比较器的严格弱排序性质)

文章目录sort的严格弱排序的性质无效的比较器&#xff08;Invalid comparator&#xff09;正确的比较器sort的严格弱排序的性质 我在给结构体数组排序的时候&#xff0c;自定义了sort函数的排序法则&#xff0c;我的结构体如下定义&#xff1a; struct score {int a, b, c;//…

English Learning - L1-8 时态(上) 2022.12.29 周四

English Learning - L1-8 时态&#xff08;上&#xff09; 2022.12.29 周四8 时态为什么时态难学&#xff1f;什么是时态&#xff1f;如何套用时态表8.1 一般时态核心思维&#xff08;一&#xff09; 一般现在时核心思维用法1. 普遍的事实和真理2. 重复活动&#xff08;习惯&am…

166页7万字智慧工厂可视化解决方案

【版权声明】本资料来源网络&#xff0c;仅用于行业知识分享&#xff0c;供个人学习参考&#xff0c;请勿商用。【侵删致歉】如有侵权请联系小编&#xff0c;将在收到信息后第一时间进行删除&#xff01;完整资料领取见文末&#xff0c;部分资料内容&#xff1a; 第 一 章 应用…

QT VS移植过程中出现的问题以及解决记录

目录 一、无法定位程序输入点于动态链接库 二、E1696 无法打开 源 文件 “QString“ 三、编译Qt项目提示 error MSB6006: “cmd.exe”已退出 四、禁止显示状态 错误 MSB8036 找不到 Windows SDK 五、E2512 功能测试宏的参数必须是简单标识符 六、Qt VS中双击ui文件无法打…

【计算机模型机设计】单周期MIPS CPU设计报告

2022年结束了&#xff0c;过去一年确实发生了很多事情&#xff0c;开心的、伤心的、激动的、平凡的…这些都已经成为过去了&#xff0c;只希望在新的一年里&#xff0c;能够多一些开心&#xff0c;少一些emo&#xff0c;做一些自己喜欢的事情。 其实说实话&#xff0c;感觉我的…

Linux驱动之平台总线

文章目录前言一、什么是平台总线&#xff1f;二、平台总线相关的结构体三、平台总线的注册和注销四、总线平台的框架总结前言 一个完整的驱动程序总是由三部分组成&#xff1a;设备、总线、驱动 设备就好比我们的硬件&#xff1a;比如oled &#xff0c;那么总线就相当于iic总线…

Faster RCNN网络源码解读(Ⅲ) --- 如何搭建自己的数据集

目录 一、如何生成类似pascal voc一样结构的文件&#xff08;split_data.py&#xff09; 二、如何创建属于自己的数据集&#xff08;my_dataset.py&#xff09; 2.1 代码 2.2 代码解释 2.2.1 初始化函数__init__ 2.2.2 parse_xml_to_dict函数&#xff08;解析xml文件&…

35岁程序员还能找到工作吗?60%选择转岗项目经理!

我因为工作关系接触过大把的程序员朋友&#xff0c;知道他们都有35岁年龄焦虑&#xff0c;曾经他们在群里调侃程序员的尽头是开出租车和开饭店。毕竟一个公司的CTO只有一个&#xff0c;随着年龄的增长他们的体力和学新的技术都会明显吃力&#xff0c;慢慢就承受不起失业&#x…

[极客大挑战 2019]Havefun1、EasySQL(BUUCTF)

前言: 这篇文章还是是为了帮助一些 像我这样的菜鸟 找到简单的题解 今天是2022年的最后一天&#xff0c; 这一年我居然写了72篇文章 获得5枚勋章 还多了14个粉丝 好了不说了&#xff0c;上水题的题解 EasySQL题目描述 解题工具: 不需什么工具&#xff0c;如题名easy …

元宇宙产业委员会发布《第一届第六次主任委员会议公报》

2022年12月29日中国移动通信联合会元宇宙产业工作委员会第一届第六次主任委员会议书面召开&#xff0c;共同主席3人、学术指导3人、产业指导3人&#xff0c;联席主任委员3人、执行主任委员4人、常务副主任委员9家/人、副主任委员25家/人均以通信方式出席会议并表决相关事项。 …

深入分析Linux虚拟化KVM-Qemu之ARMv8虚拟化

说明&#xff1a; KVM版本&#xff1a;5.9.1 QEMU版本&#xff1a;5.0.0 工具&#xff1a;Source Insight 3.5&#xff0c; Visio 1. 概述 KVM虚拟化离不开底层硬件的支持&#xff0c;本文将介绍ARMv8架构处理器对虚拟化的支持&#xff0c;包括内存虚拟化、中断虚拟化、I/O虚…

BM33 二叉树的镜像

题目 操作给定的二叉树&#xff0c;将其变换为源二叉树的镜像。 数据范围&#xff1a;二叉树的节点数 0≤n≤1000&#xff0c; 二叉树每个节点的值 0≤val≤1000。 要求&#xff1a; 空间复杂度 O(n)。本题也有原地操作&#xff0c;即空间复杂度 O(1)的解法&#xff0c;时间…