JavaScript获取文本框光标的像素位置

【简介】本文主要实现获取textarea和input光标的像素位置,即光标的offsetLeft与offsetTop。可实现如下效果:


首先说明一下,在网上搜到的很多代码是如何获取输入光标位置的如下代码是如何获取光标的的字符位置,如对于串“He|llo World!”返回的是光标|前的字符数2,并不是光标在页面上的像素位置。当然,这段代码对于获取光标的像素位置能起到一定的辅助作用。

[javascript]  view plain copy
  1. // 获取光标在文本框的位置  
  2.     function _getFocus(elem) {  
  3.         var index = 0;  
  4.         if (document.selection) {// IE Support  
  5.             elem.focus();  
  6.             var Sel = document.selection.createRange();  
  7.             if (elem.nodeName === 'TEXTAREA') {//textarea  
  8.                 var Sel2 = Sel.duplicate();  
  9.                 Sel2.moveToElementText(elem);  
  10.                 var index = -1;  
  11.                 while (Sel2.inRange(Sel)) {  
  12.                     Sel2.moveStart('character');  
  13.                     index++;  
  14.                 };  
  15.             }  
  16.             else if (elem.nodeName === 'INPUT') {// input  
  17.                 Sel.moveStart('character', -elem.value.length);  
  18.                 index = Sel.text.length;  
  19.             }  
  20.         }  
  21.         else if (elem.selectionStart || elem.selectionStart == '0') { // Firefox support  
  22.             index = elem.selectionStart;  
  23.         }  
  24.         return (index);  
  25.     }  
对于IE浏览器,通过下面的代码1实现起来比较方便。
[javascript]  view plain copy
  1. //代码1  
  2. if (document.selection) {      
  3.     elem.focus();  
  4.     var Sel = document.selection.createRange();  
  5.     return {  
  6.         left: Sel.boundingLeft,  
  7.         top: Sel.boundingTop,  
  8.         bottom: Sel.boundingTop + Sel.boundingHeight  
  9.     };  
  10. }  

而对于firefox之类的浏览器则通过模拟来实现,如下图所示。首先通过拷贝输入区域的样式到一个div层(clone层),然后在此clone层之中的text子层添加光标之前的字符,并在text子层之后添加focus层,focus层中包含字符“|”来模拟光标,进而通过获取focus层的偏移量即可获得文本光标的像素坐标位置。

具体实现代码如下:

[html]  view plain copy
  1. var kingwolfofsky = {  
  2.     /**  
  3.     * 获取输入光标在页面中的坐标  
  4.     * @param        {HTMLElement}   输入框元素          
  5.     * @return       {Object}        返回left和top,bottom  
  6.     */  
  7.     getInputPositon: function (elem) {  
  8.         if (document.selection) {   //IE Support  
  9.             elem.focus();  
  10.             var Sel = document.selection.createRange();  
  11.             return {  
  12.                 left: Sel.boundingLeft,  
  13.                 top: Sel.boundingTop,  
  14.                 bottom: Sel.boundingTop + Sel.boundingHeight  
  15.             };  
  16.         } else {  
  17.             var that = this;  
  18.             var cloneDiv = '{$clone_div}'cloneLeft = '{$cloneLeft}'cloneFocus = '{$cloneFocus}'cloneRight = '{$cloneRight}';  
  19.             var none = '<span style="white-space:pre-wrap;"> </span>';  
  20.             var div = elem[cloneDiv] || document.createElement('div'), focus = elem[cloneFocus] || document.createElement('span');  
  21.             var text = elem[cloneLeft] || document.createElement('span');  
  22.             var offset = that._offset(elem), index = this._getFocus(elem), focusOffset = { left: 0, top: 0 };  
  23.   
  24.             if (!elem[cloneDiv]) {  
  25.                 elem[cloneDiv] = div, elem[cloneFocus] = focus;  
  26.                 elem[cloneLeft] = text;  
  27.                 div.appendChild(text);  
  28.                 div.appendChild(focus);  
  29.                 document.body.appendChild(div);  
  30.                 focus.innerHTML = '|';  
  31.                 focus.style.cssText = 'display:inline-block;width:0px;overflow:hidden;z-index:-100;word-wrap:break-word;word-break:break-all;';  
  32.                 div.className = this._cloneStyle(elem);  
  33.                 div.style.cssText = 'visibility:hidden;display:inline-block;position:absolute;z-index:-100;word-wrap:break-word;word-break:break-all;overflow:hidden;';  
  34.             };  
  35.             div.style.left = this._offset(elem).left + "px";  
  36.             div.style.top = this._offset(elem).top + "px";  
  37.             var strTmp = elem.value.substring(0, index).replace(/</g, '<').replace(/>/g, '>').replace(/\n/g, '<br/>').replace(/\s/g, none);  
  38.             text.innerHTML = strTmp;  
  39.   
  40.             focus.style.display = 'inline-block';  
  41.             try { focusOffset = this._offset(focus); } catch (e) { };  
  42.             focus.style.display = 'none';  
  43.             return {  
  44.                 left: focusOffset.left,  
  45.                 top: focusOffset.top,  
  46.                 bottom: focusOffset.bottom  
  47.             };  
  48.         }  
  49.     },  
  50.   
  51.     // 克隆元素样式并返回类  
  52.     _cloneStyle: function (elem, cache) {  
  53.         if (!cache && elem['${cloneName}']) return elem['${cloneName}'];  
  54.         var className, name, rstyle = /^(number|string)$/;  
  55.         var rname = /^(content|outline|outlineWidth)$/; //Opera: content; IE8:outline && outlineWidth  
  56.         var cssText = [], sStyle = elem.style;  
  57.   
  58.         for (name in sStyle) {  
  59.             if (!rname.test(name)) {  
  60.                 val = this._getStyle(elem, name);  
  61.                 if (val !== '' && rstyle.test(typeof val)) { // Firefox 4  
  62.                     name = name.replace(/([A-Z])/g, "-$1").toLowerCase();  
  63.                     cssText.push(name);  
  64.                     cssText.push(':');  
  65.                     cssText.push(val);  
  66.                     cssText.push(';');  
  67.                 };  
  68.             };  
  69.         };  
  70.         cssText = cssText.join('');  
  71.         elem['${cloneName}'] = className = 'clone' + (new Date).getTime();  
  72.         this._addHeadStyle('.' + className + '{' + cssText + '}');  
  73.         return className;  
  74.     },  
  75.   
  76.     // 向页头插入样式  
  77.     _addHeadStyle: function (content) {  
  78.         var style = this._style[document];  
  79.         if (!style) {  
  80.             style = this._style[document] = document.createElement('style');  
  81.             document.getElementsByTagName('head')[0].appendChild(style);  
  82.         };  
  83.         style.styleSheet && (style.styleSheet.cssText += content) || style.appendChild(document.createTextNode(content));  
  84.     },  
  85.     _style: {},  
  86.   
  87.     // 获取最终样式  
  88.     _getStyle: 'getComputedStyle' in window ? function (elem, name) {  
  89.         return getComputedStyle(elem, null)[name];  
  90.     } : function (elem, name) {  
  91.         return elem.currentStyle[name];  
  92.     },  
  93.   
  94.     // 获取光标在文本框的位置  
  95.     _getFocus: function (elem) {  
  96.         var index = 0;  
  97.         if (document.selection) {// IE Support  
  98.             elem.focus();  
  99.             var Sel = document.selection.createRange();  
  100.             if (elem.nodeName === 'TEXTAREA') {//textarea  
  101.                 var Sel2 = Sel.duplicate();  
  102.                 Sel2.moveToElementText(elem);  
  103.                 var index = -1;  
  104.                 while (Sel2.inRange(Sel)) {  
  105.                     Sel2.moveStart('character');  
  106.                     index++;  
  107.                 };  
  108.             }  
  109.             else if (elem.nodeName === 'INPUT') {// input  
  110.                 Sel.moveStart('character', -elem.value.length);  
  111.                 index = Sel.text.length;  
  112.             }  
  113.         }  
  114.         else if (elem.selectionStart || elem.selectionStart == '0') { // Firefox support  
  115.             index = elem.selectionStart;  
  116.         }  
  117.         return (index);  
  118.     },  
  119.   
  120.     // 获取元素在页面中位置  
  121.     _offset: function (elem) {  
  122.         var box = elem.getBoundingClientRect(), doc = elem.ownerDocument, body = doc.body, docElem = doc.documentElement;  
  123.         var clientTop = docElem.clientTop || body.clientTop || 0, clientLeft = docElem.clientLeft || body.clientLeft || 0;  
  124.         var top = box.top + (self.pageYOffset || docElem.scrollTop) - clientTop, left = box.left + (self.pageXOffset || docElem.scrollLeft) - clientLeft;  
  125.         return {  
  126.             left: left,  
  127.             top: top,  
  128.             right: left + box.width,  
  129.             bottom: top + box.height  
  130.         };  
  131.     }  
  132. };  
  133.   
  134. function getPosition(ctrl) {  
  135.     var p = kingwolfofsky.getInputPositon(ctrl);  
  136.     document.getElementById('show').style.left = p.left + "px";  
  137.     document.getElementById('show').style.top = p.bottom + "px";  
  138. }  
测试页面如下:

[html]  view plain copy
  1. <!DOCTYPE html>  
  2. <html>  
  3. <head>  
  4.     <title>InputPostion</title>  
  5.     <script type="text/javascript" src="kingwolfofsky.js""></script>  
  6.     <script type="text/javascript">  
  7.         function show(elem) {  
  8.             var p = kingwolfofsky.getInputPositon(elem);  
  9.             var s = document.getElementById('show');  
  10.             s.style.top = p.bottom+'px';  
  11.             s.style.left = p.left + 'px';  
  12.             s.style.display = 'inherit';  
  13.         }  
  14.     </script>  
  15. </head>  
  16. <body>  
  17.     <textarea id="text" onkeyup="show(this)" style="width: 340px; height: 210px;"></textarea>      
  18.     <br />  
  19.     <input type="text" onkeyup="show(this)" style="width: 340px;" />  
  20.     <div id="show" style="width: 34px; height: 13px; background: #eee; position: absolute;border:1px solid grey;font-size:13px; display:none;">Tips</div>  
  21. </body>  
  22. </html>  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值