Posted on 2005-02-07 13:12
听棠.NET 阅读(11882)
评论(50) 编辑 收藏 网摘 所属分类:
技术积累
最经典的实现字符数控制的方案
当我们在ASP.NET开发时,经常会遇到一个头疼的问题:字符数的控制
由于数据库的字段长度是固定的,因此在进行字符输入时,最关键的就是控制字符的个数不能超过字段的长度,要不然,一个个异常会让人疯掉的。
对于单行文本框,不管是HTML控件还是Web控件,我们经常会使用MaxLength来控制,但这种控制无法控制到中文字符,即MaxLength=50的控制,可以输入50个英文与50个中文,这样的话,还是会导致中文字符数的溢出。
对于多行文本框,那就更惨了,使用MaxLenth根本不起作用的。
下面提供的方案优势:
1)最佳的方法是在文本框中输入时,控制到最大字数,超过时不能进行输入;
2)对于粘帖的情况也要能兼容,以前网上的方法不能控制到paste的情况;
3)对于最后的一个中文字符,宁愿舍去也不能多一个字符,比如50的字符数,在第49个时,最后输入一个中文,会导致最终字数为51,而这种情况,推荐是不能输入中文,保证最终的字符数<=50最佳,因为放弃一个中文字符总比数据库报错要好吧。
4)为了提高开发效率,尽可能的减少代码量,此方案不需要为文本框添加任何事件,而是由脚本块自己解决,因此只需要把脚本块饮包含到页面中就可以了,这应该是相当方便了吧
完善版修改:由于前一个方案中,一些输入法无法激活onpress事件,导致对于中文的不支持,现在采用onkeyup事件处理,在处理方式上也进行了修改,原来的onpress事件是进行输入控制,而onkeyup只能对已经输入后的字数进行字数判断,过长的进行截短处理。
在原方案中,有位朋友指出:数据采用n(type)系统不会报错,是的,如果采用n(type)的话,是以字符为基础的,可以不考虑数据库出错的可能性,但同样也存在一个界面显示的问题,比如界面上的Address值,希望是100个字符,如果不进行中英文字数区分,最多将输入100个中文,从而占200个字节空间,导致Adress在显示时会超过预料的空间,界面搞得不易控制。因此,此方案还是有可取之处的。
具体新方案实现:
1)将以下的代码包含到页面中:
<script language="javascript">
<!--
String.prototype.len=function(){
return this.replace(/[^\x00-\xff]/g,"**").length;
}
//Set maxlength for multiline TextBox
function setMaxLength(object,length)
{
var result = true;
var controlid = document.selection.createRange().parentElement().id;
var controlValue = document.selection.createRange().text;
var tempString=object.value;
var tt="";
for(var i=0;i<length;i++)
{
if(tt.len()<length)
tt=tempString.substr(0,i+1);
else
break;
}
if(tt.len()>length)
tt=tt.substr(0,tt.length-1);
object.value=tt;
}
//Check maxlength for multiline TextBox when paste
function limitPaste(object,length)
{
var tempLength = 0;
if(document.selection)
{
if(document.selection.createRange().parentElement().id == object.id)
{
tempLength = document.selection.createRange().text.len();
}
}
var tempValue = window.clipboardData.getData("Text");
tempLength = object.value.len() + tempValue.len() - tempLength;
if (tempLength > length)
{
tempLength -= length;
var tt="";
for(var i=0;i<tempValue.len()-tempLength;i++)
{
if(tt.len()<(tempValue.len()-tempLength))
tt=tempValue.substr(0,i+1);
else
break;
}
if(tt.len()<=0)
{
window.event.returnValue=false;
}
else
{
tempValue=tt;
window.clipboardData.setData("Text", tempValue);
window.event.returnValue = true;
}
}
}
function PressLength()
{
if(event.srcElement.type=="text" || event.srcElement.type=="textarea" )
{
if(event.srcElement.length!=null)
setMaxLength(event.srcElement,event.srcElement.length);
}
}
function LimitLength()
{
if(event.srcElement.type=="text" || event.srcElement.type=="textarea" )
{
if(event.srcElement.length!=null)
limitPaste(event.srcElement,event.srcElement.length);
}
}
document.documentElement.attachEvent('onkeyup', PressLength);
document.documentElement.attachEvent('onpaste', LimitLength);
//-->
</script>
2)在需要控制的控件上添加length="n"(n为要控制的字数)即可,如:
<INPUT type="text" length="3">
<TEXTAREA length="20" rows="2" cols="20"></TEXTAREA>
<asp:TextBox id="TextBox1" runat="server" length="7"></asp:TextBox>
<asp:TextBox id="TextBox2" runat="server" TextMode="MultiLine" length="10"></asp:TextBox>
上面是HTML控件与Web控件的例子,只要加一个length就可以了。
好了,大家可以体验一下了哦:
http://files.cnblogs.com/tintown/stringLenth3.rar (已经修改复了“没有length无法输入的问题”)
个人建议:1)可以把这个脚本块放在js文件中,进行引用即可
2)可以把脚本放在BasePage中,这样每个页面都可以使用了
3)可以使用这些脚本块,开发专门的服务器端控件,我没有时间开发,如果有朋友可以开发了发布一下哦!
Feedback
试了,可以了。
ps:不是强行去掉最后一个字符而是最后一个汉字 觉得不合适,可以把length加长啊。
我表达得不清楚:如果限制为5,输入第6个字符,会发现字符输入了,但又自动去掉,这样给别人看起来不舒服
3)对于最后的一个中文字符,宁愿舍去也不能多一个字符,比如50的字符数,在第49个时,最后输入一个中文,会导致最终字数为51,而这种情况,推荐是不能输入中文,保证最终的字符数<=50最佳,因为放弃一个中文字符总比数据库报错要好吧。
完全的程序员呆板思维,做出来的东西要的实用,别人最后一个字可能就是最重要的,去掉了,你存下来的资料就完全没有了意义。
所以这种解决方案根本不行哈。完全不从市场解度考虑,失败。
@轻剑傲风
莫名其妙的评论,限制成50个字符就是更具用户需求做出的呀。
@轻剑傲风
老兄,你不要妄自菲薄,我看你才是不懂的人啊!这是为了防止出错,为了界面,难道你宁愿系统报错,让客户输入过多的字符。
@all:
至于最后一个字符的删除,在控制上可能不太美观,但目前我只能这样控制,不知道有没有其他的好方法。最后一个中文的删除,也是为了保持完整性,因为一个字符容不下一个中文,所以宁愿舍去!
不好意思,前面言词不太合适
我对技术方面并不太在行,只能说是了解一些吧
我主要负责是客户需求和系统构架,在公司里。
当然,是客户要求限在50字以内,那当然无可非意,在处理时但也不应直接去掉,给出提示,让用户自行把内容改到50字以内,否则不执行后面的,这样会更人性化。
如果自动就这么去掉了,可能是最关键的去掉了,而客户自己也不知情,,,,
@轻剑傲风:
我也口气太重了,控制字数的业务情况还是蛮多的,在超过时采用弹出窗口也是可以的,有兴趣的朋友只要修改一下就可以了,不过,我倒是不太喜欢弹出来,因为挺烦人的。输不下去,自然也就知道了。
如果采用sqlserver,将该字段设置为nvarchar(50),不知道可不可以
你这个方法需要改进,我发现了一些问题
1.如果TextBox没有设置length这个属性的话,连值都输入不了
2.假如用户希望TextMode="MultiLine" 输入为NTEXT,请问您怎么实现
3.当length超过1000的时候我发现输入就很明显的慢了下来,5000以上几乎就象是死机,对客户端的影响太大了
4.输入文字后CTRL+A不能全选
总体来说这是个好方法,解决了我不少问题,但是这些方面也应该考虑一下,楼主解决了请给我邮箱发个邮件,谢谢!
@头发不能乱 :
首先要感谢你的支持。
1.此问题已经解决,请重新下载即可。
2.NTEXT可以照常输入啊,只要保存时使用nvarchar即可。
3.速度我也测试了一下,是有点慢下来了,不过,还算可以接受,可能是我的机器比较好吧,我是1G内存的。这个问题我也不知道如何解决了。
4.CTRL+A的问题我试了好几次,也不知道如何解决,哪位朋友帮个忙,我用event.keyCode=17还是不行啊。
我想要的效果就是假如我没有设置length属性的话,就不用调用那个JS函数,js对这个控件无效,也就是说我无论输入多少字符,也不会产生那种反应速度的问题了。楼主,急啊!帮帮忙,谢谢
另外楼主你这个页面上面的原代码我看了一遍,好象一点都没有变啊!!你改过了吗?
我现在改过了,你可以直接copy代码或是下载文件即可。
楼主,太谢谢你了,你的回复太及时了,.......支持楼主
帮了我大忙了
小弟学习了!
好像 shift + ← 可以全选定,而CTRL+A 不可以!
快速输入后快速用鼠标在空白处点一下,多出来的字符就不会被截掉了,hiahia,小bug
希望JavaScript高手能进行再次完善啊!其实我对js也不是特熟,象CTRL+A的问题等,我也是搞不定了啊。SOS!!!搞不定我就
!
[a-zA-Z0-9\u4e00-\uf900]
不是可以匹配一个大小写字母、数字或中文么?
用这个应该可以直接统计吧?
我觉得可以从以下几个方面来解决:
1.
在设计数据库的时候已经完全用n(type),
这样直接使length小于数据库中指定的长度就可以了。
毕竟硬件发展了,这点空间还是可以承受的,
而且可以减少很多问题,尤其需要支持多语言的时候更明显。
还有就是nvarchar比varchar的查询速度更快(信不信由你)。
2. 不要在用户输入的时候去检查用户,这样会打扰用户,
尤其很多用户就是一些专门录单子的,输入速度非常快。
建议在form的提交的时候统一检查,
如果有错误的话,将焦点停留在出错的输入框上。
不知大家的意见如何?
@咖啡猫 :
你的观点我基本同意:
1.我也是早已采用n(type)了,没有了Length问题,而且支持多语言
2.在输入时控制不控制呢,也要看情况的,如果在输入以后再提示,未必有些麻烦,在输入时他就能注意到就可以在立即修改,因为前面的输入部分可能会影响后面的输入部分。如果不是速度的影响,我还是推荐在输入时就进行控制,把错误扼杀的输入状态。
3.中英文的字符判断是需要的,因为界面控制也是非常重要的,不能因为n(type)的兼容而忽略了界面控制。
想法不错,但看上去确实很不对劲,客户很难同意
不知道又没有更好的办法
同意使用 n(*) 的解决办法。对于js我觉得尽量少用,因为js很容易出错(个人感觉),有时候还有兼容问题。但是很多友好的界面还是需要js来完成的。我觉得这个矛盾就世为什么flash能够流行的原因。
楼主能想办法过滤掉成对的<><>吗?
比如说<font color=#ff0000>红色</font>
统计字数的时候只算“红色”,其他的过滤掉
比如我输入10个文字以后,想去求改第3,4个字,但是每修改一个光标都会跑到最后!删除中间自己字时,光标也会自动跳到最后!
有点疑惑, copy 你的code, html control 可以, asp server control (textbox) 好像不可以, 解析成html control 没有length property, code 中event.srcElement.length == undefind, 暂时我没有好办法, 另用个hidden来充当event.srcElement, 来弥补undefind, 你们有什么好办法吗?
这个js已经很不错了,但是有一点小bug,当我们在TEXTAREA 内容中间部分用键盘输入数据时;光标会自动指向最后一个字符,很不方便!希望能否改进一下!感谢!!
1.关于光标会自动移动到后面的问题,这是因为楼主的代码是每次,不管你这次输入的是不是超出长度,都会用一个暂存的变量向当前选中的textbox里面赋值,所以每次光标自然是移动到最后面了.
2.关于crl+a的问题,开始着实让人找不到出路.因为虽然if ((event.ctrlKey)&&(event.keyCode==65))判断可以判断出当前按的是ctr+a,可问题是,我们松开的时候并不一定是同时松,所以atr按钮和a按钮的放开事件变会又执行一次,于是按以前楼主的代码,用一个暂存的变量向当前选中的textbox里面赋值,所以不但每次光标自然是移动到最后面了.而且ctr+a的全选状态也被取消了.
解决以上问题,我是换了一种思路,就是当用户输入不超长时,就让其保存原来的值.超长再用暂存的变量去覆盖.改了点代码,于是,上面两个问题就解决了
3.觉得每次把用户输入的超出长度的最后部分截掉太不友好了,因此定义了个全局变量来保存上一次存入的合规则的值.这样,当超出长度时,就可以只取消用户当前的输入而不老是去截最后的值.
改动的代码如下:var globalStr="";
//Set maxlength for multiline TextBox
function setMaxLength(object,length)
{
var result = true;
var controlid = document.selection.createRange().parentElement().id;
var controlValue = document.selection.createRange().text;
var tempString=object.value;
var tt="";
for(var i=0;i<=length;i++)
{
if(tt.len()<=length)
tt=tempString.substr(0,i+1);
else
break;
}
if(tt.len()>length)
{
alert("输入超出"+length+"个字符");
object.value=globalStr;
//tt=tt.substr(0,tt.length-1);
//object.value=tt;
}
else
{
globalStr= tt;
}
}
最后,非常感谢楼主,从你这里学了很多东西.
这有问题啊。。。特别是在用微软拼音输入的时候,当达到maxlength之后然后再用微软输入中文字符会把整个框的内容全部删除的。。
这不是最好的方案,用onpropertychange属性就可以控制,我以前的控制方法如下,可以封装一下,做成共用文件的:
<script language="javascript">
<!--
function MaxLength(field,maxlimit){
var j = field.value.replace(/[^\x00-\xff]/g,"**").length;
//alert(j);
var tempString=field.value;
var tt="";
if(j > maxlimit){
for(var i=0;i<maxlimit;i++){
if(tt.replace(/[^\x00-\xff]/g,"**").length < maxlimit)
tt = tempString.substr(0,i+1);
else
break;
}
if(tt.replace(/[^\x00-\xff]/g,"**").length > maxlimit)
tt=tt.substr(0,tt.length-1);
field.value = tt;
}else{
;
}
}
</script>
单行文本框控制<br />
<INPUT type="text" id="Text1" name="Text1" onpropertychange="MaxLength(this, 5)"><br />
多行文本框控制:<br />
<TEXTAREA rows="14"
cols="39" id="Textarea1" name="Textarea1"
onpropertychange="MaxLength(this, 15)"
style="WIDTH: 336px; HEIGHT: 232px"></TEXTAREA><br />
Email:kefanmail@163.com
欢迎沟通
刚刚回复错了,好象回复到了另一篇文章,呵..不好意思.
帅哥,你知道什么叫“人性化吗”?
1、你觉得这应该让客户自己去取舍还是让你来强制执行?
2、你那个javascript离开ie就死翘翘了。
3、在客户端代码里加个length是很管用吗?在地址栏里输入一句脚本就可以改掉了。
4、对于包含 Unicode 的内容,本来就应该使用 nvarchar 之类的字段类型,数据库已经给你提供了解决方案,你不用
5、在显示的时候考虑占位长度是应该的,但你的做法貌似本末倒置了,仅仅因为这样你就压缩了用户的输入空间?是不是把你的做法放到显示这个环节比较好?
最终该判断的还判断,规范长度的方法n多,你不但用了最不可取的方式,还是一种多余的方式。
两个问题:
1、firefox下不生效
2、用微软拼音输入的时候,当达到maxlength之后然后再用微软输入中文字符会把整个框的内容全部删除的
把中英文混编的字段设置成nvarchar或ntext就可以了。
你们好,我要设个密码,它说必须是字符数,啥叫字符数
--引用--------------------------------------------------
听棠.NET: @轻剑傲风:
我也口气太重了,控制字数的业务情况还是蛮多的,在超过时采用弹出窗口也是可以的,有兴趣的朋友只要修改一下就可以了,不过,我倒是不太喜欢弹出来,因为挺烦人的。输不下去,自然也就知道了。
--------------------------------------------------------
楼主说得对,又要想我们以最快的速度做出项目,又要求代码质量,还要我们把市场解度完美的考虑进去,还要不要我们活了?
--引用--------------------------------------------------
听棠.NET: @轻剑傲风
<br> 老兄,你不要妄自菲薄,我看你才是不懂的人啊!这是为了防止出错,为了界面,难道你宁愿系统报错,让客户输入过多的字符。
<br>@all:
<br> 至于最后一个字符的删除,在控制上可能不太美观,但目前我只能这样控制,不知道有没有其他的好方法。最后一个中文的删除,也是为了保持完整性,因为一个字符容不下一个中文,所以宁愿舍去!
--------------------------------------------------------
妄自菲薄???用错词了吧!
@听棠.NET
解决CTRL+A的问题:只要在
function setMaxLength(object,length)
{
var result = true;
var controlid = document.selection.createRange().parentElement().id;
var controlValue = document.selection.createRange().text;
var tempString=object.value;
var tt="";
for(var i=0;i<length;i++)
{
if(tt.len()<length)
tt=tempString.substr(0,i+1);
else
break;
}
if(tt.len()>length)
tt=tt.substr(0,tt.length-1);
if(object.value != tt)//在这个函数添加这一行就可以了
object.value=tt;
}
感谢博主~
楼上的太牛B了,解决微软拼音输入法回车时清空textbox的漏洞