动态获取输入框光标在页面中的位置! || 动态添加 style标签 || 获取元素样式 || 获取元素在页面中的位置

html

<!DOCTYPE html>
<html>
    <head>
    <title>InputPostion</title>
    <script src="./getFocusPosition.js"></script>
    </head>
    <body>
        <textarea id="text" style=" 340px; height: 210px;"></textarea>
        <button onclick=" getPosition() ">获取焦点</button>
        <script>
            function getPosition(){
                let textareaNode = document.getElementById("text");
                console.log("textarea焦点位置",getFocusPosition.getInputPositon(textareaNode));
            }
        </script>
    </body>
</html>

getFocusPosition.js

/**
 * getPositionApiObj 是获取输入框(textarea、input)的光标焦点位置的对象,里面包含各种api,其中getInputPositon方法会返回 光标的位置坐标
 */
var getFocusPosition = {
    /**
    * 主方法
    * 获取输入光标在页面中的坐标
    * @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 {// 非IE Support
            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'), //clone的div元素
                focus = elem[cloneFocus] || document.createElement('span');//clone的span元素
            var text = elem[cloneLeft] || document.createElement('span');//clone的span元素
            var offset = that._offset(elem), 
                index = this._getFocus(elem), //获取到textarea或input的光标所在的索引
                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;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(/
/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
            };
        }
    },

    /**
    *获取光标在文本域或输入框的光标所在的位置(这里的位置是光标在第几个字符串的索引)对获取光标位置有辅助作用
    *@param {HTMLElement} 输入框元素
    */
    _getFocus:function(elem) {
        var index =0;
        if (document.selection) {// IE Support
            console.log("支持");
            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);
    },
    /**
    *获取元素在页面中位置
    *@param {HTMLElement} 输入框元素
    */
    _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
        };
    },
    // 克隆元素样式并返回类
    _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)) {
                var val;
                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;
    },
    // 获取元素某个属性样式值
    _getStyle: 'getComputedStyle'in window ? function (elem, name) {
        return getComputedStyle(elem, null)[name];
    } :  function (elem, name) {
        return elem.currentStyle[name];
    },
    // 动态插入style标签(样式)
    _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: {},

}

效果:

 原理是,动态创建一个div,克隆输入框的所有样式,往div内动态添加两个span元素,span(text)里面装输入框里的文字,span(模仿光标),这两个元素都设置为行内块元素,然后只需要获取到span(模拟光标)在页面中的位置,就是光标所在的位置。

原文地址:https://www.cnblogs.com/fqh123/p/13536522.html