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

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

  • input事件操作el.value值
    此处按照事件的顺序均可实现

【input|input 输入控制-原生和vue的指令方式】onkeydown,onkeypress都有一个比较明显的缺点,就是非数组字符仍可以输入,只是在下一次输入之后才会替换掉.
keyup事件能在输入不正确的字符之后立刻就能清除掉, 但是这个动作还是人眼可见的.
封装 : 此种方式也可先定义一个函数,将this传递到该函数然后进行复杂操作

  • 最佳方案 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 = https://www.it610.com/article/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 = https://www.it610.com/article/(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事件对应的字符编码,然后再决定如何响应.例如,下列代码只允许用户输入数值.

例子中,使用EventUtil.getCharCode()实现了跨浏览器取得字符编码,然后使用String.fromCharCode()将字符编码转换成字符串,再使用正则表达式/\d/来测试该字符串,将测试失败的数值使用EventUtil.preventDefault()屏蔽按键事件.
  1. vue指令方式
    通过vue指令可以在input 标签上添加相应指令名称就可以达到操作原生input事件,满足各种input功能需求, 逻辑即清晰亦是解耦,可移植性强.
  • 限制input输入数字最大最小值
    下面是我封装后的完整示例:
    HTML部分
input 控制输入

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.valuehttps://www.it610.com/article/= ""; } else { el.value = https://www.it610.com/article/round(Number(el.value), decimal); } cb.call(null, Number(el.value)); if (el.value> max) { el.value = https://www.it610.com/article/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的,而且只能输入数字键盘。支持输入#,*,+

    推荐阅读