首页 > 代码库 > 关于javascript实时显示textarea剩余字符数

关于javascript实时显示textarea剩余字符数

今天在百度的项目中碰到一个问题,就是实现javascript实时显示textarea剩余字符数的 功能,咋一看,这个功能也太简单了吧,一般都是只用keydown和keyup事件监听textarea的字符数就可以了,但是QA检测需要支持鼠标右键 的相关事件(包括粘贴,撤销,删除和剪切等),而且要求鼠标直接拖动文字至textarea中也要实时改变字数,由于这些方法没有直接按键盘,所以光 keydown和keyup事件监听是不够的。
此时就需要用onpropertychange事件了,该事件与onchange事件存在本质区别,onpropertychange事件是当控件里的内容一改变马上触发事件(注意:onpropertychange事件仅限于使用在普通的html上,使用过struts的html:textarea 标签的不包含该事件,否则会报错),但是onpropertychange是IE专享的,而且好像不能用attachEvent绑定,而要直接obj.onpropertychange = fun;其他浏览器需要用oninput事件替代。
一个简单的demo:

<!DOCTYPE HTML><html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>无标题文档</title></head><body><textarea name="" id="textarea"></textarea><p id="remain"></p><script type="text/javascript">var textareaObj=document.getElementById("textarea"),    remainObj=document.getElementById("remain"),    num=0;if(/msie/i.test(navigator.userAgent)){    textareaObj.onpropertychange=function(){        num=1000-this.value.length;        remainObj.innerHTML="剩余"+num+"字";    }    }else{    textareaObj.oninput=function(){        num=1000-this.value.length;        remainObj.innerHTML="剩余"+num+"字";    }}</script></body></html>

上面这个demo支持FF,chrome、ie7和safari所有的事件,包括键盘的输入、删除和直接鼠 标拖入,也可以鼠标右键里面的粘贴、删除、撤销和剪切等,opera也支持这些事件,但是不支持鼠标直接拖入,ie8,ie9不支持鼠标的右键事件(除了 粘贴)。ie9支持键盘输入,不支持键盘删除。
onpropertychange事件没法直接鼠标右键里面的删除和撤销等事件,而且也没办法直接监听这些事件,不像鼠标右键的剪切粘贴和直接拖动等能够用onpaste、oncut和ondrop监听,所以这方面还没找到有效的办法,如果有童鞋知道,请告知,万分感激!
demo:

/*计算剩余字符,base.remainWord("#textarea",10,"#wordsNum");*/    remainWord:function(textareaId, totalNum, remainId) {        /*        textareaId:代表textarea的ID;        totalNum:代表可输入的总共的字符数;        remainId:显示剩余字符数的ID;        */        $(textareaId).each(function() {            var self = $(this), remainObj = $(remainId), num = 0;            function fun() {                num = totalNum - self.val().length;                if (num >= 0) {                    remainObj.css("color", "#828181").html("剩余" + num + "个字");                    self.removeClass("error");                } else {                    remainObj.css("color", "#f00");                    self.addClass("error").val(self.val().substring(0, totalNum));                }                if (self.val() == "") {                    self.prev("label").html("请输入想要说的问题,我们会及时给您反馈。");                } else {                    self.prev("label").html("");                }            }            //ie用onpropertychange事件,IE9不支持鼠标右键里面的删除,onpropertychange不支持很多事件,需要单独写            if (/msie/i.test(navigator.userAgent)) {                self[0].onpropertychange = fun;                self.keydown(fun);                self.keyup(fun);                base.bindEvent(self[0], "paste", function() {                    setTimeout(fun, 100);                });                base.bindEvent(self[0], "cut", function() {                    setTimeout(fun, 100);                });            } else {                base.bindEvent(self[0], "input", fun);            }            //opera和IE拖动事件            if (/opera/i.test(navigator.userAgent) || /msie/i.test(navigator.userAgent)) {                //防止用户拖动内容到输入框                base.bindEvent(self[0], "drop", function() {                    setTimeout(fun, 100);                });                base.bindEvent(self[0], "dragend", function() {                    setTimeout(fun, 100);                });            }        });    },

最终解决方式如下:

/*检测字数通用fun*/    checkWord: function(obj, fun, speed) {        //部分ie中的onpropertychange事件并不能检测鼠标右键的删除和撤销等事件,opera的oninput事件不能检测直接拖动内容到textarea事件drop&&dragend,故这利用定时器解决        if (base.browser() == "ie6" || base.browser() == "ie7" || base.browser() == "ie8" || base.browser() == "ie9" || base.browser() == "opera") {            var timer;            $(obj).focus(function() {                timer = setInterval(fun, speed);            });            $(obj).blur(function() {                clearInterval(timer);            });        }        //FF,Chrome,safari等浏览器可以利用oninput事件监听所有的事件,包括keydown,keyup,鼠标右键中的cut,paste和删除,撤销等所有事件,包括直接拖动drop等也支持        else {            base.bindEvent(obj, "input", fun);        }    },    /*计算剩余字符,base.remainWord("#textarea","#wordsNum");*/    remainWord: function(textareaId, remainId) {        /*		textareaId:代表textarea的ID;		remainId:显示剩余字符数的ID;		*/        $(textareaId).each(function() {            var self = $(this),            	remainObj = $(remainId),            	num = 0;            function fun() {                num = base.totalNum - self.val().length;                if (num > 0) {                    remainObj.css("color", "#828181").html("剩余" + num + "个");                    self.removeClass("error");                    if (num == base.totalNum) {                        remainObj.html("最多" + base.totalNum + "字");                    }                } else {                    remainObj.css("color", "#f00").html("剩余0个");                    self.addClass("error");                    //防止ie下输入全部内容后不能ctrl+a全选                    if (num != 0) {                        self.val(self.val().substring(0, base.totalNum));                        //防止输入全部内容后能在前面输入字符,同时删除了后面的字符                        self.unbind("keydown");                        self.keydown(function(event) {                            //排除一些删除按钮和方向按钮等,getTextareaSelectVal是为了当选择textarea一部分内容后,就可以输入内容,否则不能输入,self.val().length >= base.totalNum是为了删除textarea一部分内容后,能够重新输入                            if (! (event.keyCode == 8 || event.keyCode == 9 || event.keyCode == 46 || event.keyCode == 37 || event.keyCode == 38 || event.keyCode == 39 || event.keyCode == 40 || event.ctrlKey && event.keyCode == 65 || getTextareaSelectVal()) && self.val().length >= base.totalNum) {                                return false;                            }                        });                        //防止输入全部内容后用户拖动内容到输入框                        self[0].ondrop = function() {                            if (self.val().length >= base.totalNum) {                                return false;                            }                        };                        //防止输入全部内容后用户鼠标右键粘贴内容到输入框                        self[0].onpaste = function() {                            if (self.val().length >= base.totalNum && !getTextareaSelectVal()) {                                return false;                            }                        };                        //获取所选文本的开始和结束位置                        function getPositions() {                            var x = 0,                            y = 0,                            val = self[0].value;                            x = self[0].selectionStart;                            y = self[0].selectionEnd;                            return {                                "val": val,                                "x": x,                                "y": y                            };                        }                        //获取textarea中选择的文本                        function getTextareaSelectVal() {                            if (window.getSelection) {                                //Firefox,Chrome,Safari,opera etc                                return getPositions().val.substring(getPositions().x, getPositions().y).length > 0;                            } else if (document.selection) {                                //IE,IE下可以直接获取,不必利用开始和结束位置截取                                return document.selection.createRange().text.length > 0;                            }                        }                    }                }                if (self.val() != "") {                    self.prev("label").html("");                }            }            base.checkWord(self[0], fun, 100);        });    },

关于javascript实时显示textarea剩余字符数