`
hongtoushizi
  • 浏览: 379294 次
  • 性别: Icon_minigender_1
  • 来自: 天津
社区版块
存档分类
最新评论

Javascript键盘事件及输入控制

阅读更多

 

Javascript键盘事件及输入控制

进行web开发时,我们会对表单做提交验证,为了进一步增强用户体验,要在用户输入时就进行限制,比如针对电话只能输入数字、长度不允许超过固定值等。随着微博的流行,从Twitter开始,很多记录的文字输入在设计时就都添加上了字数限制与提示的功能,这已成了输入框的标配。本文从这一需求出发,说明Javascript中键盘事件和输入控制的技术细节。

功能需求

限制输入功能一般满足下面的需求:

  • 统计还可以输入多少文字并实时显示
  • 限制的字数可能是以汉字为单位计数,这时要判断单字节、双字节的输入
  • 可能还要求达到限制数量后,输入框不可输入,或仅允许输入固定类型(如果用keyup事件,输入框内容会跳动)

这里讨论实现这些需求的方案,基于我们日常使用的标准键盘和最常见的四种内核的浏览器,对于一个web应用,这些兼容就足够了。

下面讨论中仅以事件名称代替,不加前缀‘on’

解决方案

为了实时监控文字的多少,需要对每个输入进行监控,每次改变都应该被纳入到监控中。Javascript中的键盘事件只是监控每次按键,但是对于右键粘贴、拖拽方式改变输入框的内容就无能为力了,我们只能去探寻其他事件。

对字数和类型的限制,原理上都是检查输入的是否符合要求,不符合就把不允许的部分删除,重新给输入框赋值。但是只要用过键盘事件就会发现,keydown、keypress 事件无法获取刚输入的内容,而 keyup 又貌似控制晚了:总是看到字符被输入又再被删除。

什么事件能够满足这种需求呢?那就是 input 和 propertychange 事件。如果你知道这两个事件,一切都不是问题,只要监控它们,既能得到新输入的内容,又能随时控制内容,而不担心文字显示又删除的过程展示在用户面前。

$('textarea').bind('input', function () {
    var value = $(this).val();
    // todo: 处理截断 or 对比是否超出限制
});

但我还是想看看用键盘事件能够做到哪一步。

/* 因为中文不同浏览器返回不同,这里只考虑键盘上字符的输入 */
var input = $('textarea'),
    limitLength = 20, // 限制字符长度
    markForCountWhenKeyup = false; // 标记需要keyup后才能计数(限制输入时控制删除键)

// 绑定事件
input.bind('keydown', keydown)
    .bind('keyup', keyup);
    
// keydown事件
function keydown (evt) {
    // 键盘上的全部可打印键
    var isPrintableKey = function (k) {
            return !(evt.altKey || evt.ctrlKey || evt.metaKey) && (
                   k === 32 ||              // 空格
                   (k >= 48 && k <= 57) ||  // 数字
                   (k >= 65 && k <= 90) ||  // 字母
                   (k >= 96 && k <= 105) || // 小键盘数字
                   // 其他符号键
                   (k === 106 || (k >= 186 && k <= 192) || (k >= 219 || k <= 222))
                   ); 
        };

    switch (evt.keyCode) {
    // 1. 回车键,除了shift+Enter执行默认换行,其他Enter都是提交
    case 13: 
        if (!evt.shiftKey) {
            // todo: 提交处理
            evt.preventDefault(); // 防止换行
        }
        break;
    // 2. 删除键/中文,在keyup后再计算字数
    case 8:   // backspace
    case 46:  // delete
        markForCountWhenKeyup = true;
        break;
    // 3. 输入键,在原内容基础上加1 (这时文本框的值还未改变)
    default:
        if (isPrintableKey(evt.keyCode)) {
            // 超出范围,不再允许将该次键值输入
            if (input.val().length + 1 - limitLength > 0) {
                evt.preventDefault();
            }
        }
    }
}
// 配合keydown,只有退格、删除键才响应,检测字数。(这时文本框的值已经改变)
function keyup (evt) {
    var k = evt.keyCode;
    if (markForCountWhenKeyup && (k === 8 || k === 46 )) {
        // 允许删除
        markForCountWhenKeyup = false;
    }
}

上面的代码满足键盘输入控制,但是仅能处理键盘上看得到的字符的输入,一旦遇到中文、粘贴、拖拽改变输入框内容时,就无能为力了。

技术探究

输入元素

HTML中一般用到的输入文字的元素是文本框,包括input、textarea。富文本编辑不在讨论之列。

js中的键盘事件

js中的键盘事件只有三种:keydown、keyup、keypress。它们触发的顺序是:keydown -> keypress -> keyup。当按下一个键不放开,一般会重复地触发 keydown+keypress,直到放开后触发一个 keyup 事件。

三种键盘事件区别

keydown 和 keyup 是比较底层的事件,分别对应一个键的按下与放开,键盘上任何一个键被点按,都会触发这两个事件。keypress 更接近用户,只有可打印的字符和控制字符(如换行)被键入才触发。

keydown 和 keyup 被触发后,都会产生一个虚拟键盘码,用来表示按下的是哪个键。键盘上的每个键只对应一个虚拟键盘码。keypress 被触发后产生的是实际键入的字符的 Ascll 编码,而没有对应的虚拟键盘码。这两种编码有时在数值上是相等的。

如何访问到事件产生的编码信息,就又要涉及到浏览器兼容问题,几大浏览器处理是不同的。

获取按键信息

在 IE 中,事件对象在 window.event 中,编码信息放到了 keyCode 属性内。keyCode属性的含义根据事件变化,在 keydown 和 keyup 事件中表示的是虚拟键盘码,在 keypress 时表示的就是实际字符的编码。

非IE浏览器内,事件对象在回调函数中返回,存储在事件对象的keyCodewhichcharCode 中,看到了吧,相比 IE 中增加了两个属性。

keyCode 只表示虚拟字符编码,因为 keypress 事件没有该编码,在这个事件里,keyCode的值是 0。charCode 只在 keypress 事件中有值,为实际键入的字符编码,其他事件中都是 0。

which 更像是 IE 中的 keyCode,当 keydown 和 keyup 事件中有虚拟键盘码时,which表示虚拟键盘码;当 keypress 事件中只有字符编码时,which 又表示字符编码。

上面是 firefox 浏览器的标准表现形式。webkit 内核浏览器中(safari、chrome),相比 firefox,在 keypress 时,keyCode 不再是 0,而是和 whichcharCode 两个属性的值相等。opera 浏览器相比 webkit 内核的浏览器,三个 key 事件都去掉了 charCode 属性。

当按下小写字母a键时,对应关系如下:

            keyCode   which     charCode
--ie6/7/8:------------------------------ 
keydown       65    undefined  undefined
keypress      97    undefined  undefined
keyup         65    undefined  undefined
--ie9/10:------------------------------
keydown       65       65         0
keypress      97       97         97
keyup         65       65         0
--firefox:------------------------------
keydown       65       65         0
keypress      0        97         97
keyup         65       65         0
--webkit:-------------------------------
keydown       65       65         0
keypress      97       97         97
keyup         65       65         0
--opera:--------------------------------
keydown       65       65         0
keypress      97       97         97
keyup         65       65         0

除了老版的 IE、firefox,其他浏览器的表现是一致的 
jQuery 为 IE 事件增加了 which 属性值

因此,如果只是 keydown 和 keyup 事件,都访问事件对象的 keyCode 即可;如果是 keypress 事件,就要区别对待了,IE 中还是使用 keyCode,非 IE 要使用 which ,这时他们表示的是实际输入的字符码,通过 String.fromCharCode() 获得实际的可打印字符。

组合按键

除了单个按键,还有组合按键,如很多快捷键是由功能键和其他键组合而来。这些按键除了 opera,都比较一致:

  • ctrlKey --- Ctrl 键
  • shiftKey--- Shift 键
  • altKey ---- Alt 键
  • metaKey --- command 键(Mac下)

中文支持情况

各个浏览器对中文的支持不同,中文输入法下,不同浏览器下按键触发的键盘码是不同的。但它们都不产生 keypress 事件。

  • webkit 内核浏览器:每按一个键都产生 keydown、keyup;keydown 时,可打印字符的键盘码都是 229;keyup 时返回正常的键盘码值。
  • firefox 浏览器:输入中文的中间过程中不产生任何键盘事件;开始输入的第一个按键产生正常的 keydown,结束的 空格或回车 产生 keyup,键盘码是正常的键盘码。
  • opera 浏览器:Window 系统下与 webkit 表现一致;Mac下每次按键都只产生 keydown 事件,键盘码是正常键盘码。
  • ie 浏览器:6~10几个版本触发方式与键盘码值与 webkit 内核浏览器一致。

总之,多数浏览器中文输入法(搜狗输入法)一般开始都是299,但是有些会因系统有差异。用键盘事件控制中文输入不太靠谱。

输入框内容改变事件

form 表单中很多元素都有 change 事件,当表单元素的值发生变化时,就会触发该事件。只能是由用户触发的改变才会发出 change 事件,用脚本修改值是不会产生的,form的很多事件都是如此,包含本文提到的。但是在输入框中,需要焦点离开,改变的状态才会触发这一事件,也就是输入时每次的改变我们是无法知道的,只有在输入框外点击一下,如果内容变化了,才会发出 change 事件。

幸运的是,还有一个 input 事件,会在每次输入框的内容改变时触发,无论是敲键盘输入,还是粘贴文本,甚至是拖拽,只要内容值变化了,就会触发该事件。这个事件是 HTML5 的标准事件,除了老版 IE 基本都支持,它一般藏的比较深,很少会看到关于它的介绍。在 Chrome console 中的自动提示中可以看到一个长长的事件列表,说不准哪些将来我们就会用到了。

Chrome console中提示的textarea支持的事件 
Chrome console 中提示的 textarea 支持的事件

针对不支持的老版 IE6/7/8,还有一个替代事件:propertychange。看它的名字就知道它监视的是属性值的改变,而输入值 value 只是一个元素众多属性中的一个,因此这个事件返回对象需要过滤出我们需要的属性 value

有一点要特别注意的是,IE9/10 同时支持 input 和 propertychange,如果两种事件都注册了,就都会触发,可能会被重复处理。

事件触发顺序

当我们把键盘事件和内容改变事件放到一起,他们触发的顺序是: keydown -> keypress -> input/propertychange -> keyup。

这个顺序特别的地方仍然发生在 IE 中。IE9/10 对两个内容改变事件都支持,但它们的触发顺序却又不同。IE9 是先触发 input,然后才是 propertychange,而 IE10 这个过程正好相反。

当我们敲击可打印的键,它表示的字符是什么时候输入到文本框中的呢?

根据测试观察,文本框中的值在 keypress 事件中还没有改变,但在 input 中已经改变了。在 input 中改变输入框的值,看上去没有任何不妥;如果放到 keyup 事件中再去改变,能看到文字敲进去了然后又被改变了,跳动很明显。在 input 的时候,文本框的值已经改变,但是尚未渲染显示出来,这时用脚本改变文本框中的值,不会出现内容跳动情况。如果在 input 的事件处理函数中设置断点,就能看到内容已经改变,所以我们在这里面获取到的值是改变后的值,只是没有呈现出来。没有看源码与文档,仅从现象推理,希望看到相关资料的能不吝分享。

IE9 的特例

IE9,而且是当前系统中 IE 最高版本为 9 时,敲击退格和删除键,都只能触发 keydown -> keyup 事件。因为这两个键是不可打印的,因此正常情况应该只是不触发 keypress 事件。这个 bug 导致我们的处理程序还要加上对 IE9 这个问题的特别处理。

这个 bug 只存在当前系统最高 IE 版本是 9 的情况下,如果在 IE10 的开发者工具模拟,则不会出现该问题。

结语

要实时监控输入框内容变化,用 input(propertychange) 会简单有效。但不要忘记对 IE9 的特别处理。

keydown、keyup 这两个键盘事件可以直接用 event.keyCode 取得键盘码值,keypress 要得到实际的字符码,需要 event.keyCode || event.which,然后可以用String.fromCharCode() 获取实际的字符表示。最后,各个类型的浏览器及其不同版本可能会有些差别 :( 。

中文的输入,测试中发现不同系统、不同版本都会有影响,无法用键盘事件来控制。

补充

2012-12-20:

对于限制文本框中输入特定的字符,如某些字段只允许数字,还有一种方式,即用 keypress 的 charCode 获取键入的值,判断是否是要求输入的,而不再去获取输入框的值(keypress时,输入框内尚未赋值)。

// 限制 input 输入框中只能输入数字
input.bind('keypress', function (evt) {
    // 取得键入的实际字符。
    // 这里用 keyCode 替换 charCode,同样可以获得想要的值(参见前文)
    var char = String.fromCharCode(evt.keyCode);

    // 如果不是数字,就不允许输入
    if (!/\d/.test(char)) {
        evt.preventDefault();
    }
});

如果是键入,这个简单的处理函数可以很好地工作,但是一旦用输入法、粘贴、拖拽等,就不再能工作了。

还是要回归到 input 事件。

测试代码:http://jsfiddle.net/calefy/uBYWH/

-EO
分享到:
评论

相关推荐

    javascript键盘事件全面控制脚本代码.docx

    - **键盘事件冒泡与捕获阶段**:理解事件传播机制有助于更好地控制事件处理流程。 - **键盘布局与语言**:不同国家/地区的键盘布局可能有所不同,这会影响按键的实际效果。 - **触摸屏设备上的键盘事件**:随着移动...

    javascript键盘响应事件

    一、原生JavaScript键盘事件 1. `keydown`事件:当用户按下键盘上的一个键时触发。 2. `keyup`事件:当用户释放键盘上的一个键时触发。 3. `keypress`事件:对于可打印字符,此事件在`keydown`之后、`keyup`之前...

    javascript网页键盘交互式代码

    以上内容只是JavaScript键盘交互的基础。实际上,你可以通过更多的技术,如防抖(debounce)或节流(throttle)来优化性能,或者利用CSS和HTML5 API来增强用户体验。总之,JavaScript提供了强大的能力,使网页能够响应...

    asp.net控制键盘keycode事件

    在ASP.NET中,开发Web应用程序时,我们可能会遇到需要监听用户键盘输入的情况,例如实现特定按键触发特定功能。本文将详细讲解如何在ASP.NET中处理键盘事件,特别是使用`keycode`来识别用户按下的键。 一、键盘事件...

    用javascript实现软键盘

    通常,这种软键盘会以HTML元素的形式动态生成,并通过JavaScript事件监听来响应用户的点击,模拟真实键盘输入的效果。 描述中提到的"页面代码,及所引用keyboard.js,keyboard.css,keyboard.png",揭示了实现这个...

    javaScript鼠标键盘事件

    ### JavaScript鼠标键盘事件详解 在Web开发中,JavaScript是实现用户交互的重要手段之一。通过监听用户的鼠标和键盘操作,开发者可以构建出响应式且交互丰富的网页应用。本文将重点介绍几种常用的鼠标和键盘事件...

    jquery 监听 键盘 事件

    在JavaScript的世界里,jQuery库为开发者提供了方便快捷的方式来操作DOM、处理事件、执行动画和Ajax交互。其中,监听键盘事件是常见的用户交互处理之一。本文将深入探讨如何使用jQuery来监听键盘事件,以及相关的...

    JavaScript程序设计——事件处理实验报告.docx

    实验报告详细介绍了JavaScript事件处理的相关知识,这在Web开发中是非常关键的一部分,因为事件是用户与网页交互的主要方式。以下是对各个知识点的详细说明: 1. **JavaScript事件基本概念**: - **事件**:是用户...

    javascript表单事件汇总

    它们是处理键盘输入的基础,可以用来捕捉用户的输入行为,如实现快捷键、游戏控制或文本输入限制。 ### 九、onload 页面加载完毕后触发`onload`事件。这是一个重要的生命周期事件,常用于初始化页面状态、加载额外...

    javascript模拟键盘

    在本例中,JavaScript被用来创建和控制虚拟键盘的各个元素,包括按键布局、响应用户点击事件、处理输入法功能(如汉语全拼)等。 虚拟键盘的实现通常涉及以下几个关键知识点: 1. HTML结构:虚拟键盘的可视化部分...

    javascript键盘事件全面控制脚本代码

    这些事件可以帮助开发者实现各种功能,比如监听特定按键、处理输入或创建自定义键盘输入控制。在这个全面控制的脚本中,我们将深入理解键盘事件的类型、如何获取按键信息以及如何在网页上展示这些信息。 首先,我们...

    JavaScript做的软键盘代码

    在没有Java Applet或Flash等插件支持的情况下,JavaScript软键盘代码是一种实用的解决方案,用于提供安全的输入环境,尤其在移动设备上,比如在线支付或敏感信息输入时。 软键盘通常由一系列按钮组成,模拟物理键盘...

    浅谈js键盘事件全面控制

    总结来说,对于js键盘事件的全面控制,需要我们考虑事件类型的多样性、浏览器之间的兼容性问题,并且要能够灵活地利用现有的JavaScript对象和属性来实现复杂的输入逻辑。通过上述的分析和讨论,我们能够掌握实现键盘...

    JS键盘控制JS键盘控制JS键盘控制

    总的来说,JavaScript键盘控制是通过监听键盘事件并响应用户输入来实现的。通过理解并利用这些事件和相关属性,开发者可以创建丰富的交互体验,如游戏控制、快捷键系统或者自定义输入处理。在实际项目中,务必注意...

    javascript 屏幕软键盘

    总的来说,JavaScript屏幕软键盘涉及前端开发中的多种技术,包括DOM操作、事件处理、CSS样式设计、逻辑控制以及跨平台和性能优化。掌握这些知识,将使你能够在触摸屏设备上提供优秀的用户输入体验。

    Javascript键盘虚拟键值编码表

    在JavaScript编程中,了解键盘虚拟键值编码表是非常重要的,特别是在处理键盘事件或者实现自定义键盘输入时。这个编码表提供了每个键盘按键对应的ASCII或Unicode值,这些值可以在JavaScript的键盘事件对象(如`event...

    键盘控制事件2.rar

    在这个"键盘控制事件2.rar"的压缩包文件中,我们可以推测包含了一些关于如何处理键盘输入事件的示例代码或教程。 键盘控制事件通常是指当用户按下或释放键盘上的键时,操作系统或应用程序接收到的信号。这些事件...

    js键盘事件实现人物的行走

    然后,通过JavaScript来监听键盘事件,根据用户的按键输入来控制人物的图像变化,从而实现行走或跳跃的动作。 示例代码如下所示: ```html &lt;!DOCTYPE html&gt; &lt;title&gt;JS Keyboard Events for Character Movement...

Global site tag (gtag.js) - Google Analytics