javascript - 获取页面中被选中文字的相对位置

 圣友家具简章da 发布于 2022-11-23 13:26

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Odit, saepe, tempore, quam, similique perferendis possimus rem optio harum sapiente hic dicta temporibus quae sit neque eaque illo ex 你好 asperiores consectetur nemo ullam odio delectus distinctio enim quasi cumque accusantium deleniti voluptatum eligendi sunt quibusdam

在页面中选中了

标签里的“你好”后,我想要返回它在页面中的相对位置。
要用到什么方法。

2 个回答
  • 「被选中文字的相对位置」,位置(Position)既可理解爲相對於給定原點的笛卡爾坐標系的坐標(Coordinate, 公子的答案),也可以理解爲以字符爲基本單位的坐標(Offset, 如選擇了字符從第 10 到第 12)。

    對於前者:

    Range.getBoundingClientRect()

    若老舊瀏覽器不支持,可以使用 span 包圍選區(Range.surroundContents()),然後 Element.getBoundingClientRect()。

    下面是對後者的答案:

    因爲涉及到任意富文本,我寫了一個通用富文本光標抽象(來自 http://segmentfault.com/blog/bum/1190000000764811)。

    var c = document.querySelector("code");
    
    var Caret = function() {
        function some(a, f, u) {
            if (u === void(0)) u = false;
            for (var i = 0, n = a.length, r; i < n; ++i) if ((r = f(a[i], i, n)) !== u) return r;
            return u;
        }
    
        function getOffset(c, co, cc) {
            var cto = co, cp;
            if (c.nodeType !== 3) co = 0, some(c.childNodes, function(x, i) {
                if (i === cto) return true;
                co += x.textContent.length;
                return false;
            });
            return c === cc || cc && !cc.contains(c) ? co : function get(c, co, cc) {
                var cp = c.parentNode;
                if (c !== cp.firstChild) some(cp.childNodes, function(x) {
                    if (x === c) return true;
                    co += x.textContent.length;
                    return false;
                });
                return cc && cc !== cp && cc.contains(cp) ? get(cp, co, cc) : co;
            }(c, co, cc);
        }
    
        function setOffset(cc, co, set, tion) {
            var to = co, c = cc;
            some(cc.childNodes, function(x, i, n) {
                var l = x.textContent.length; c = x;
                if (tion) {
                    if (to < l) return true;
                    if (to !== l || i !== n - 1) to -= l;
                } else {
                    if (to <= l) return true;
                    to -= l;
                }
                return false;
            });
            return c === cc || c.nodeType === 3 ? (set(c, to), c) : c = setOffset(c, to, set, tion);
        }
    
        return { get: getOffset, set: setOffset };
    }();
    
    function getCaret(x) {
        var s = window.getSelection(), r = s.getRangeAt(0);
    
        return (x.contains(r.startContainer)) ? 
            [Caret.get(r.startContainer, r.startOffset, x), Caret.get(r.endContainer, r.endOffset, x)] : false;
    }
    
    function setCaret(ro, y) {
        var s = window.getSelection(), r;
    
        if (ro) {
            if (document.activeElement !== c)
                c.focus();
    
            s.removeAllRanges();
    
            r = document.createRange();
    
            Caret.set(y, ro[0], r.setStart.bind(r));
    
            if (ro[0] === ro[1])
                r.collapse(true);
            else
                Caret.set(y, ro[1], r.setEnd.bind(r));
    
            s.addRange(r);
        }
    }
    

    獲取光標相對於元素的位置(當光標包含在該元素中時):getCaret(c)
    設置光標相對於元素的位置:setCaret([caretStart, caretEnd], c)

    2022-11-23 13:50 回答
  • getSelection() 可以捕捉到光标选择内容的位置,也能拿到选择内容所处的 DOM 标签,也能拿到选择内容前的文字。

    1. 先算出 容器DOM 所处页面的相对位置
    2. 新设一个 p,样式和 容器DOM 要一致,然后把选择内容前的文字放进去,容器DOM 的高度 + 该 p 的高度 就是选择文字的高度了
    3. 记下上一个 p 的宽度,然后再设置一个 span 保证内容在一行然后得到这个 span 的宽度,并以 p 的宽度取余,这样 容器DOM 的宽度 + p 宽度 % span 宽度 就是选择文字的宽度了。

    记得每次处理完之后记得把过程中的 p 和 span 都删除掉,这样应该能应付绝大多数的场景了。

    2022-11-23 13:50 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有