兼顾pc和移动端的textarea字数监控的实现方法
概述
详细
代码下载:http://www.demodashi.com/demo/10444.html
一、需求阐述和常用的解决方案
制作一个文本框限制最大字数,实时监听当前已经输入的字数,并显示出来。期初我实现这个功能的方法很简单:给textarea控件添加onkeyup事件方法,在方法中将textarea值的长度打印出来,并给textarea添加一个maxlength属性设置长度限制即可。代码如下:
<div class="form-group needCount"> <textarea id="txt0" maxlength="10"></textarea><p><span id="txtNum0">0</span>/10</p></div>
var txt0 = document.getElementById("txt0");var txtNum0 = document.getElementById("txtNum0");txt0.addEventListener("keyup",function(){txtNum0.textContent = txt0.value.length;});
二、存在的问题
这样貌似很简单就实现了,在英文输入法下一切还都ok,但当我们用输入法输入中文时,问题很快就来了,比如我们要输入“文章”一词就要输入“wenzhang”浏览器会监听到8词keyup事件。在一些浏览器(如safari)中,如果这个过程超过maxlength甚至会阻止你继续输入。因此单纯的监听keyup事件显示是不够的。
(图1- 每次按下键盘就会触发监听事件)
三、问题的解决
经过查阅前辈们的解决方案,发现了两个之前没有听说过的属性“compositionstart”和“compositionend”。
MDN上的解释:compositionstart 事件触发于一段文字的输入之前(类似于 keydown 事件,但是该事件仅在若干可见字符的输入之前,而这些可见字符的输入可能需要一连串的键盘操作、语音识别或者点击输入法的备选词)。
compositionend就是对应的就是一段文字输入的事件。
有了这两个事件,我们就可以做一个“开关”,一旦检测到开始使用输入法输入一段文字了,就把这个“开关打开”,检测到一段文字输入完毕了,就观赏这个“开关”。接下来我们在之前的keyup方法中添加一个判定条件,如果开关关闭,正常打印出textaarea值的长度;如果开关打开,停止打印。而输入一段文字时,监听输入完成的事件“compositionend”,将textarea的值的长度打印出来。这样无论是否开启了输入法都能正确的打印出控件值的长度了。
代码如下:(其中变量chnIpt就是代表是否开启了输入法进行输入的关键变量“开关”)
var txt0 = document.getElementById("txt0");var txtNum0 = document.getElementById("txtNum0");var chnIpt0 = false;txt0.addEventListener("keyup",function(){if(chnIpt0 ==false){countTxt();}});txt0.addEventListener("compositionstart",function(){chnIpt0 = true;})txt0.addEventListener("compositionend",function(){chnIpt0 = false;countTxt();})function countTxt(){if(chnIpt0 == false){txtNum0.textContent = txt0.value.length;}}
如此实现的效果就是英文输入法下没放开键盘就会进行一次字数统计,输入法输入中文时,输入结束时才会统计字数。
四、实现复用
当然一个完整的插件一定是可以复用的。如果页面里需要多个文本框都要限制字数如何实现。我们需要考虑以下几个问题:
1. 关键元素(文本框txt和用于显示字数的txtNum)的变量创建和元素获取如何实现?
2. 同是监听“keyup”和“compositionend”如何区分不同的textarea
要解决问题1,首先想到创建一个数组,数组中的每一个元素通过不同的Id获取一个元素。一个独立的过程中我们需要获取两个元素:txt和txtNun,一个关键变量chnIpt,因此我们要创建三个数组。为了方便理解,假定页面中有需要三组控件:
<div class="form-group needCount"> <textarea id="txt0" maxlength="10" οnfοcus="ff(0)"></textarea><p><span id="txtNum0">0</span>/10</p></div><div class="form-group needCount"> <textarea id="txt1" maxlength="10" οnfοcus="ff(1)"></textarea><p><span id="txtNum1">0</span>/10</p></div><div class="form-group needCount"> <textarea id="txt2" maxlength="10" οnfοcus="ff(2)"></textarea><p><span id="txtNum2">0</span>/10</p></div>
则创建数组的过程:
var txt0 = document.getElementById("txt0");var txt1 = document.getElementById("txt1");var txt2 = document.getElementById("txt2");var txtNum0 = document.getElementById("txtNum0");var txtNum1 = document.getElementById("txtNum1");var txtNum2 = document.getElementById("txtNum2");var chnIpt0 = false;var chnIpt1 = false;var chnIpt2 = false;var txt=[txt0,txt1,txt2];var txtNum=[txtNum0,txtNum1,txtNum2];var chnIpt=[chnIpt0,chnIpt1,chnIpt2];
这样txt就是textarea控件的数组,txtNum就是现实字数的标签的数组,chnIpt就是判断“开关”的关键变量数组,以待调用。
现在思考第二个问题“同是监听“keyup”和“compositionend”如何区分不同的textarea”。或者说,我们怎么判断当前输入的textarea是txt元素中的第几个呢。
这里就需要表单控件都具有的focus事件进行区别,在focus事件的方法中传入代表数组索引的参数,从而选择调用数组中相应那个元素。
代码如下:(ff(i)即为focus事件调用的方法参数为索引值)
function ff(i){txt[i].addEventListener("keyup",function(){if(chnIpt[i] ==false){txtNum[i].textContent = txt[i].value.length;}});txt[i].addEventListener("compositionstart",function(){chnIpt[i] = true;});txt[i].addEventListener("compositionend",function(){chnIpt[i] = false;txtNum[i].textContent = txt[i].value.length;});}
我们再来考虑最后一个问题。目前是已知页面中需要几组文本框的情况,我们可以手动创建,费时费力代码也不美观。
进一步优化一下创建数组的过程:给每一个独立的组件一个class,获取具有这个class的元素的长度,循环这个class的长度,给数组中添加元素即可。如此处理,引用一段脚本不必再做更改,只需要在html中添加相应的组件即可。JS代码如下:
var txt = [],txtNum = [],chnIpt = []; var needCount = document.getElementsByClassName("needCount"); for(var i=0;i<needCount.length;i++){txt[i] = document.getElementById("txt"+i);txtNum[i] = document.getElementById("txtNum"+i);chnIpt[i] = false; }
最终完整的JS代码:
var txt = [],txtNum = [],chnIpt = []; var needCount = document.getElementsByClassName("needCount"); for(var i=0;i<needCount.length;i++){txt[i] = document.getElementById("txt"+i);txtNum[i] = document.getElementById("txtNum"+i);chnIpt[i] = false; } function ff(i){txt[i].addEventListener("keyup",function(){if(chnIpt[i] ==false){txtNum[i].textContent = txt[i].value.length;}});txt[i].addEventListener("compositionstart",function(){chnIpt[i] = true;});txt[i].addEventListener("compositionend",function(){chnIpt[i] = false;txtNum[i].textContent = txt[i].value.length;}); }
(图2 - 一组字符输入完全之前不会监听自述变化)
五、文件以及演示地址
1、文件
2、演示地址
demo效果
六、兼容性
如此实现知识该组件我尝试以来最为接近预期的实现方法,在pc端主流浏览器(ie9以上),安卓、ios的原生键盘输入、“讯飞语音”的语音输入法效果良好。但在一些特定情况下仍然会出现问题,譬如:
1. 无法监听ios自带输入法的语音识别输入
2. 猎豹浏览器下使用鼠标点选词组会结算“keyup”而不是“compositionend”,并且会使maxlength失效。再次 监听到“keyup”恢复正常。
以上两个问题至今没有找到解决,以及,我发现在火狐浏览器下会执行两次“compositionend”,但并不影响字数统计。诸如这些疑问还烦请网上的各位高人如遇到类似问题给予在下指正与指点。
最后我想说一句话:“如果事件不再有浏览器之间的差异,世界将变成美好的人间!”
注:本文著作权归作者,由demo大师(http://www.demodashi.com)宣传,拒绝转载,转载需要作者授权
兼顾pc和移动端的textarea字数监控的实现方法相关推荐
- 学习RPG Maker MZ开发创建并发布PC和移动端游戏
Complete RPG Maker MZ: Create and Publish for PC and Mobile 完整的RPG制造商MZ:为个人电脑和移动设备创建和发布 MP4 |视频:h264 ...
- 前端分辨pc和移动端导入不同css
通过navigator获取浏览器,根据浏览器的不同判断出pc和移动端然后设置不同的css 分辨不同屏幕导入不同的css文件: function loadCSS() { if((navigator.us ...
- PHP判断pc和移动端跳转,JS判断是PC还是移动端浏览器,并根据不同的终端跳转到不同的网址...
JS判断是PC还是移动端浏览器,并根据不同的终端跳转到不同的网址 function browserRedirect() { var sUserAgent = navigator.userAgent.t ...
- java五大浏览器,[Java教程]各主流浏览器(PC、移动端)userAgent属性信息
[Java教程]各主流浏览器(PC.移动端)userAgent属性信息 0 2017-10-17 18:00:58 PC: IE.QQ.chrome.firefox.360.safair 移动端:微信 ...
- 【Vue】pc和移动端网页样式适配
在下面环节会讲解怎么做pc和移动端网页样式适配. 在当下有两种实现样式适配的:JS 适配方案和CSS 媒体查询适配.下面会具体讲解一下代码该怎么写.
- 静态html页面如何兼容pc和移动端
静态html页面如何兼容pc和移动端 在"test.html"文件中的head之间,录入如下代码: <meta name="viewport" conte ...
- 判断是pc还是移动端浏览器
通过JavaScript判断终端类型 //把请求头信息转为小写 //user agent是指用户代理,使服务器能够识别客户使用的操作系统及版本.CPU 类型.浏览器及版本.浏览器渲染引擎.浏览器语言. ...
- 快速开发app,这个快速开发框架,整合PC、移动端开发,让开发更畅快!
之前,有发过不少PC端快速开发的文章,但是现在越来越多的项目需要PC和移动端结合,所以,我给大家介绍一下之前快速开发平台的APP版本,希望大家能够体验一下,发表一下自己的看法.下载的话,在官网:www ...
- vue项目PC兼容移动端
做完的pc项目要求兼容移动端,常规操作的话是新做一个webapp后再来回跳转, 当前pc项目没有太多的交互和复杂的页面,所以决定在一个项目里进行兼容适配 1.新建两个组件,pc端页面组件,m端页面组件 ...
最新文章
- 三、const常量声明方式
- python语言可以应用在哪些方面-Python语言的应用领域主要有哪些?
- [leetcode] 62 Unique Paths (Medium)
- java多线程必杀技_Java技术大牛必备25个必杀技你都知道吗
- 81. 搜索旋转排序数组 II(014)二分查找+思路+详解+二种做法
- java网络编程3 -- NIO一些简单说明
- 问题六十二:怎么求一元十次方程在区间内的所有不相等的实根(2)——修正“区间端点零值”问题
- 公用Laravel 5框架与公用库架构
- 三星 安装程序无法将 配置为此计算机,三星手机怎么安装软件 三星手机无法安装软件解决办法...
- hp 官方没有针对 mac 的显示器驱动
- 客户管理系统代码项目_低代码案例:快速交付包含门店销售终端的SCM供应链管理系统...
- 使用jad反编译Java文件
- 《Java性能调优实战》00丨开篇词丨怎样才能做好性能调优?2022.03.08-20220329学习完
- 汽车电子行业常见缩略词(前视摄像头相关)
- matlab环境下图像分形维数的计算,MATLAB环境下图像分形维数的计算_杨书申
- Threejs 加载3D模型
- 详解Mysql执行计划explain
- MySQL取离当前时间最近的记录
- 集成百度ORC 识别报 Fatal signal 11 (SIGSEGV) (RenderThread) 错误(已解决)
- Dependency ‘org.mybatismybatisx.x.x‘ not found问题解决方法