Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

javascript - iOS下带小数点的数字键盘 - 个人文章 - SegmentFault 思否 #83

Open
HenryTSZ opened this issue Oct 18, 2023 · 0 comments

Comments

@HenryTSZ
Copy link
Owner

HenryTSZ commented Oct 18, 2023

https://segmentfault.com/a/1190000037775243

问题

业务开发中经常遇到要弹出数字键盘的问题,产品方希望弹出带小数点的纯数字键盘。
下面代码:

<input type='number'/>

在android下能弹出数字与小数点的键盘,而且自动会屏蔽非法字符,很完美。
但iOS下不是纯数字键盘,只是键盘的第一行是数字而已:

而且iOS下无法防止中文、字母、空格、及各种特殊符号。而且输入这些符号后绑定的值变成空,无法获取当前显示的内容。

这种键盘很难处理,在keydown input等事件里做输入拦截、过滤,难以处理所有状况。特别是切换到九宫格键盘后更是没法处理。

预期结果

我们想要这样的键盘:

这种键盘在很多app内部,以及一些组件库里都见到过。iOS原生很容易实现这种数字键盘,h5里比较麻烦。

解决方案如下:

这是一段vue代码:

<input v-model="purchaseMoney" type="text" inputmode="decimal" maxlength="12" placeholder="不少于0.01元" @input="onInputAmount($event)" @blur="onInputBlur($event)">

利用inputmode这个属性,详细请参考:https://developer.mozilla.org...

好,现在键盘已经是带小数点的数字键盘了。在iOS下safari,微信等大概看了下,目前都可以。

键盘是出来了,然后还需要写点逻辑处理一些非法情况:防止复制粘贴进来特殊字符、屏蔽表情、多个小数点并存、开头有多个0、替换开头的0为新的数字、控制小数为2位等。

onInputAmount() {
  let temp = this.purchaseMoney;
  if (temp) {
    temp = temp.replace(/[^0-9.]/g, '');

    
    if (temp && temp.length && temp.indexOf('.') != temp.lastIndexOf('.')) {
      var arr = temp.split('.');
      let first = arr.shift();
      temp = first + '.' + arr.join('');
    }
    
    if (temp.indexOf('.') != -1) {
      let intergerPart = temp.split('.')[0];
      let decimalPart = temp.split('.')[1];
      if (decimalPart.length > 2) {
        decimalPart = decimalPart.substring(0, 2);
      }
      temp = intergerPart + '.' + decimalPart;
    }

    
    while (/^0[0-9]/.test(temp)) {
      temp = temp.substring(1);
    }
  }
  this.purchaseMoney = temp;
},

至此,主要的功能基本满足了,以后发现问题再更新。

在用vant的组件时,看到field组件也是使用了inputmode方案,官网还有特别说明。

也可以配置为一个自定义指令:

/**
 * input输入框只能输入数字和小数点的检验指令
 */
export default {
  bind: (el, binding, vnode) => {
    // 获取 input dom
    const input = el.hasChildNodes() ? el.getElementsByTagName('input')[0] : el
    if (input) {
      // 设置为带小数点的数字键盘
      input.setAttribute('inputmode', 'decimal')

      input.addEventListener('input', e => {
        let temp = e.target.value
        if (temp) {
          // 删除非数字和小数点的字符
          temp = temp.replace(/[^0-9.]/g, '')

          // 解决多个小数点并存
          if (
            temp &&
            temp.length &&
            temp.indexOf('.') !== temp.lastIndexOf('.')
          ) {
            const arr = temp.split('.')
            const first = arr.shift()
            temp = `${first}.${arr.join('')}`
          }

          // 首位键入的是'.',则自动补'0',控制小数为 3 位
          if (temp.includes('.')) {
            let [integerPart, decimalPart] = temp.split('.')
            if (!integerPart) {
              integerPart = '0'
            }
            if (decimalPart.length > 3) {
              decimalPart = decimalPart.substring(0, 3)
            }
            temp = `${integerPart}.${decimalPart}`
          }

          // 开头有多个0、替换开头的0为新的数字
          while (/^0[0-9]/.test(temp)) {
            temp = temp.substring(1)
          }

          // 更新 input 值
          e.target.value = temp
          // e.target.dispatchEvent(new Event('input'))
          vnode.componentInstance.$emit('input', temp)
        }
      })
    }
  }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant