美文网首页
input 输入控制-原生和vue的指令方式

input 输入控制-原生和vue的指令方式

作者: wwmin_ | 来源:发表于2018-08-11 23:41 被阅读56次

    我们经常会要求用户在文本框中输入特定的数据,或者输入特定格式的数据.例如,必须包含木屑字符,或者必须匹配某种模式.由于文本框在默认情况下没有提供多少验证数据的手段,因此必须是哟个JavaScript来完成此类过滤输入的操作.而综合运用事件和DOM手段,就可以将普通的文本框转换成能够理解用户输入数据的工程型控件.
    1.原生事件方法:

    • input事件操作el.value值
      此处按照事件的顺序均可实现
    <!--onkeydown-->
     <input onkeydown="this.value=this.value.replace(/\D/g,'')">
    <!--onkeypress-->
     <input onkeypress="this.value=this.value.replace(/\D/g,'')">
    <!--推荐-->
    <!--onkeyup-->
     <input onkeyup="this.value=this.value.replace(/\D/g,'')">
    

    onkeydown,onkeypress都有一个比较明显的缺点,就是非数组字符仍可以输入,只是在下一次输入之后才会替换掉.
    keyup事件能在输入不正确的字符之后立刻就能清除掉, 但是这个动作还是人眼可见的.

    封装 : 此种方式也可先定义一个函数,将this传递到该函数然后进行复杂操作

    <input onkeyup="keyUp(this)">
    <script>
    function keyUp(el) {
      el.value = el.value.replace(/\D/g, '');
    }
    </script>
    
    • 最佳方案 event.preventDefault
      为了让不希望输入的字符不会在input框中闪现,可以通过阻止某个按键的默认行为来屏蔽此类字符.在极端的情况下,可以通过下列代码屏蔽所有按键操作.
    EventUtil.addHandler(textBox,"keypress",function(event){
        event=EventUtil.getEvent(event);
        EventUtil.preventDefault(event);
    })
    

    放上用到的EventUtil公共方法

    let EventUtil = {
      addHandler: function (element, type, handler) {
        if (element.addEventListener) {
          element.addEventListener(type, handler, false);
        } else if (element.attachEvent) {
          element.attachEvent("on" + type, hander);
        } else {
          element["on" + type] = handler;
        }
      },
      removeHandler: function (element, type, handler) {
        if (element.removeEventListener) {
          element.removeEventListener(type, handler, false);
        } else if (element.detachEvent) {
          element.detachEvent("on" + type, handler);
        } else {
          element["on" + type] = null;
        }
      },
      getEvent: function (event) {
        return event ? event : window.event;
      },
      getTarget: function (event) {
        return event.target || event.srcElement;
      },
      preventDefault: function (event) {
        if (event.preventDefault) {
          event.preventDefault();
        } else {
          event.returnValue = false;
        }
      },
      stopPropagation: function (event) {
        if (event.stopPropagation) {
          event.stopPropagation();
        } else {
          event.cancelBubble = true;
        }
      },
      getCharCode: function (event) {
        if (typeof event.charCode === "number") {
          return event.charCode;
        } else {
          return event.keyCode;
        }
      }, 
      getClipboardText: function (event) {
        var clipboardData = (event.clipboardData || window.clipboardData);
        return clipboardData.getData("text");
      },
      setClipboardText: function (event, value) {
        if (event.clipboardData) {
          return event.clipboardData.setData("text/plain", value);
        } else if (window.clipboardData) {
          return window.clipboardData.setData("text", value);
        }
      }
    }
    

    运行以上代码后,由于所有按键操作都被屏蔽,结果会导致文本框变成只读的.如果只想屏蔽特定的字符,则需要检测keypress事件对应的字符编码,然后再决定如何响应.例如,下列代码只允许用户输入数值.

    <input type="text" id="textBox">
    <script>
    EventUtil.addHandler(textBox, "keypress", function (event) {
      event = EventUtil.getEvent(event);
      var target = EventUtil.getTarget(event);
      var charCode = EventUtil.getCharCode(event);
      if (!/\d/.test(String.fromCharCode(charCode)) && charCode>9 && !event.ctrlKey) {
        EventUtil.preventDefault(event);
      }
    })
    </script>
    

    例子中,使用EventUtil.getCharCode()实现了跨浏览器取得字符编码,然后使用String.fromCharCode()将字符编码转换成字符串,再使用正则表达式/\d/来测试该字符串,将测试失败的数值使用EventUtil.preventDefault()屏蔽按键事件.

    1. vue指令方式
      通过vue指令可以在input 标签上添加相应指令名称就可以达到操作原生input事件,满足各种input功能需求, 逻辑即清晰亦是解耦,可移植性强.
    • 限制input输入数字最大最小值
      下面是我封装后的完整示例:
      HTML部分
    <div id="app">
          <h2>input 控制输入</h2>
          <div>
            <input type="number" v-model.lazy="value" v-int-num="{cb:showAlert,min:10,max:100,decimal:0}" >
          </div>
    </div>
    

    JavaScript部分

    // 截取精确小数方法
    const round = (n, decimals = 0) => Number(`${Math.round(`${n}e${decimals}`)}e-${decimals}`);
    Vue.directive('int-num', {
      bind: function (el, binding, vnode) {
        let {
          cb,//回调函数,可在不满足条件的情况下做一下后续提示等操作
          min,//最小值
          max,//最大值
          decimal //精确小数位数
        } = binding.value ? binding.value : {
          cb: Function,
          min: 0,
          max: 100,
          decimal: 0
        };
    
        if (min > max) {
          throw new Error("最小值不能大于最大值");
          return;
        }
    
        el.keypressHandler = function (event) {
          // 当小数位数位0时,此时不允许输入'.'点符号
          if (decimal === 0 && event.charCode === 46) {
            event.preventDefault();//组织默认行为
            event.stopPropagation();//停止传递冒泡事件,不会进入input事件中
          }
        }
        el.inputHandler = function (event) {
          if (isNaN(Number(el.value))) {
            el.value = "";
          } else {
            el.value = round(Number(el.value), decimal);
          }
          cb.call(null, Number(el.value));
          if (el.value > max) {
            el.value = max;
          }
        }
        el.blurHandler = function () {
          if (el.value > max) {
            cb.call(this, "最大值是 " + max)
          }
          if (el.value < min) {
            cb.call(this, "最小值是 " + min);
          }
        }
        // 添加事件监听
        el.addEventListener("keypress", el.keypressHandler)
        el.addEventListener('input', el.inputHandler);
        el.addEventListener("blur", el.blurHandler);
      },
      unbind: function (el) {
        // 移除事件监听
        el.removeEventListener("keypress", el.keypressHandler)
        el.removeEventListener('input', el.inputHandler);
        el.removeEventListener("blur", el.blurHandler);
      }
    });
    new Vue({
      el: "#app",
      data: {
        value: ""
      },
      methods: {
        showAlert(e) {
          console.info(JSON.stringify(e));
        }
      }
    })
    

    特别注意:
    v-model值绑定的时候需要使用.lazy进行修饰,因为v-model内部也是用input事件截取值和绑定值的,哪个先执行是不确定的,偶尔会看到input值闪动出现。当用.lazy修饰之后,v-model内部使用change事件绑定值,而change事件是在input事件之后,故此时已经是经过自定义处理之后的值,不会出现数值跳动的情况。

    其实内部实现也是input事件的原生方法,经过vue指令的封装,控制输入行为会更灵活,也更直观和方便.
    如果需要对特定字符进行组织或只允许输入特定字符,可以在keypress事件中用 event.charCode判断即可实现.

    题外话:
    为了只允许输入数字可以用input[type=number]和input[type=tel],但是有一些缺陷

    • input[type=number]
      不支持maxlength,支持输入e,.
    • input[type=tel]
      在移动设备上,input[type=tel] 是支持maxlength的,而且只能输入数字键盘。支持输入#,*,+

    相关文章

      网友评论

          本文标题:input 输入控制-原生和vue的指令方式

          本文链接:https://www.haomeiwen.com/subject/ynwlbftx.html