微信小程序 - 自定义计数器 - 优化(键盘输入校验)

微信小程序通过自定义组件,实现计数器值的增加、减少、清零、最大最小值限定、禁用等操作。通过按钮事件触发方式,更新计数器的值,并修改相关联的其它变量。通过提升用户体验,对计数器进行优化设计,使用户操作更加便捷和直观。

计数器的实现主要涉及到几个关键部分,上一篇已重点讲过,该篇将讲述一下中间input输入框值变化后的校验操作。

由于该篇是接上一篇继续完善和优化,所以建议先了解上一篇后,再来看此篇内容。地址:微信小程序 - 自定义计数器-CSDN博客

如上图中,增加、减小按钮操作已限定了其值范围;但是通过小键盘输入内容后,发现值并不正规或者已超出了其限定范围,所以需要增加监听input输入框的内容变化,对其值进行校验和处理。

一、bindinput事件监听

首页需要在Counter计数器中绑定监听事件,bindinput事件会在每次输入一个数字、字母或符号时执行一次。index.wxml代码如下:

html 复制代码
<view class="counter-wrap">
  <button class="btn mul" disabled="{{isDisabledMul}}" bind:tap="mulEvent">-</button>
  <input type="number" value="{{value}}" class="number" bindinput="inputEvent" />
  <button class="btn add" disabled="{{isDisabledAdd}}" bind:tap="addEvent">+</button>
</view>

index.js中添加inputEvent监听事件,代码如下:

javascript 复制代码
// components/Counter/index.js
Component({
  /**
   * 组件的属性列表
   */
  properties: {
    // 值
    value: {
      type: Number,
      value: 0
    },
    // 目标key
    target: {
      type: String,
      value: ''
    },
    // 最小值
    min: {
      type: Number,
      value: null
    },
    // 最大值
    max: {
      type: Number,
      value: null
    }
  },
  /**
   * 组件的初始数据
   */
  data: {
    isDisabledAdd: false,     // 是否禁用 加 按钮
    isDisabledMul: false,     // 是否禁用 减 按钮
  },
  /**
   * 组件的方法列表
   */
  methods: {
    // 略...    

    // 输入后 监听事件
    inputEvent(e){
      console.log(e.detail.value);
    }
  }
})

如代码所示,inputEvent监听事件中,是通过e.detail.value获取修改后的新内容。

二、防抖操作

每输入一个数字,inputEvent函数则会被执行一次,此时用户内容可能并没有输入完整,所以这里增加一个计时器,当用户最后一次输入内容,再执行数值校验。代码如下:

javascript 复制代码
// components/Counter/index.js
Component({
  /**
   * 组件的属性列表
   */
  properties: {
    // 值
    value: {
      type: Number,
      value: 0
    },
    // 目标key
    target: {
      type: String,
      value: ''
    },
    // 最小值
    min: {
      type: Number,
      value: null
    },
    // 最大值
    max: {
      type: Number,
      value: null
    }
  },
  /**
   * 组件的初始数据
   */
  data: {
    isDisabledAdd: false,     // 是否禁用 加 按钮
    isDisabledMul: false,     // 是否禁用 减 按钮
  },
  /**
   * 组件的方法列表
   */
  methods: {
    // 略...

    // 输入后  监听事件
    inputEvent(e){
      clearTimeout(this.inputHandle);
      // 开始计时
      this.inputHandle = setTimeout((value) => {
        
      }, 800);
    }
  }
})

在每次执行inputEvent函数时,先清除上一次计时器,这样就只会执行最后一次计时器的回调函数。

三、形参传递

如图所示,键盘输入的内容会出现很多种情况,"0232"需要使用parseInt(e.detail.value)转化为"232","adfs"通过parseInt转换后,会变成"NaN"。

另外,在修正父组件中value值时,需要先把未校验的内容传给父组件中变量;例如:当父组件中值为0时,用户输入内容为-1200小于最小值0,校验后虽然给父组件中值重新赋值为0,但之前值为0未发生变化,此时输入框中还是显示-1200。所以此处需要先将错误值传递给父组件中的变量,再进行校验处理,这样则需要对旧值进行备份。

对于JS中的计时器,很多人可能还不知道其能传递形参,这块知识在之前一篇中也讲述过,需要了解的可以去查看。地址:setTimeout和setInterval区别,以及定时器的传参功能-CSDN博客

setTimeout参数

参数 描述
func 必需。要执行的javascript代码串,也可以是一个函数
time 必需。执行周期(毫秒数)
param1, param2, ... 可选。传入执行函数其他参数

将parseInt之后的新值,和之前旧值,通过计时器的形参传递到下个执行函数中,代码如下:

javascript 复制代码
// components/Counter/index.js
Component({
  /**
   * 组件的属性列表
   */
  properties: {
    // 值
    value: {
      type: Number,
      value: 0
    },
    // 目标key
    target: {
      type: String,
      value: ''
    },
    // 最小值
    min: {
      type: Number,
      value: null
    },
    // 最大值
    max: {
      type: Number,
      value: null
    }
  },
  /**
   * 组件的初始数据
   */
  data: {
    isDisabledAdd: false,     // 是否禁用 加 按钮
    isDisabledMul: false,     // 是否禁用 减 按钮
    inputHandle: null,        // 计时器手柄
  },
  /**
   * 组件的方法列表
   */
  methods: {
    // 略...

    // 输入后  监听事件
    inputEvent(e){
      clearTimeout(this.inputHandle);
      // 开始计时
      this.inputHandle = setTimeout((nValue, oValue) => {
       
        console.log('e', oValue, nValue);
      }, 800, parseInt(e.detail.value), this.data.value);
    }
  }
})

这样,像"032"之类新值,则会转换为正常数值传递到下次执行函数中;旧值则通过oValue往下传递,当父组件中value被替换后,this.data.value被修改,也不会影响到oValue,使其缓存到下次执行函数中备用。

四、判断是否为NaN

当最后一次校验函数执行后,parseInt(e.detail.value)传递的新值如果为NaN,则将其置回来之前旧值,为了确保值能正常被更新,所以需要先将父组件中的变量赋值为未校验的值。代码如下:

javascript 复制代码
// components/Counter/index.js
Component({
  /**
   * 组件的属性列表
   */
  properties: {
    // 值
    value: {
      type: Number,
      value: 0
    },
    // 目标key
    target: {
      type: String,
      value: ''
    },
    // 最小值
    min: {
      type: Number,
      value: null
    },
    // 最大值
    max: {
      type: Number,
      value: null
    }
  },
  /**
   * 组件的初始数据
   */
  data: {
    isDisabledAdd: false,     // 是否禁用 加 按钮
    isDisabledMul: false,     // 是否禁用 减 按钮
    inputHandle: null,        // 计时器手柄
  },
  /**
   * 组件的方法列表
   */
  methods: {
    // 略...

    // 输入后  监听事件
    inputEvent(e){
      clearTimeout(this.inputHandle);
      // 开始计时
      this.inputHandle = setTimeout((nValue, oValue) => {
        this.triggerMsg(e.detail.value);     // 先置为输入内容,后续校验后再相应调整
        // 判断内容是否为NaN
        if(isNaN(nValue)) {
          this.triggerMsg(oValue);
          return;
        }
        console.log('e', oValue, nValue);
      }, 800, parseInt(e.detail.value), this.data.value);
     
    }
  }
})

此时,再输入像"adfs"之类内容,则会被置为之前旧值。当然,这里输入框input的类型为number,在手机端出现的键盘为 数字键盘,不会出现输入字母情况。但为程序严谨性,或以防某些平台存在兼容问题,还是需要考虑到这一步。

五、最小值和最大值校验

对于最大值和最小值的校验,在上一篇中已有,并对之前判断稍作修改,这个大家慢慢细评、多思考。代码如下:

javascript 复制代码
// components/Counter/index.js
Component({
  /**
   * 组件的属性列表
   */
  properties: {
    // 值
    value: {
      type: Number,
      value: 0
    },
    // 目标key
    target: {
      type: String,
      value: ''
    },
    // 最小值
    min: {
      type: Number,
      value: null
    },
    // 最大值
    max: {
      type: Number,
      value: null
    }
  },
  /**
   * 组件的初始数据
   */
  data: {
    isDisabledAdd: false,     // 是否禁用 加 按钮
    isDisabledMul: false,     // 是否禁用 减 按钮
    inputHandle: null,        // 计时器手柄
  },
  /**
   * 组件的方法列表
   */
  methods: {
    // 略...

    // 输入后  监听事件
    inputEvent(e){
      clearTimeout(this.inputHandle);
      // 开始计时
      this.inputHandle = setTimeout((nValue, oValue) => {
        this.triggerMsg(e.detail.value);     // 先置为输入内容,后续校验后再相应调整
        // 判断内容是否为NaN
        if(isNaN(nValue)) {
          this.triggerMsg(oValue);
          return;
        }
        // 判断值是否小于最小值
        if(this.data.min != null && this.data.min >= nValue) {
          this.triggerMsg(this.data.min);                   // 将值置为最小值
          this.setData({ isDisabledMul: true });            // 当底于最小值时,禁用 减 按钮
          // 如果减小按钮禁用,解除增加按钮的禁用
          if(this.data.isDisabledAdd) this.setData({ isDisabledAdd: false }); 
          return;
        } else if(this.data.isDisabledMul) {
          this.setData({ isDisabledMul: false }); 
        }
        // 判断值是否大于最大值
        if(this.data.max != null && this.data.max <= nValue)  {
          this.triggerMsg(this.data.max);                   // 将值置为最大值
          this.setData({ isDisabledAdd: true });            // 当超过最大值时,禁用 加 按钮 
          // 如果增加按钮禁用,解除减小按钮的禁用
          if(this.data.isDisabledMul) this.setData({ isDisabledMul: false }); 
          return;
        } else if(this.data.isDisabledAdd) {
          this.setData({ isDisabledAdd: false }); 
        }
        console.log('e', oValue, nValue);
      }, 800, parseInt(e.detail.value), this.data.value);

    }
  }
})

此时,通过键盘输入内容后,如果不符合规范内容,或者超出限定范围的值,都会被立即纠正,并改回之前的值。如下图:

上篇中addEvent事件函数和mulEvent事件函数中,都有对最大值和最小值的判断,如果觉得此处代码较为冗余,大家可以自行调整,合并代码。由于这里只是演示效果,就不细分了。

相关推荐
GISer_Jing2 小时前
前端面试通关:Cesium+Three+React优化+TypeScript实战+ECharts性能方案
前端·react.js·面试
落霞的思绪3 小时前
CSS复习
前端·css
咖啡の猫5 小时前
Shell脚本-for循环应用案例
前端·chrome
百万蹄蹄向前冲7 小时前
Trae分析Phaser.js游戏《洋葱头捡星星》
前端·游戏开发·trae
朝阳5818 小时前
在浏览器端使用 xml2js 遇到的报错及解决方法
前端
GIS之路8 小时前
GeoTools 读取影像元数据
前端
ssshooter9 小时前
VSCode 自带的 TS 版本可能跟项目TS 版本不一样
前端·面试·typescript
你的人类朋友9 小时前
【Node.js】什么是Node.js
javascript·后端·node.js
Jerry9 小时前
Jetpack Compose 中的状态
前端
dae bal10 小时前
关于RSA和AES加密
前端·vue.js