首页 前端知识 小输入框,大讲究:Table 数字输入框 debounce 实战分享

小输入框,大讲究:Table 数字输入框 debounce 实战分享

2025-02-24 13:02:35 前端知识 前端哥 215 960 我要收藏

前言

 📫 大家好,我是陈三心,热爱技术和分享,欢迎大家交流,一起学习进步!

 🍅 个人主页:陈三心

Table表格在前端开发中是十分常见的,用于展示结构化数据,如商品列表、用户信息等。

本文分享一下自己在表格开发中遇到的一个奇葩问题,以及采取的解决方法。 


目录

背景

编辑数量

极端情况

闭包

结语


背景

项目中使用Ant Design Vue进行表格的开发,允许用户直接在表格内编辑数量,如下:

上述就是本次任务需要实现的目标,是的,你没听错,就是这么简单。但其中却有着一个意想不到的坑,听我细细道来。

编辑数量

首先当然就是数据的获取了,在组件实例创建后调用接口获取列表数据。

<template>
  <a-table
    :columns="columns"
    :data-source="dataList"
  >
  </a-table>
</template>
<script>
export default {
  data() {
    return {
      // 设置表格列描述对象
      columns: [
        ...
      ],
      // 表格数据
      dataList: [],
    }
  },
  created() {
    this.getDataList()
  },
  methods: {
    /*
     * 获取数据列表
     */
    getDataList() {
      //此处省略...
    },
  },
}
</script>

编辑数量使用Ant Design Vue的数字输入框组件,利用table的scopedSlots进行列的自定义渲染。

<template>
  <a-table :columns="columns" :data-source="dataList">
    <template slot="productCount" slot-scope="text, record">
      <a-input-number
        v-model="record.productCount"
        @change="editNumber(record)"
      ></a-input-number>
    </template>
  </a-table>
</template>

<script>
export default {

  ...

  methods: {
    /**
     * 编辑数量
     * @param {object} row 物品信息
     */
    editNumber(row) {
      // 发送请求更新数量,更新完后重新获取数据
      ...
    },
  },
}
</script>

给数字输入框绑定change事件,只要改变数量就发送请求给后端触发更新。当然,这肯定是有问题的,频繁发送请求会造成性能消耗,所以加上防抖是很有必要的。对上述代码进行优化:

<script>
export default {

  ...

  methods: {
    /**
     * 编辑数量
     * @param {object} row 物品信息
     */
    editNumber: debounce(function (row) {
      // 发送请求更新数量,更新完后重新获取数据
      ...
    }, 1000),
  },
}
</script>

上述debounce可以使用lodash库中的防抖函数,如果不想引入额外的库,也可以自己手写封装,具体可以去看下我的这篇文章。

极端情况

到此,你以为编辑数量的功能就完成了吗?作为一个开发者,我们当然需要考虑各种极端情况,来看看下面这个:

上述场景中,使用上下箭头去修改当前行的数量,编辑完后立马点击另一行的数字输入框上下箭头修改数量,此时却只生效了后一个的数量编辑。

这是什么原因呢?思来想去,不如直接交给GPT来解答。

总结下问题原因其实就是,表格中的每个数字输入框绑定的是同一个debounce函数,共享了相同的debounce定时器。

知道问题原因后,解决思路就很简单了,为每个数字输入框元素创建独立的 debounce 实例,这样debounce的定时器不会在多个输入框间共享,每个元素都有自己的防抖逻辑。改进后的代码:

<template>
  <a-table :columns="columns" :data-source="dataList">
    <template slot="productCount" slot-scope="text, record, index">
      <a-input-number
        v-model="record.productCount"
        @change="debounceEditNumber(record, index)"
      ></a-input-number>
    </template>
  </a-table>
</template>

<script>

export default {
  data() {
    return {
      // 存储每个元素的 debounce 实例
      debouncedHandlers: {},
    }
  },
  methods: {
    /**
     * 为每个元素创建独立的 debounce 实例
     * @param {object} row 设备信息
     * @param {number} index 行索引
     */
    createDebouncedHandler(row, index) {
      // 清除已存在的 debounce 实例
      if (this.debouncedHandlers[index]) {
        this.debouncedHandlers[index].cancel()
      }

      // 创建新的 debounce 实例
      this.debouncedHandlers[index] = debounce(() => {
        this.editNumber(row)
      }, 1000)

      return this.debouncedHandlers[index]
    },

    /**
     * 编辑设备数量
     * @param {object} row 物品信息
     * @param {number} index 行索引
     */
    debounceEditNumber(row, index) {
      this.createDebouncedHandler(row, index)()
    },

    /**
     * 更新数量
     * @param {object} row 物品信息
     */
    editNumber(row) {
      // 发送请求更新数量,更新完后重新获取数据
      ...
    },
  },
}
</script>

组件实例销毁之前,需要在beforeDestroy中清理所有 debounce 实例,防止内存泄漏。

beforeDestroy() {
    // 清理所有 debounce 实例,防止内存泄漏
    Object.keys(this.debouncedHandlers).forEach((index) => {
      this.debouncedHandlers[index].cancel()
      delete this.debouncedHandlers[index]
    })
},

 现在的效果:

闭包

其实深入思考下,定时器之所以会共享,本质原因是 debounce 函数返回的是一个闭包。以下是debounce的内部实现逻辑:

function debounce(fn, delay = 500) {

    let timer = null;

    // 这里返回的函数是每次用户实际调用的防抖函数
    return function(...args) {	
    	// 如果已经设定过定时器了就清空上一次的定时器
    	if(timer) {
        	clearTimeout(timer);	
        }

        // 开始一个新的定时器,延迟执行用户传入的方法
        timer = setTimeout(() => {  
        	fn.apply(this, args);   
        }, delay)	
    }
}

使用闭包来保存定时器变量timer,每次实际调用的函数都可以访问到外层作用域中的这个timer,就会导致上述问题(闭包可以去看我的这篇文章)。

结语

🔥如果此文对你有帮助的话,欢迎💗关注、👍点赞、⭐收藏、✍️评论,支持一下博主~

 

转载请注明出处或者链接地址:https://www.qianduange.cn//article/21261.html
标签
评论
发布的文章

C/C | 每日一练 (2)

2025-02-24 13:02:49

Linux性能监控工具汇总

2025-02-24 13:02:48

Python常见面试题的详解16

2025-02-24 13:02:48

QQ登录测试用例报告

2025-02-24 13:02:47

大家推荐的文章
会员中心 联系我 留言建议 回顶部
复制成功!