【简介】本文主要实现获取textarea和input光标的像素位置,即光标的offsetLeft与offsetTop。可实现如下效果:
首先说明一下,在网上搜到的很多代码是如何获取输入光标位置的如下代码是如何获取光标的的字符位置,如对于串“He|llo World!”返回的是光标|前的字符数2,并不是光标在页面上的像素位置。当然,这段代码对于获取光标的像素位置能起到一定的辅助作用。
- // 获取光标在文本框的位置
- function _getFocus(elem) {
- var index = 0;
- if (document.selection) {// IE Support
- elem.focus();
- var Sel = document.selection.createRange();
- if (elem.nodeName === 'TEXTAREA') {//textarea
- var Sel2 = Sel.duplicate();
- Sel2.moveToElementText(elem);
- var index = -1;
- while (Sel2.inRange(Sel)) {
- Sel2.moveStart('character');
- index++;
- };
- }
- else if (elem.nodeName === 'INPUT') {// input
- Sel.moveStart('character', -elem.value.length);
- index = Sel.text.length;
- }
- }
- else if (elem.selectionStart || elem.selectionStart == '0') { // Firefox support
- index = elem.selectionStart;
- }
- return (index);
- }
- //代码1
- if (document.selection) {
- elem.focus();
- var Sel = document.selection.createRange();
- return {
- left: Sel.boundingLeft,
- top: Sel.boundingTop,
- bottom: Sel.boundingTop + Sel.boundingHeight
- };
- }
而对于firefox之类的浏览器则通过模拟来实现,如下图所示。首先通过拷贝输入区域的样式到一个div层(clone层),然后在此clone层之中的text子层添加光标之前的字符,并在text子层之后添加focus层,focus层中包含字符“|”来模拟光标,进而通过获取focus层的偏移量即可获得文本光标的像素坐标位置。
具体实现代码如下:
- var kingwolfofsky = {
- /**
- * 获取输入光标在页面中的坐标
- * @param {HTMLElement} 输入框元素
- * @return {Object} 返回left和top,bottom
- */
- getInputPositon: function (elem) {
- if (document.selection) { //IE Support
- elem.focus();
- var Sel = document.selection.createRange();
- return {
- left: Sel.boundingLeft,
- top: Sel.boundingTop,
- bottom: Sel.boundingTop + Sel.boundingHeight
- };
- } else {
- var that = this;
- var cloneDiv = '{$clone_div}', cloneLeft = '{$cloneLeft}', cloneFocus = '{$cloneFocus}', cloneRight = '{$cloneRight}';
- var none = '<span style="white-space:pre-wrap;"> </span>';
- var div = elem[cloneDiv] || document.createElement('div'), focus = elem[cloneFocus] || document.createElement('span');
- var text = elem[cloneLeft] || document.createElement('span');
- var offset = that._offset(elem), index = this._getFocus(elem), focusOffset = { left: 0, top: 0 };
- if (!elem[cloneDiv]) {
- elem[cloneDiv] = div, elem[cloneFocus] = focus;
- elem[cloneLeft] = text;
- div.appendChild(text);
- div.appendChild(focus);
- document.body.appendChild(div);
- focus.innerHTML = '|';
- focus.style.cssText = 'display:inline-block;width:0px;overflow:hidden;z-index:-100;word-wrap:break-word;word-break:break-all;';
- div.className = this._cloneStyle(elem);
- div.style.cssText = 'visibility:hidden;display:inline-block;position:absolute;z-index:-100;word-wrap:break-word;word-break:break-all;overflow:hidden;';
- };
- div.style.left = this._offset(elem).left + "px";
- div.style.top = this._offset(elem).top + "px";
- var strTmp = elem.value.substring(0, index).replace(/</g, '<').replace(/>/g, '>').replace(/\n/g, '<br/>').replace(/\s/g, none);
- text.innerHTML = strTmp;
- focus.style.display = 'inline-block';
- try { focusOffset = this._offset(focus); } catch (e) { };
- focus.style.display = 'none';
- return {
- left: focusOffset.left,
- top: focusOffset.top,
- bottom: focusOffset.bottom
- };
- }
- },
- // 克隆元素样式并返回类
- _cloneStyle: function (elem, cache) {
- if (!cache && elem['${cloneName}']) return elem['${cloneName}'];
- var className, name, rstyle = /^(number|string)$/;
- var rname = /^(content|outline|outlineWidth)$/; //Opera: content; IE8:outline && outlineWidth
- var cssText = [], sStyle = elem.style;
- for (name in sStyle) {
- if (!rname.test(name)) {
- val = this._getStyle(elem, name);
- if (val !== '' && rstyle.test(typeof val)) { // Firefox 4
- name = name.replace(/([A-Z])/g, "-$1").toLowerCase();
- cssText.push(name);
- cssText.push(':');
- cssText.push(val);
- cssText.push(';');
- };
- };
- };
- cssText = cssText.join('');
- elem['${cloneName}'] = className = 'clone' + (new Date).getTime();
- this._addHeadStyle('.' + className + '{' + cssText + '}');
- return className;
- },
- // 向页头插入样式
- _addHeadStyle: function (content) {
- var style = this._style[document];
- if (!style) {
- style = this._style[document] = document.createElement('style');
- document.getElementsByTagName('head')[0].appendChild(style);
- };
- style.styleSheet && (style.styleSheet.cssText += content) || style.appendChild(document.createTextNode(content));
- },
- _style: {},
- // 获取最终样式
- _getStyle: 'getComputedStyle' in window ? function (elem, name) {
- return getComputedStyle(elem, null)[name];
- } : function (elem, name) {
- return elem.currentStyle[name];
- },
- // 获取光标在文本框的位置
- _getFocus: function (elem) {
- var index = 0;
- if (document.selection) {// IE Support
- elem.focus();
- var Sel = document.selection.createRange();
- if (elem.nodeName === 'TEXTAREA') {//textarea
- var Sel2 = Sel.duplicate();
- Sel2.moveToElementText(elem);
- var index = -1;
- while (Sel2.inRange(Sel)) {
- Sel2.moveStart('character');
- index++;
- };
- }
- else if (elem.nodeName === 'INPUT') {// input
- Sel.moveStart('character', -elem.value.length);
- index = Sel.text.length;
- }
- }
- else if (elem.selectionStart || elem.selectionStart == '0') { // Firefox support
- index = elem.selectionStart;
- }
- return (index);
- },
- // 获取元素在页面中位置
- _offset: function (elem) {
- var box = elem.getBoundingClientRect(), doc = elem.ownerDocument, body = doc.body, docElem = doc.documentElement;
- var clientTop = docElem.clientTop || body.clientTop || 0, clientLeft = docElem.clientLeft || body.clientLeft || 0;
- var top = box.top + (self.pageYOffset || docElem.scrollTop) - clientTop, left = box.left + (self.pageXOffset || docElem.scrollLeft) - clientLeft;
- return {
- left: left,
- top: top,
- right: left + box.width,
- bottom: top + box.height
- };
- }
- };
- function getPosition(ctrl) {
- var p = kingwolfofsky.getInputPositon(ctrl);
- document.getElementById('show').style.left = p.left + "px";
- document.getElementById('show').style.top = p.bottom + "px";
- }
- <!DOCTYPE html>
- <html>
- <head>
- <title>InputPostion</title>
- <script type="text/javascript" src="kingwolfofsky.js""></script>
- <script type="text/javascript">
- function show(elem) {
- var p = kingwolfofsky.getInputPositon(elem);
- var s = document.getElementById('show');
- s.style.top = p.bottom+'px';
- s.style.left = p.left + 'px';
- s.style.display = 'inherit';
- }
- </script>
- </head>
- <body>
- <textarea id="text" onkeyup="show(this)" style="width: 340px; height: 210px;"></textarea>
- <br />
- <input type="text" onkeyup="show(this)" style="width: 340px;" />
- <div id="show" style="width: 34px; height: 13px; background: #eee; position: absolute;border:1px solid grey;font-size:13px; display:none;">Tips</div>
- </body>
- </html>