网络编程
位置:首页>> 网络编程>> JavaScript>> 关于textarea的直观换行的一些研究材料

关于textarea的直观换行的一些研究材料

  发布时间:2024-11-11 02:12:56 

标签:textarea,换行

前两天研究了一下textarea的直观行的换行规律,挺复杂啊:

直观行怎样取不光要看cols大小,还要看网页编码方式。
cols="30"的textarea,实际上每行可以容纳29个半角字符,多少个全角字符就不一定了,与网页编码方式有关。
在IE6.0实测的情况,直观行的换行发生在红字处(红字折到下一行)。

dddddddddddd米ddddddddddddddddddddd //全角后面的连续半角内容被当成一个完整单词处理,如果剩下的位置容不下单词的长度了,就要换行,此为特殊规律A

网页按Unicode编码(“运行代码”的弹出页面即按此编码,JS生成的页面均按此编码)时的一般规律是

(“占满”是说后面无论再跟全角、半角字符,都得换行)

123456789012345678901234567890 //29半角占满
一二三四五六七八九十一二三四五六七八九十 //17全角占满
一二三四五六七八九十一二三四五六七0八九十
一二三四五六七八九十一二三四五六0七八九十 
0一二三四五六七八九十一二三四五六1七八九十 //16全角,1半角占满
0一二三四五六七八九十一二三四五六七八九十
0一二三四五六七八九十一二三四五1六七八九十 //15全角,2半角后不可容全角
01一二三四五六七八九十一二三四五六七八九十
01一二三四五六七八九十一二三四五2六七八九十 //15全角,2半角后可再容1半角(多于1半角时按特殊规律A)
012一二三四五六七八九十一二三四五六七八九十 //15全角,3半角占满
012一二三四五六七八九十一二三四五3六七八九十
0123一二三四五六七八九十一二三四五六七八九十 //14全角,4半角后不可容全角
0123一二三四五六七八九十一二三四4五六七八九十 //14全角,4半角后可再容1半角(多于1半角时按特殊规律A)
01234一二三四五六七八九十一二三四五六七八九十 //14全角,5半角占满
01234一二三四五六七八九十一二三四5五六七八九十
012345一二三四五六七八九十一二三四五六七八九十 //13全角,6半角后不可容全角
012345一二三四五六七八九十一二三6四五六七八九十 //13全角,6半角后可容1半角(多于1半角时按特殊规律A)
0123456一二三四五六七八九十一二三四五六七八九十 //13全角,7半角占满
0123456一二三四五六七八九十一二三7四五六七八九十
01234567一二三四五六七八九十一二三四五六七八九十 //12全角,8半角占满
01234567一二三四五六七八九十一二8三四五六七八九十
012345678一二三四五六七八九十一二三四五六七八九十 //11全角,9半角后不可容全角
012345678一二三四五六七八九十一9二三四五六七八九十 //11全角,9半角后可再容1半角(多于1半角时按特殊规律A)
0123456789一二三四五六七八九十一二三四五六七八九十 //11全角,10半角占满

……

0一二三四五六七八九十一二三四五12六七八九十 //15全角,1半角后可再容2半角连续字符(多于2半角时按特殊规律A),此条可由15全角,3半角占满得出

……

0一二三四五六七八九十一二三四1234五六七八九十 //14全角,1半角后可再容4半角连续字符(多于4半角时按特殊规律A),此条可由14全角,5半角占满得出

……

01一二三四五六七八九十一二三四234五六七八九十 //14全角,2半角后可再容3半角连续字符(多于3半角时按特殊规律A),此条可由14全角,5半角占满得出

……
换行位置不仅与换行位置之前的整行文字有关,还与红字有关(往往全角文字是因为无法在上行末尾挤下才被折到下一行的)。

总结一下就有:

CODE:[Copy to clipboard]x全角,y半角占满 = x全角,y-1半角后不可容全角 = x全角,y-n半角后可再容n半角连续字符(多于n半角时按特殊规律A)。
所以做实验搞清楚所有“占满”的情形就可以了。

现将cols=30,网页按Unicode编码时的“占满”情况列出:

17全角
16全角,1半角
15全角,3半角
14全角,5半角
13全角,7半角
12全角,8半角
11全角,10半角
10全角,12半角
9全角,13半角
8全角,15半角
7全角,17半角
6全角,19半角
5全角,21半角
4全角,22半角
3全角,24半角
2全角,26半角
1全角,28半角
29半角

利用濒于发生按特殊规律A换行的情形,很容易测出所有“占满”的情形:
例如,一二三四五六七八九十012345678912一二三四五六七八九十 //10全角,12半角占满
一二三四五六七八九十0123456789123一二三四五六七八九十 //红字处按特殊规律A换行,蓝字处按9全角,13半角占满换行

cols=30,网页按GB2312编码时,“占满”规律不同了:

14全角,1半角
13全角,3半角
12全角,5半角
11全角,7半角
10全角,9半角
9全角,11半角
8全角,13半角
7全角,15半角
6全角,17半角
5全角,19半角
4全角,21半角
3全角,23半角
2全角,25半角
1全角,27半角
29半角

这样的话,要根据网页的编码方式和cols,通过实验具体才能测出“占满”规律。

从textarea内容的开头起计算全角和半角字符的数目,根据“占满”规律及特殊规律A决定第一个直观换行的位置,再从第二行(包括物理行和直观行)起计算全角和半角字符的数目,根据“占满”规律及特殊规律A决定第二个直观换行的位置……如是继续下去,直到textarea内容的末尾。这样就可以得到所有的换行位置了。

当然实际应用时没必要也没可能这样做实验啦,比如说选中textarea的第X行到第Y行,还没了解官方的办法是怎样的,我是这么办的:

<textarea rows=5 cols=30 id=abc> 祖父听说我要带女朋友去钓鱼,也想去会会她。我带了女朋友先去,等候祖父的时候,我已经钓到了一条18公斤重的鲈鱼。 祖父到了,我把女友介绍给他认识,又举起那条鱼给他看。 真不错!他说,怎样钓上的? 用蚯蚓。我回答。 那就奇了,他故意一本正经地说, 我那一代至少要用一顿饭和一场电影!<&#47textarea> <script language=JScript> /* Create by Bound0 on Blueidea mailto:bound0eureka@gmail.com */ function sele(s,e){ var src = document.getElementById("abc") var oTR = src.createTextRange() var text=src.innerText var textLength = text.length conts=[0] /* 我一开始不知道getClientRects()方法,就用这段代码取textarea内容开始处在网页中的大致坐标,可见条条大路通罗马 Obj=src for (var sumTop=0,sumLeft=0;Obj!=window.document.body;sumTop+=Obj.offsetTop,sumLeft+=Obj.offsetLeft, Obj=Obj.offsetParent); startx=sumLeft+6 //textarea内容开始处在网页中的大致坐标 starty=sumTop+9 */ startx=src.createTextRange().getClientRects()[0].left starty=src.createTextRange().getClientRects()[0].top stepy=3 //光标向下移动的步长,不能大于textarea中的字高 currentScr=0 //当前滚动条位置 stepScr=30 //滚动条向下滚动的步长,不能大于textarea的高度 while(1){src.scrollTop=currentScr currenty=starty while(1) //光标从textarea内容的开头开始向下移动,遍历各行,在conts[]中记下各换行位置 {oTR.moveToPoint(startx, currenty) oTR.moveEnd("character", textLength) cont = textLength - oTR.text.length if(cont>=textLength)break if(cont>conts[conts.length-1])conts[conts.length]=cont currenty+=stepy } if(currentScr>=src.scrollHeight)break currentScr+=stepScr } if(e=="")e=s s=parseInt(s) e=parseInt(e) if(isFinite(s)&amp;&amp;isFinite(e)&amp;&amp;s>0&amp;&amp;e>0){if(s>conts.length||e>conts.length){alert("总共只有"+conts.length+"行。") //检查参数有效性 return} if(e<s){e=s;end.value=e} //如果结束行在开始行之前,强行调整参数 src.scrollTop=0 oTR.moveToPoint(startx,starty) //光标回到textarea内容的开头 st=conts[s-1] texpreStart=text.substr(0,st).replace(/\r/g,"") //自textarea内容的开头至选择起点前的字串,由于moveStart方法将\r\n视为一个字符,需要修正计数 st=texpreStart.length oTR.moveStart("character",st) en=textLength if(e<conts.length)en=conts[e] texpreEnd=text.substr(0,en).replace(/\r/g,"") //自textarea内容的开头至选择结束点前的字串,由于moveEnd方法将\r\n视为一个字符,需要修正计数 en=texpreEnd.length oTR.moveEnd("character", en-st) oTR.select() } } </script> 选中第<input name=start value=3>行至第<input name=end value=5>行 <button onclick=sele(start.value,end.value)>select</button>



04 年初写的东西,应该是目前研究比较全面的了吧??

<style> * {     font-size: 12px; } </style> <script language="javascript"> // Coded by windy_sk <windy_sk@126.com> 20040210 function reportError(msg,url,line) {     var str = "You have found an error as below: \n\n";     str += "Err: " + msg + " on line: " + line;     alert(str);     return true; } window.onerror = reportError; function show_all(obj, txt_obj) {     var x, y;     txt_obj.value = "";     for(x in obj) {         if(typeof(obj[x])=="object") {             txt_obj.value += x + " : \n";             for(y in obj[x])                 txt_obj.value += "    " + y + " -    " + obj[x][y] + "\n";         } else {             txt_obj.value += x + " -    " + obj[x] + "\n";         }     }     return; } var cur_pos = 0; var p_row = 0; var p_col = 0; var v_row = 0; var v_col = 0; var s_len = 0; var r_count = 0; function get_txt_pos() {     try{         var obj = document.getElementById("test");         var rng = obj.createTextRange();         var rng_sel = obj.document.selection.createRange();         var if_end = false;         var arr_sel = new Array();                  show_all(rng, ctr);         show_all(rng_sel, cr)         show_all(rng.getClientRects(), ctr_crt);         show_all(rng_sel.getClientRects(), cr_crt)         show_all(rng.getBoundingClientRect(), ctr_bcrt);         show_all(rng_sel.getBoundingClientRect(), cr_bcrt)                  s_len = rng_sel.text.replace(/\r/, "").length;         rng.moveToPoint(rng_sel.offsetLeft, rng_sel.offsetTop);         rng.moveStart('character', -obj.value.length);         try {             r_count = rng.text.match(/\r/g).length;         } catch(e) {             r_count = 0;         }         cur_pos = rng.text.length;                  if_end = (rng.getBoundingClientRect().left == rng_sel.getBoundingClientRect().left);         arr_sel = rng.text.split("\r\n");         p_row = arr_sel.length;         p_col = if_end?0:arr_sel[arr_sel.length-1].length;                  var rct = rng.getClientRects();         v_row = rct.length;         rng.moveToPoint(rct[v_row-1].left, rct[v_row-1].top);         rng.moveStart('character', -cur_pos);         v_col = if_end?0:(cur_pos - rng.text.length);         if(v_col - p_col == 2) v_col = p_col;                  err.value = "";     }catch(e){         show_all(e, err)         cur_pos = 0;         p_row = 0;         p_col = 0;         v_row = 0;         v_col = 0;         s_len = 0;         r_count = 0;     }     show_txt_pos();     return; } function restore_txt() {     var obj = document.getElementById("test");     obj.focus();     var rng = obj.createTextRange();      rng.moveStart('character', cur_pos - r_count);     rng.collapse(true);     rng.moveEnd('character', s_len);     rng.select();     show_txt_pos();     return; } function show_txt_pos() {     cur_pos_show.innerText = cur_pos - r_count;     p_row_show.innerText = p_row;     p_col_show.innerText = p_col;     v_row_show.innerText = v_row;     v_col_show.innerText = v_col;     return;     } </script> <table><tr><td> <textarea id="test" style="width:400px; height:200px" onclick="get_txt_pos()" onkeyup="get_txt_pos()"> 1 - 1234567890 2 - 12345678901234567890 3 - 123456789012345678901234567890 4 - 1234567890123456789012345678901234567890 5 - 12345678901234567890123456789012345678901234567890 6 - 123456789012345678901234567890123456789012345678901234567890 7 - 1234567890123456789012345678901234567890123456789012345678901234567890 8 - 12345678901234567890123456789012345678901234567890123456789012345678901234567890 9 - 123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 0 - 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 <&#47textarea> </td><td width="50">&amp;nbsp;</td><td valign="top"> <b>Current Position : </b> <b>Physical Row: </b> <b>Physical Column: </b> <b>Visible Row: </b> <b>Visible Column: </b> <b>Error Message: </b> <textarea id="err" style="width:350px; height:120px"><&#47textarea> </td></tr></table> <input type="button" name="textfield" onclick="restore_txt()" value="Restore Selection">   <table> <tr> <td><b>CreateRange</b> <textarea id="cr" style="width:400px; height:200px"><&#47textarea> </td><td><b>CreateTextRange</b> <textarea id="ctr" style="width:400px; height:200px"><&#47textarea> </td> </tr> <tr> <td><b>CreateRange.getClientRects()</b> <textarea id="cr_crt" style="width:400px; height:200px"><&#47textarea> </td><td><b>CreateTextRange.getClientRects()</b> <textarea id="ctr_crt" style="width:400px; height:200px"><&#47textarea> </td> </tr> <tr> <td><b>CreateRange.getBoundingClientRect()</b> <textarea id="cr_bcrt" style="width:400px; height:200px"><&#47textarea> </td><td><b>CreateTextRange.getBoundingClientRect()</b> <textarea id="ctr_bcrt" style="width:400px; height:200px"><&#47textarea> </td> </tr> </table>



根据被某网站匿名转载的页面( http://dl.pconline.com.cn/html_2/4/545/id=38457&pn=0.html )上的网友留言,上面的《JS实现文本域的任意行选定》示例代码有一处bug:即在滚动条不在顶端的情况下运行示例代码会出错。现已修正:只增加了一行代码

CODE:
src.scrollTop=0 //确保开始数行数时滚动条位于顶部

<textarea rows=5 cols=30 id=abc> Bound0 子确工作室 生物信息学相关业务简介 [多步生物信息查询的一步化] 将繁琐的多步生物信息查询合并为一步,减少在各个网页间的手工跳转。 只要能够理清多步生物信息查询的流程就可能做到一步化。 [批量数据转录、整合] 将大量零散的文档收录到数据库中或整理、转化为符合要求的格式。 例如:将数百个结构复杂的word文档内容收录到数据库中。 [定制Bound0 Eureka预选器数据库] 利用Bound0 Eureka预选器数据库可以初步判断样品的成分,缩小进一步实验的处理范围,对接下来的实验环节做出调整,或预选出最佳的实验方案,从而缩短研究、开发的周期,节省人力物力。还可以初步验证某些假设推断,并有助于提出新的假设推断,构建新的假说。同时让交流和教学过程变得更简单、方便。 有关Bound0 Eureka预选器数据库核心技术的专利申请已被受理,专利申请号:200610077985.3。 定制Bound0 Eureka预选器数据库(Bound0 Eureka Preselector)的业务实质: 1、定制公共数据库内容的本地化整合。 2、定制数据库查询方式和查询项目。 3、定制分析、统计功能。 4、定制数据共享功能。 5、定制教学展示功能。 6、定制其他辅助功能。 例如:Bound0酵母蛋白Eureka预选器数据库的数据内容整合了SGD数据库(Saccharomyces Genome Database,酵母基因组库http://www.yeastgenome.org/)中的部分数据。共包含6713个蛋白的信息。 Bound0酵母蛋白Eureka预选器数据库具有以下基本功能: (1)Eureka Preselector(主功能): 根据条件给出符合条件的蛋白质列表。根据蛋白质的特征与目标特征的接近程度对列表内的蛋白质进行排名。以网页形式输出、保存 Eureka 结果。对保存的结果进行对比分析。 (2)以树状结构显示(treeview)蛋白质的各种生物学信息。 (3)以搜索引擎形式,对描述蛋白质充当的细胞组分、参与的生物过程、分子功能等描述性特征的标准化术语(GO Term)提供注释和指导。 (4)以搜索引擎形式,对蛋白质的各种ID、名称进行通译。 (5)在安装了Bound0酵母蛋白Eureka预选器数据库的计算机上,实现自定义的eureka:// 协议。可以在用户自己的网页中以超级链接(文字链接、图片热点链接等)的方式动态地调用数据库中的内容进行演示。 (6)自动生成上述演示所需要的链接代码。 (7)独立发行(便于数据共享)的数据分析配件,可对以网页形式保存的 Eureka 结果进行处理。 更多详情请置询bound0@tom.com<&#47textarea> <script language=JScript> /* Create by Bound0 on Blueidea mailto:bound0@tom.com */ function sele(s,e){ var src = document.getElementById("abc") var oTR = src.createTextRange() var text=src.innerText var textLength = text.length conts=[0] /* 我一开始不知道getClientRects()方法,就用这段代码取textarea内容开始处在网页中的大致坐标,可见条条大路通罗马 Obj=src for (var sumTop=0,sumLeft=0;Obj!=window.document.body;sumTop+=Obj.offsetTop,sumLeft+=Obj.offsetLeft, Obj=Obj.offsetParent); startx=sumLeft+6 //textarea内容开始处在网页中的大致坐标 starty=sumTop+9 */ src.scrollTop=0 //确保开始数行数时滚动条位于顶部 startx=src.createTextRange().getClientRects()[0].left starty=src.createTextRange().getClientRects()[0].top stepy=3 //光标向下移动的步长,不能大于textarea中的字高 currentScr=0 //当前滚动条位置 stepScr=30 //滚动条向下滚动的步长,不能大于textarea的高度 while(1){src.scrollTop=currentScr currenty=starty while(1) //光标从textarea内容的开头开始向下移动,遍历各行,在conts[]中记下各换行位置 {oTR.moveToPoint(startx, currenty) oTR.moveEnd("character", textLength) cont = textLength - oTR.text.length if(cont>=textLength)break if(cont>conts[conts.length-1])conts[conts.length]=cont currenty+=stepy } if(currentScr>=src.scrollHeight)break currentScr+=stepScr } if(e=="")e=s s=parseInt(s) e=parseInt(e) if(isFinite(s)&amp;&amp;isFinite(e)&amp;&amp;s>0&amp;&amp;e>0){if(s>conts.length||e>conts.length){alert("总共只有"+conts.length+"行。") //检查参数有效性 return} if(e<s){e=s;end.value=e} //如果结束行在开始行之前,强行调整参数 src.scrollTop=0 oTR.moveToPoint(startx,starty) //光标回到textarea内容的开头 st=conts[s-1] texpreStart=text.substr(0,st).replace(/\r/g,"") //自textarea内容的开头至选择起点前的字串,由于moveStart方法将\r\n视为一个字符,需要修正计数 st=texpreStart.length oTR.moveStart("character",st) en=textLength if(e<conts.length)en=conts[e] texpreEnd=text.substr(0,en).replace(/\r/g,"") //自textarea内容的开头至选择结束点前的字串,由于moveEnd方法将\r\n视为一个字符,需要修正计数 en=texpreEnd.length oTR.moveEnd("character", en-st) oTR.select() } } </script> 选中第<input name=start value=3>行至第<input name=end value=5>行 <button onclick=sele(start.value,end.value)>select</button>


0
投稿

猜你喜欢

手机版 网络编程 asp之家 www.aspxhome.com