美文网首页
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