textarea的中文输入判断与搜狗输入法的特殊行为
虽然要讲解的知识点是通用的,但是还是要介绍下我的应用场景和测试环境。
0.1 应用场景和测试环境
我的应用是一块使用Html Canvas开发的黑板,在黑板上实现简单的文字编辑功能。
操作系统:win10
设备:为触屏和非触屏设备若干(一体机,surface,笔记本电脑)
主要浏览器: chrome 58
0.2 监控文字输入的方法
使用Canvas实现文字编辑器的细节这里就不讲了,原理大致都相同。一个必要条件是需要一个隐藏的textarea监听文字输入,因为canvas是无法记录文字选中、换行等信息的,也没有办法直接激活输入法和软键盘。textarea 如下:
<textarea id="ghostTextArea" tabindex="0" style="width: 1000px; height: 1px; position: static; top: 0px; z-index: 5; opacity: 0; display: block;"></textarea>
很多情况下,我们需要实时监控文字输入的变化,下面是几种选择。
0.2.1 键盘事件
监听keydown 和 keyup事件是最直接的方法,通过keyCode我们可以获取按键值。
this.hiddenTextArea.onkeyup = (e) => {
console.log("textKeyup",e.keyCode);
}
this.hiddenTextArea.onkeydown = (e) => {
console.log("textKeydown",e.keyCode);
}
0.2.2 oninput事件
input事件在keydown事件触发之后被触发,这是input类型元素使用的标准事件,表示有文字输入。
从上图中我们可以看到,触发的事件为InputEvent,从该事件对象的data属性中可以获取到当前输入的按键值。
正常情况下,每一次按键都会触发oninput事件。
0.2.3 onpropertychange 事件
该事件主要是为了兼容IE9及以下浏览器对oninput事件的处理。
在监听到 onpropertychange 事件后,可以使用 event 的 propertyName 属性来获取发生变化的属性名称。
// Internet Explorer
function OnPropChanged (event) {
if (event.propertyName.toLowerCase () == "value") {
alert ("The new content: " + event.srcElement.value);
}
}
0.3 非直接输入模式
我们把及时响应键盘按键输入单个按键代表的字符到文本框的行为称为直接输入模式,相对的非直接输入模式,通常是输入法拦截了按键消息之后的输入,以中文输入法为例,通常是回车或者空格后完成输入。
在非直接输入模式下,我们期待的结果是当用户完成输入的时候(按了空格或者回车键)触发一次oninput事件。但是很不幸,每次按键都会触发oninput事件,这会导致我们不知道用户正在输入的是不是中文,也不知道什么时候结束的输入,也就没办法及时对输入的中文进行处理。 为了解决这个问题,我们看一下非直接输入情况下几个有用的属性和事件。
0.3.1 selectionStart 和 selectionEnd
这两个属性是textarea对文字选中区域的标识,从0开始,简化分析,我们只考虑正常文字输入,不考虑有选中的情况,首先是直接输入模式。
上图是我在oninput事件中打的日志,可以明显的看到每次oninput触发之后,selectionStart和selectionEnd的值都相同而且表示最后一个文本,视觉上是我们看到的光标所在的位置,如果我们挪动光标,这两个值也会变化。这里我们提取两个关键特征,在及时输入的情况下:
- selectionStart和selectionEnd随光标位置变化而变化
- selectionStart和selectionEnd值相等
下面我们再看非直接输入模式。
从上图中,我们可以看到在非直接输入模式下,在未完成输入之前,selectionStart一直为0,selectonEnd随着输入一直变化。完成输入时,selectionStart与selectonEnd值会相等。
0.3.2 value
从0.3.1的图中我们可以看到拼音输入法输入过程中,value值的变化,在完成输入之前这个值是由输入法控制的,完成之后,value的值会变为输入的文字内容。
0.3.3 compositionstart 与 compositionend 事件
这是一对事件,当非直接输入开始第一个按键的时候,触发compositionstart事件,非直接输入结束的时候触发compositionend事件, 在直接输入情况下,这两个事件都不会触发。我们添加对这两个事件的监听:
this.hiddenTextArea.addEventListener('compositionstart', function () {
console.log("compositionstart");
that.isCompositionsting = false;
})
this.hiddenTextArea.addEventListener('compositionend', function () {
console.log("compositionend");
that.isCompositionsting = false;
})
观察上图的输出内容,各个事件的执行顺序为:
keydown-->compositionstart-->input-->keyup....-->input-->compositionend-->keyup。
0.3.4 keyCode
现在我们观察下在非直接模式下,按键的值。
this.hiddenTextArea.onkeyup = (e) => {
console.log("keydowncode",e.keyCode);
}
this.hiddenTextArea.onkeydown = (e) => {
console.log("keyupcode",e.keyCode);
}
通过上图,我们可以看到不论你按下的是什么键,keycode都被重置为229了。当然这并不是什么标准,不同输入法的行为还是不一样的。不过目前我们能接触到的中文输入法,正常情况下都是229。
0.4 思路整理
通过上面的分析,我们重新整理下及时响应非直接输入的思路。
0.4.1 如何知道正非直接输入的开始和结束
- 响应compositionstart事件和compositionend事件
- 比较selectionStart 和 selectionEnd是否相等。通常需要一个变量来标识开始和结束,考虑有选中的情况,这两个值可能会经历“相等--不等--相等”(或者 “不等--不等(相差为1)--不等(值增加)--相等”)的流程。
*判断按键的code是否为229,当然这也需要额外的变量来记录开始,还需要结合electionStart 和 selectionEnd才能判断出结束。
下面以selectionStart 和 selectionEnd为例,判断中文输入的开始和结束(非完整代码)。
this.hiddenTextArea.oninput = (e) => {
if (textArea.selectionStart == textArea.selectionEnd) {
editor.bdCanvas.textEditor.currentText.text = textArea.value;
if (!isCompositionsting && 没有文字选中情况) {
//直接插入ascii字符
} else {
//插入文字(如果有部分文字被选中并替换)
//先删除被选中的文字
if (isCompositionsting) {//中文(中文输入法按空格之后,或者回车后输入的字符)
isCompositionsting = false;
} else {//英文、数字 (有选中内容被替换)
}
}
} else {//到这儿说明输入的是中文(中文输入法未按空格之前)
isCompositionsting = true;
}
}
上面的代码引入了isCompositionsting变量,结合selectionStart和selectionEnd来做文字处理。其他方法同理,这里就不过多讲解了。下面我们来分析点异常情况。
0.5 搜狗输入法的非常规套路
这是我安装的最新的搜狗输入法,下面要说的非正常情况,只在这一个版本下会出现。
我们在代码中对keydown,keyup,input,compositionstart和compositionend同时做事件监听,然后使用这个版本的搜狗输入法做输入。结果如下:
在未按下回车或者空格键之前,我们看到:
- textarea只响应了keydown和keyup事件
- keyup时keyCode并不是229
- 过程中没有触发input事件
再看结束输入时的情况:
上图红框内的内容为结束输入时的记录,此时触发一次input事件,selectionStart和selectionEnd相等。
这种情况,结束输入触发一次input,我倒是认为很合理的做法,这样很多情况我们不用关心是否是中文输入了,input的时候获取新的value,记录上一次的selectionstart就可以了。
这种特殊行为我没有具体研究是输入法本身的问题,还是和浏览器、操作系统共同作用的结果。如果你编写类似的程序,需要额外注意下。
0.6 小结
本篇文章只是分析记录了一些现象,并没有什么技术含量,欢迎留言讨论。
textarea的中文输入判断与搜狗输入法的特殊行为的更多相关文章
- intellij idea 12、13 win8 下 中文输入覆盖的问题(搜狗输入法或者其他输入法)
最近升级到idea12,发现中文输入存在问题,输入中文的时候会出现空格,并且覆盖后面的字符,这个问题让我很郁闷. 假设idea的安装位置为:D:\Program Files\JetBrains\Int ...
- JS对输入判断变化屏蔽中文输入法输入时连续触发事件的方法
代码如下: //智能搜索提示 IntelligenceSearch: function IntelligenceSearch() { $('#keyWord').on('input', functio ...
- JS 对输入判断变化屏蔽中文输入法连续输入时触发的事件
//智能搜索提示 IntelligenceSearch: function IntelligenceSearch() { $('#keyWord').on('input', function () { ...
- textarea中限制输入字符长度
要在textarea中限制输入字符的长度,比如在twitter中要限制字符为140个,可实现的方法有: 1. <textarea name="A" cols="45 ...
- Ubuntu14.04安装pycharm用于Python开发环境部署,并且支持pycharm使用中文输入
一.目标 实现在Linux下用pycharm调试工具/Python开发 Linux使用vi/vim工具写Python,缺点:调试不方便,无代码提示.跳转等诸多功能. Windows使用idle/pyc ...
- ubuntu字符界面怎么设置中文显示和中文输入
在ubuntu的字符登陆界面,中文显示默认是乱码的,而且也不支持中文输入,解决方法有很多, 1)安装zhcon--解决中文显示乱码的问题. sudo apt-get install zhcon 然后c ...
- webstorm不能中文输入问题
版本:2018.1.4 原因:http://www.javatang.com/archives/2017/08/27/52101751.html 解决方案:https://www.cnblogs.co ...
- 完美解决 Linux 下 Sublime Text 中文输入
首先,我参考了好几篇文章,都是蛮不错的,先列出来: sublime-text-imfix:首先推荐这个方法,最简单,但是在我的系统上有些问题.可用这个的强烈推荐用这个 完美解决 Linux 下 Sub ...
- Emacs下的中文输入
Emacs如此优秀的编辑器,如果输入中文不顺畅,不免遗憾.可惜现实是折腾很久也未必用得称心如意,作为一个重度(也许是中毒) Emacs使用者,根据个人经验写下此文,希望对同道中人有所帮助. 在Wind ...
随机推荐
- JQuery hover鼠标变换
一般而言,我们为非按钮.链接等元素添加hover事件时,虽然能够处理悬停事件,但是鼠标却并没有变化,会造成悬停事件不明显的结果,为此,我们可以添加CSS样式cursor:pointer,使得该元素的悬 ...
- Unity 多屏(分屏)显示,Muti_Display
Unity 多屏(分屏)显示,Muti_Display 最近项目有个需求,主要用于在展厅的展示游戏. 比如,在一个很大的展厅,很大的显示屏挂在墙上,我们不可能通过操作墙上那块显示器上的按钮来控制游戏 ...
- 洛谷【P2393】题解
P2393 [yyy loves Maths II] 原题链接 话说,这题其实方法对了,也蛮水的. 首先方法是一样的,直接扩大忽略精度问题. 其次,我用了c++的函数控制输出小数位数,方法:cout& ...
- ajax返回json数据示例
前端发送请求与接收数据: $.ajax({ type : "post", url : "/queryStudent", ...
- JavaScript知识点整理(一)
JavaScript知识点(一)包括 数据类型.表达式和运算符.语句.对象.数组. 一.数据类型 1) js中6种数据类型:弱类型特性 5种原始类型:number(数字).string(字符串).bo ...
- 关于SqlServer远程跨库修改数据
今天遇到一个需求需要修改远程服务器上的数据,如何直接修改,并且垮库,跨库简单,直接加上数据库名字,远程的话则需要创建链接服务器,具体步骤如下: --创建链接服务器 exec sp_addlinked ...
- Python实现RNN
一般的前馈神经网络中, 输出的结果只与当前输入有关与历史状态无关, 而递归神经网络(Recurrent Neural Network, RNN)神经元的历史输出参与下一次预测. 本文中我们将尝试使用R ...
- 数值类型中JDk的编译期检查和编译期优化
byte b1 = 5;//编译期检查,判断是否在byte范围内 byte b2 = 5+4;//编译期优化,相当于b2=9 byte b3 = 127;//编译通过,在byte范围内 byte b4 ...
- three.js粒子效果(分别基于CPU&GPU实现)
前段时间做了一个基于CPU和GPU对比的粒子效果丢在学习WebGL的群里,技术上没有多作讲解,有同学反馈看不太懂GPU版本,干脆开一篇文章,重点讲解基于GPU开发的版本. 一.概况 废话不多说,先丢上 ...
- Linux 下安装RabbitMQ 3.6.1
1.安装erlang 依赖 yum install -y gcc gcc-c++ unixODBC-devel openssl-devel ncurses-devel 2.安装erlang ### 设 ...