概述

pc端移动端中文本框监控字数的功能的一种较为简单的实现,考虑到安卓和IOS输入法输入过程中是否触发keyup的差异。利用监听compositionstart判断是否开启了输入法。从而实现体验较为良好兼容性较强的监控字数的控件。

详细

一、需求阐述和常用的解决方案

制作一个文本框限制最大字数,实时监听当前已经输入的字数,并显示出来。期初我实现这个功能的方法很简单:给textarea控件添加onkeyup事件方法,在方法中将textarea值的长度打印出来,并给textarea添加一个maxlength属性设置长度限制即可。代码如下:

  1. <div class="form-group needCount">
  2.  
  3. <textarea id="txt0" maxlength="10"></textarea>
  4.  
  5. <p><span id="txtNum0">0</span>/10</p>
  6.  
  7. </div>
  1. var txt0 = document.getElementById("txt0");
  2.  
  3. var txtNum0 = document.getElementById("txtNum0");
  4.  
  5. txt0.addEventListener("keyup",function(){
  6.  
  7. txtNum0.textContent = txt0.value.length;
  8.  
  9. });

二、存在的问题

这样貌似很简单就实现了,在英文输入法下一切还都ok,但当我们用输入法输入中文时,问题很快就来了,比如我们要输入“文章”一词就要输入“wenzhang”浏览器会监听到8词keyup事件。在一些浏览器(如safari)中,如果这个过程超过maxlength甚至会阻止你继续输入。因此单纯的监听keyup事件显示是不够的。

(图1- 每次按下键盘就会触发监听事件)

三、问题的解决

经过查阅前辈们的解决方案,发现了两个之前没有听说过的属性“compositionstart”和“compositionend”。
MDN上的解释:compositionstart 事件触发于一段文字的输入之前(类似于 keydown 事件,但是该事件仅在若干可见字符的输入之前,而这些可见字符的输入可能需要一连串的键盘操作、语音识别或者点击输入法的备选词)。
compositionend就是对应的就是一段文字输入的事件。
有了这两个事件,我们就可以做一个“开关”,一旦检测到开始使用输入法输入一段文字了,就把这个“开关打开”,检测到一段文字输入完毕了,就观赏这个“开关”。接下来我们在之前的keyup方法中添加一个判定条件,如果开关关闭,正常打印出textaarea值的长度;如果开关打开,停止打印。而输入一段文字时,监听输入完成的事件“compositionend”,将textarea的值的长度打印出来。这样无论是否开启了输入法都能正确的打印出控件值的长度了。
代码如下:(其中变量chnIpt就是代表是否开启了输入法进行输入的关键变量“开关”)

  1. var txt0 = document.getElementById("txt0");
  2. var txtNum0 = document.getElementById("txtNum0");
  3. var chnIpt0 = false;
  4. txt0.addEventListener("keyup",function(){
  5. if(chnIpt0 ==false){
  6. countTxt();
  7. }
  8. });
  9. txt0.addEventListener("compositionstart",function(){
  10. chnIpt0 = true;
  11. })
  12. txt0.addEventListener("compositionend",function(){
  13. chnIpt0 = false;
  14. countTxt();
  15. })
  16. function countTxt(){
  17. if(chnIpt0 == false){
  18. txtNum0.textContent = txt0.value.length;
  19. }
  20. }

如此实现的效果就是英文输入法下没放开键盘就会进行一次字数统计,输入法输入中文时,输入结束时才会统计字数。

四、实现复用

当然一个完整的插件一定是可以复用的。如果页面里需要多个文本框都要限制字数如何实现。我们需要考虑以下几个问题:

1. 关键元素(文本框txt和用于显示字数的txtNum)的变量创建和元素获取如何实现?
2. 同是监听“keyup”和“compositionend”如何区分不同的textarea

要解决问题1,首先想到创建一个数组,数组中的每一个元素通过不同的Id获取一个元素。一个独立的过程中我们需要获取两个元素:txt和txtNun,一个关键变量chnIpt,因此我们要创建三个数组。为了方便理解,假定页面中有需要三组控件:

  1. <div class="form-group needCount">
  2.  
  3. <textarea id="txt0" maxlength="10" onfocus="ff(0)"></textarea>
  4.  
  5. <p><span id="txtNum0">0</span>/10</p>
  6.  
  7. </div>
  8.  
  9. <div class="form-group needCount">
  10.  
  11. <textarea id="txt1" maxlength="10" onfocus="ff(1)"></textarea>
  12.  
  13. <p><span id="txtNum1">0</span>/10</p>
  14.  
  15. </div>
  16.  
  17. <div class="form-group needCount">
  18.  
  19. <textarea id="txt2" maxlength="10" onfocus="ff(2)"></textarea>
  20.  
  21. <p><span id="txtNum2">0</span>/10</p>
  22.  
  23. </div>

则创建数组的过程:

  1. var txt0 = document.getElementById("txt0");
  2. var txt1 = document.getElementById("txt1");
  3. var txt2 = document.getElementById("txt2");
  4. var txtNum0 = document.getElementById("txtNum0");
  5. var txtNum1 = document.getElementById("txtNum1");
  6. var txtNum2 = document.getElementById("txtNum2");
  7. var chnIpt0 = false;
  8. var chnIpt1 = false;
  9. var chnIpt2 = false;
  10. var txt=[txt0,txt1,txt2];
  11. var txtNum=[txtNum0,txtNum1,txtNum2];
  12. var chnIpt=[chnIpt0,chnIpt1,chnIpt2];

这样txt就是textarea控件的数组,txtNum就是现实字数的标签的数组,chnIpt就是判断“开关”的关键变量数组,以待调用。
现在思考第二个问题“同是监听“keyup”和“compositionend”如何区分不同的textarea”。或者说,我们怎么判断当前输入的textarea是txt元素中的第几个呢。
这里就需要表单控件都具有的focus事件进行区别,在focus事件的方法中传入代表数组索引的参数,从而选择调用数组中相应那个元素。
代码如下:(ff(i)即为focus事件调用的方法参数为索引值)

  1. function ff(i){
  2.  
  3. txt[i].addEventListener("keyup",function(){
  4.  
  5. if(chnIpt[i] ==false){
  6.  
  7. txtNum[i].textContent = txt[i].value.length;
  8.  
  9. }
  10.  
  11. });
  12.  
  13. txt[i].addEventListener("compositionstart",function(){
  14.  
  15. chnIpt[i] = true;
  16.  
  17. });
  18.  
  19. txt[i].addEventListener("compositionend",function(){
  20.  
  21. chnIpt[i] = false;
  22.  
  23. txtNum[i].textContent = txt[i].value.length;
  24.  
  25. });
  26.  
  27. }

我们再来考虑最后一个问题。目前是已知页面中需要几组文本框的情况,我们可以手动创建,费时费力代码也不美观。
进一步优化一下创建数组的过程:给每一个独立的组件一个class,获取具有这个class的元素的长度,循环这个class的长度,给数组中添加元素即可。如此处理,引用一段脚本不必再做更改,只需要在html中添加相应的组件即可。JS代码如下:

  1. var txt = [],txtNum = [],chnIpt = [];
  2. var needCount = document.getElementsByClassName("needCount");
  3. for(var i=0;i<needCount.length;i++){
  4. txt[i] = document.getElementById("txt"+i);
  5. txtNum[i] = document.getElementById("txtNum"+i);
  6. chnIpt[i] = false;
  7. }

最终完整的JS代码:

  1. var txt = [],txtNum = [],chnIpt = [];
  2. var needCount = document.getElementsByClassName("needCount");
  3. for(var i=0;i<needCount.length;i++){
  4. txt[i] = document.getElementById("txt"+i);
  5. txtNum[i] = document.getElementById("txtNum"+i);
  6. chnIpt[i] = false;
  7. }
  8. function ff(i){
  9. txt[i].addEventListener("keyup",function(){
  10. if(chnIpt[i] ==false){
  11. txtNum[i].textContent = txt[i].value.length;
  12. }
  13. });
  14. txt[i].addEventListener("compositionstart",function(){
  15. chnIpt[i] = true;
  16. });
  17. txt[i].addEventListener("compositionend",function(){
  18. chnIpt[i] = false;
  19. txtNum[i].textContent = txt[i].value.length;
  20. });
  21. }

(图2 - 一组字符输入完全之前不会监听自述变化)

五、文件以及演示地址

1、文件

2、演示地址

demo效果

六、兼容性

如此实现知识该组件我尝试以来最为接近预期的实现方法,在pc端主流浏览器(ie9以上),安卓、ios的原生键盘输入、“讯飞语音”的语音输入法效果良好。但在一些特定情况下仍然会出现问题,譬如:

1. 无法监听ios自带输入法的语音识别输入
2. 猎豹浏览器下使用鼠标点选词组会结算“keyup”而不是“compositionend”,并且会使maxlength失效。再次 监听到“keyup”恢复正常。

以上两个问题至今没有找到解决,以及,我发现在火狐浏览器下会执行两次“compositionend”,但并不影响字数统计。诸如这些疑问还烦请网上的各位高人如遇到类似问题给予在下指正与指点。

最后我想说一句话:“如果事件不再有浏览器之间的差异,世界将变成美好的人间!”

注:本文著作权归作者,由demo大师发表,拒绝转载,转载需要作者授权

兼顾pc和移动端的textarea字数监控的实现方法的更多相关文章

  1. js常见的判断移动端或者pc端或者安卓和苹果浏览器的方法总结

    1.js常见的判断移动端或者pc端或者安卓和苹果浏览器的方法总结 : http://www.haorooms.com/post/js_pc_iosandmobile 2.Js判断客户端是否为PC还是手 ...

  2. 用react开发一个新闻列表网站(PC和移动端)

    最近在学习react,试着做了一个新闻类的网站,结合ant design框架, 并且可以同时在PC和移动端运行: 主要包含登录和注册组件.头部和脚部组件.新闻块类组件.详情页组件.评论和收藏组件等: ...

  3. JS判断PC和移动端设备

    1.方法一 function IsPC() { var userAgentInfo = navigator.userAgent; var Agents = ["Android", ...

  4. 前端分辨pc和移动端导入不同css

    通过navigator获取浏览器,根据浏览器的不同判断出pc和移动端然后设置不同的css 分辨不同屏幕导入不同的css文件: function loadCSS() { if((navigator.us ...

  5. 判断PC机大小端

    判断PC机大小端 #include<stdio.h> #include<stdlib.h> int main() { short a = 0x0102; char *p = ( ...

  6. js判断是pc还是移动端

    //判断pc还是移动端 var isM = function () { var ua = navigator.userAgent; /* navigator.userAgent 浏览器发送的用户代理标 ...

  7. 一个 VUE 组件:实现子元素 scroll 父元素容器不跟随滚动(兼容PC、移动端)

    介绍 我们经常遇到一种情况.当滑动滚动条区域时,子元素滚动条到底部或顶部时就会触发父级滚动条,父级滚动条同理会继续向上触发,直至body容器.这是浏览器默认的滚动行为. 但是很多情况,我们想要子元素滚 ...

  8. 把图片画到画布上,适应PC和移动端

    画一张图片到画布上 <canvas id="myCanvas" width="1000px" height="200px" >您 ...

  9. 如何使用蓝湖设计稿同时适配PC及移动端

    如何使用蓝湖设计稿同时适配PC及移动端 项目需求: 一套代码同时适配PC及移动端 方案: pc端采用px布局,移动端采用rem布局,通过媒体查询(media query)切换 坑: 尝试过使用post ...

随机推荐

  1. js 日期相差的天数

    function DateDiff(sDate1, sDate2){ //sDate1和sDate2是2006-12-18格式 var aDate, oDate1, oDate2, iDays aDa ...

  2. .NET:CLR via C#:CLR Hosting And AppDomains

    AppDomain Unloading To unload an AppDomain, you call AppDomain’s Unload static method.This call caus ...

  3. 开篇-QT完全手册

    嵌入式工具Qt的安装与使用 摘要 Qt是Trolltech公司的一个产品.Trolltech是挪威的一家软件公司,主要开 发两种产品:一种是跨平台应用程序界面框架:另外一种就是提供给做嵌入式Linux ...

  4. Coursera课程《大家的Python》中一些资料

    Printed copies of Python for Informatics are available for $10 or less from Amazon and $2 or less on ...

  5. cgroup子系统2_devices子系统

    devices子系统用于控制cgroup中全部进程能够訪问哪些设备,三个控制文件:devices.allow,devices.deny,devices.list. devices.allow用于指定c ...

  6. 数学图形之克莱因瓶(klein bottle)

    克莱因瓶是一种内外两面在同一个曲面上的图形. 在数学领域中,克莱因瓶(德语:Kleinsche Flasche)是指一种无定向性的平面,比如二维平面,就没有“内部”和“外部”之分.克莱因瓶最初的概念提 ...

  7. 微博与Redis系统技术文章记录

    Redis 持久化,有两种: rdb 和 aof, rdb是记录一段时间内的操作,一盘的配置是一段时间内操作超过多少次就持久化. aof可以实现每次操作都持久化. 这里我们使用aof. 配置方式,打开 ...

  8. JavaScript之深浅拷贝

    数组的浅拷贝 如果是数组,我们可以利用数组的一些方法比如:slice.concat 返回一个新数组的特性来实现拷贝.比如: , true, null, undefined]; var new_arr ...

  9. 解决百度ueditor支持iframe框架页面的视频播放问题

    新下载的ueditor 增加了xss 安全过虑,把iframe过滤了,导致发表的文章包含的视频播放功能被限制了. 说明:新版本ueditor要修改 xss过滤白名单 修改配置文件ueditor.con ...

  10. JSON在php中的使用

    从5.2版本开始,PHP原生提供json_encode()和json_decode()函数,前者用于编码,后者用于解码. json_encode()                           ...