最近时值国庆且中秋,玩的很欢乐所以写了之后并没有立即分享出来
说一说思路:
这个定位的小功能还不是很完善.只是有人说这块难控制.我提供一个思路出来仅供参考,这是练手用的。所以最好不要直接使用。
原因是首先应该通过keypress控制而且监听的范围太小,而且focus等事件处理。
而且这个存在误差 我只做了个英文的 中文我要通过code判断 还需要额外的写(上班期间写这个不合适啊,写的时间越短风险越小)
其中某一步骤有一定问题我会标注出来。
接下来说说代码
首先需要判断出光标的位置,写一个range方法,通过传参控制让他返回几个数,一个是光标的位置,一个是选中的起始。
接下来获得光标位置到开始的字符串,判断里面半角与全角字符的个数。半角占1 全角占2,通过这个控制div的left,并且判断这里面有没有换行符(判断个数是方便后续的del换行符时对行高的操作),如果有要将top增加一个行高,如果文字自动换行则对这个字符求余去处理这个字符在每一个中的位置。
代码中最后是通过当前键入的@来控制的,没有用keyCode处理是因为keyup低级事件的原因.如果是keypress的话处理方式有所不同。
/* * date:2012-9-27 * blog:http://www.cnblogs.com/businessdiv/ */ //num指的是行高,hNum指的是最大高度 function order(num, hNum) { var tPar = document.getElementById('txt'); var tChild = tPar.getElementsByTagName('textarea')[0]; var txtDiv = tPar.getElementsByTagName('div')[0]; var dWidth = parseInt(txtDiv.style.width, 10); var cols = tChild.cols; var oWidth = tChild.clientWidth; var tWidth = oWidth / cols; var oLeft = 0; var oVal = ""; var ocurr = 0; tChild.onkeyup = function(e) { var e = e || event; var t = e.srcElement || e.target; var kCode = e.keyCode || e.charCode; //获得value var val = t.value; //保存当前长度 var len = val.length; //传入的行高 //计算光标位置 取得当前插入位置 var oTop = num; var oLen = range(t); lNum = 0, oNum = 0, item = 0; //获得光标位置内容 //取得光标处插入的字符 var lastCode = val.charAt(oLen - 1); oVal = val.substring(0, oLen); //判断匹配中英文个数 判断半角全角 //这步有偷懒.存在跟中文字符有关系的错误 var req = oVal.match(/^[\x00-\xff]*$/); var l = req.toString().length; //拿到光标位置中文字符的个数 var ol = oLen - l; //控制oLeft //获得通过enter键入的\n的数量,作为定位的控制开关之一 for(var i = len; i--;){ //判断\n if(val.charAt(i) == "\n"){ //控制max if(oTop < hNum){ oTop += num; } //执行一次 if(item++ == 0){ oNum = i; } } } //**这步中oNum其实不够准确 偷懒的原因没有处理其中半角全角.所以计算出来的有一定误差 lNum = (l + ol/2 - oNum)%40*tWidth; //控制oTop maxnum; //通过取得倍数判断是 otop+=num for(var i = Math.floor((l + ol*2)/40); i--;){ if(oTop < hNum){ oTop += num; } } //控制光标left if((lNum + dWidth) > oWidth){ oLeft = oWidth - dWidth + tWidth; }else{ oLeft = lNum + tWidth; } if (lastCode == "@") { txtDiv.style.display = "block"; txtDiv.style.left = oLeft + "px"; txtDiv.style.top = oTop + "px"; } } } function range(obj, curr) { if (typeof(obj.selectionStart) == "number") { start = obj.selectionStart; end = obj.selectionEnd; //判断是否支持doucment.selection } else if (document.selection) { var range = document.selection.createRange(); if (range.parentElement().id == obj.id) { var range_all = document.body.createTextRange(); range_all.moveToElementText(obj); //range_all.compareEndPoints()比较两个端点 //控制start相同。 for (start = 0; range_all.compareEndPoints("StartToStart", range) < 0; start++){ range_all.moveStart('character', 1); } //判断value中'\n'存在 && start就++ for (var i = 0; i <= start; i++) { if (obj.value.charAt(i) == '\n') { start++ }; } var range_all = document.body.createTextRange(); range_all.moveToElementText(obj); //同上理 for (end = 0; range_all.compareEndPoints('StartToEnd', range) < 0; end++){ range_all.moveStart('character', 1); } for (var i = 0; i <= end; i++) { if (obj.value.charAt(i) == '\n') { end++ }; } } } if(curr){ return [start, end] }else{ return end } } order(20, 100)
接下来是html的代码.正常情况下弹出框是ajax过来的数据 这里就不写的那么完整了,并且每一个keyup都会将@和光标位置之间的字符ajax一下然后返回给弹出框。这里还涉及到本地存储的一些问题:
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>模板1</title> <style type="text/css"> #txt{width:500px;margin:10px auto;position:relative;} #txt textarea{height:100px;display:block;line-height:20px;overflow-y:scroll;} .txtBox{position:absolute;width:50px;height:50px;background:#ccc;left:0;top:0;display:none;} </style> </head> <body> <div id="txt"> <textarea name="" id="" cols="40" rows="10"></textarea> <div class="txtBox" style="width:50px;"> 1 </div> </div> <script type="text/javascript" src="order.js"></script> </body> </html>