表单交互问题小记

一、input输入手机号时的注意事项

需求说明:
用户手机聚焦input后,弹出数字键盘,可以正常输入11位手机号,也可以从电话本复制电话号然后直接执行粘贴操作。

问题说明:
1.input聚焦时弹出数字键盘,type=number时,安卓正常,ios无效。
2.当input type 为number时,input加maxlength限制长度属性无效。
3.ios上粘贴电话号到input中会有空格,且获取不到数据。

问题解决:

  1. 因为手机号都是数字,为了方便用户体验,我们会选择input聚焦时,手机上直接弹出数字键盘,此时,input type类型应该为:number,设置此属性后,安卓上能够正常显示数字键盘,但是ios不行,此时,需要再加上一个属性:pattern="\d*",pattern用于规定输入内容的模式和格式,加上这两个属性,就可以正常弹出数字键盘,但是ios数字键盘上没有小数点。
    示例:
// 使用type=number
// <input type="number“ pattern="\d*" />

// 使用type=tel
<input type="tel" />

2、当type为number时,发现maxlength并不生效,此时可以采用以下方式:

<input type="number" oninput="if(value.length>11)value=value.slice(0,11)" />

// 或者
<input type="number“ pattern="\d*" @input="handleInput" />
...
handleInput(e){
    let value = e.target.value + '';
    if(value.length > 11){
        this.mobile = value.slice(0, 11);
    }
}

// 或者
<input type="tel" maxlength="11" />
然后对输入做非数字禁止输入的校验

3、在ios系统上,当input type为number时,将复制的手机号粘贴到input中时,是拿不到数据的,但是在安卓手机上,可以成功复制到手机号;
因为number为数值类型,而复制的手机号是文本类型,可以考虑将number改为text或者tel。

// js
<input type="tel" name="searchText" id="searchText" placeholder="输入用户手机号"
        oninput="value=value.replace(/[^0-9]/ig,''); if(value.length>11)value=value.slice(0,11)"
        onkeypress="return( /[\d]/.test(String.fromCharCode(event.keyCode) ) )" />
        
// vue
<input type="tel" pattern="\d*" name="mobile" v-model.trim="mobile" @input="handleInput" placeholder="输入手机号" />
...
handleInput(e){
  let value = e.target.value + '';
  // 如果有空格,去掉空格
  let regSpace = /\s/;
  if(regSpace.test(value)){
    this.mobile = value.replace(/\s+/g, "");
    return;
  }
  // 限制输入位数
  if (value.length > 11) {
    this.mobile = value.slice(0, 11);
  }
}       

4、有的复制手机号,前面会有86,这时候在限制11位的情况下,会截掉后两位,如果有限制位数的需求的话,可以用正则去掉前面的86;
综上几种情况,可以把手机号的输入限制如下:

<input type="tel" v-model.trim="mobile" placeholder="请输入手机号" @input="handleMobile" />

// 1、不能超过11位;2、复制粘贴后,保证只有11位有效电话[去掉86、空格、中间的短横线]
handleMobile(e) {
  let value = e.target.value;

  // 去掉空格和非数字
  value = value.replace(/[^0-9]/ig, '');

  // 去掉在电话本中复制的86
  let reg1 = /^(\+86)/;
  if (reg1.test(value)) {
    value= value.slice(3);
  }

  let reg2 = /^(\86)/;
  if (reg2.test(value)) {
    value= value.slice(2);
  }

  // 限制输入位数
  if (value.length > 11) {
    value = value.slice(0, 11);
  }

  this.mobile = value;
}

二、输入框禁止输入

1、实现达到条件后禁止表单输入

// js中,必须将当前DOM节点传递出去,修改此节点的value值
<input type="tel" oninput="fn(this)" />
function fn(obj) {
    obj.value = obj.value.replace(/[^0-9]/gi,'');
}


// vue,同样修改当前节点的值,不能使用this,可以使用$event,当前事件,用e.target.value获取当前值
@input="fn(e)"  
let value = e.target.value
🌰:
// 非数字禁止输入
this.mobile = value.replace(/[^0-9]/ig,'');

// 超过某个数值禁止输入
if(value > 100) {
    this.mobile = value.replace(/[^0-9]/ig,'').slice(0, value.length-1);
    alert('超过最大数量')
}

2、在vue中使用computed的get和set方式禁止表单输入
当你读取一个变量的时候会触发该变量的getter.
当你修改该变量时候会触发他的setter.
当修改表单中双向绑定的值是,先触发setter,再触发getter

<input type="number" @input="watchCurNum" @blur="defaultCurNum" 
 v-model.number="curNum" ref="numDom" onpaste = "return false;"/>
 
 data() {
     return {
         curNum1: 1,  // 当前份数
     }
 }
 
 computed: {
     // 份数计算
    curNum: {
      get() {
        let value = this.curNum1;
        if (value >= this.maxNum) {
          this.$toast({
            message: '购买数量超出范围'
          })
          this.maxFlag = true;
          return value;
        } else {
          this.maxFlag = false;
          return value;
        }
      }, 
      set(val) {
        if(val <= this.maxNum) {
          this.curNum1 = val;
        } else {
          this.$forceUpdate();
          this.$toast({
            message: '购买数量超出范围'
          })
        }
        if(val == 0 && this.curNum1 == '') {
          this.curNum1 = ''
        }
      }
    }
 }

三、input为number时注意事项

1、input的type为number是,可以输入除了数字之外的:e[e在数学上代表2.71828,也是数字]、+、-、.[小数点]、以及在iOS数字键盘上出现的各种标点符号都可以输入;
但是如果是这样:

<input type="number" v-model="money" placeholder="请输入金额" @input="handleMoney" />
// 依次输入:34e.e.23...e234.e.e
// 控制台打印的value是:3 34 '' '' '' '' 
// 即输入非数字的,就获取不到value的值
// 如果输入400.22 控制台可以打印出400.22
// 如果输入400.22.44 控制台可以打印出''

可以考虑用number做输入金额的限制,最多只有一位小数点,但是由于number类型有太多限制,因此使用text

<input type="text" v-model="money" placeholder="请输入金额" @input="handleMoney" />

// 只能输入金额,包含一个小数点,两位小数位;【缺点:不能调起数字键盘】
handleMoney(e) {
  let value = e.target.value;

  value = value.replace(/[^\d.]/g, '');
  value = value.replace('.','$#$').replace(/\./g,'').replace('$#$','.');
  value = value.replace(/^(\-)*(\d+)\.(\d\d).*$/, '$1$2.$3');

  // 如果第一位是小数点
  if(value.indexOf('.') == 0) {
    value = '0' + value;
  }  
  this.money = value;
}

2、number基础用法,数值大小限制
min和max只对可操作的上下箭头有效[如下图],还是可以输入任意数值

<input type="number" v-model="number" placeholder="请输入数值" max="10" min="1"/>

四、iOS上使用oninput的问题

问题:我们经常会用oninput监听表单的值变化,做一些正则校验;但是在iOS中,使用oninput并在其中写了类似于"value=value.replace(/\s/g, '')"这样的语句后,会发现输入中文时,会将拼音输入其中,并且maxlength也会失效;

经过查资料,原因是:文本框会填入 “虚拟文本”(待确认文本),同时触发input事件;
因此我们可以修改为在触发compositionend时,就是填入实际内容后(已确认文本),再给输入框赋值:

<input type="text" id="test" v-model="textTest" placeholder="请输入姓名或者身份证"  />

var flag = true;
$('#test').on('compositionstart',function(){
    flag = false;
})
$('#test').on('compositionend',function(){
    flag = true;
})
$('#test').on('input',function(){
  var _this = this;
    setTimeout(function(){
        if(flag){
            // console.log(1);
            _this.value = _this.value.replace(/\s/g, '').slice(0,6);
        }
    },0)
})

1、此现象只会出现在oninput方法上,经过验证在Vue中使用@input并不会有此现象
2、限制长度最好使用slice截断,使用maxlength有时候会出现闪烁的现象【尤其是在iOS上输入时,且有待确认文本时】
3、此种限制也可以用在输入框实时搜索中的节流

五、解决IOS12以上微信内置浏览器下键盘收起底部空白的问题

原始做法如下,可以解决问题,但是毕竟粗鲁,在切换输入框时能看到明显的抖动现象;

// 原始做法1:
window.scroll(0,0);

// 原始做法2:
document.body.scrollIntoView();

优化做法,只在iOS中生效,每次切换输入框页面滑动较少【亲测有用】:即在当前页面滚动的位置上下滚动1px的距离即可实现页面的自适应

let _this = this;
let ua = window.navigator.userAgent;
let app = window.navigator.appVersion;
//$alert('浏览器版本: ' + app + '\n' + '用户代理: ' + ua);
if(!!ua.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/)){
  // alert('ios端');  
  document.addEventListener('blur', function(e) {
    if(['input', 'textarea'].includes(e.target.localName)) {
      var currentPosition,timer;
        var speed=1;
        timer=setInterval(function(){
            currentPosition=document.documentElement.scrollTop || document.body.scrollTop;
            currentPosition-=speed; 
            window.scrollTo(0,currentPosition);//页面向上滚动
            currentPosition+=speed;
            window.scrollTo(0,currentPosition);//页面向下滚动
            console.log(currentPosition)
            _this.currentPosition = currentPosition;
            clearInterval(timer);
        },100);
    }
  }, true)        
  
  
}else if(ua.indexOf('Android') > -1 || ua.indexOf('Adr') > -1) {
  //$alert('android端');
}

六、用addEventListener添加focus事件和blur事件

必须要加true,即

document.getElementById("IdName").addEventListener("focus", myFunctiona,true);

因为input没有::before和::after的微元素

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 问题探究 1. ios中,输入框获得焦点时,页面输入框被遮盖,定位的元素位置错乱: 原因:当页input存在于吸顶...
    郁南阅读 5,610评论 0 2
  • 随着手机的普及,移动端的开发也成了一个重要的方向,但由于设备的不统一会造成一些兼容性问题, 1、安卓浏览器看背景图...
    聂嘚吧嘚阅读 5,899评论 3 14
  • 1、安卓浏览器看背景图片,有些设备会模糊。 用同等比例的图片在PC机上很清楚,但是手机上很模糊,原因是什么呢? 经...
    LIT乐言阅读 3,892评论 0 1
  • 20、圆角bug某些Android手机圆角失效background-clip: padding-box; 21、顶...
    紫夏离殇阅读 5,439评论 0 1
  • 今天阳光很好,早起给娃儿下载了老师布置的作业:《燕子》阅读六遍,拍照或者视频签到。哄着让她把原文从手机上抄下来了,...
    silence2016330阅读 851评论 0 0