Подтвердить что ты не робот

Как получить смещение пикселя от текущей позиции каретки в iframe с contentEditable

Я хотел бы поместить плавающий элемент div в iframe с contentEditable, если пользователь вводит определенную комбинацию клавиш (для целей автозаполнения).

Я знаю, как получить позицию каретки: document.getElementById('elm1_ifr').contentWindow.getSelection().anchorOffset

Я могу использовать это для вычисления свойства left для div, но я не могу понять, как получить top.

Другая возможность, о которой я думал, - использование: document.getElementById('elm1_ifr').contentWindow.getSelection().anchorNode.parentNode

И используя jQuery для получения смещения, но если у этого родителя есть длинная текстовая строка, я бы смог извлечь только верхнюю позицию первой строки.

Может ли кто-нибудь помочь мне с этим?

4b9b3361

Ответ 1

Единственный надежный способ сделать это - вставить временный элемент в каретку (убедитесь, что он равен нулю), получить его положение и удалить его снова. Вы должны также склеить два конца текста node (если это был текст node, содержащий каретку) назад, чтобы гарантировать, что DOM так же, как и перед вставкой node. Обратите внимание, однако, что выполнение этого (или любого другого ручного манипулирования DOM на редактируемом контенте) нарушает внутренний стек отладки браузера.

Причиной этого является то, что тщательное чтение спецификации для метода getBoundingClientRect() Range показывает, что getBoundingClientRect() не обязан возвращать Rect для свернутого диапазона. Понятно, что не каждая позиция в документе имеет четко определенный ограничивающий прямоугольник. Однако каретка имеет физическое расположение на экране, которое, на мой взгляд, должно предоставляться API-интерфейсом выбора, но в настоящее время в браузерах нет ничего, чтобы обеспечить это.

Ответ 2

Сегодня я столкнулся с этой проблемой. После некоторого тестирования я получил эту работу, не используя темный элемент.

В IE легко обрабатывать его со свойствами offsetLeft и offsetTop объекта TextRange. Однако для webkit необходимы некоторые усилия.

В этом тесте вы можете увидеть результат. http://jsfiddle.net/gliheng/vbucs/12/

var getCaretPixelPos = function ($node, offsetx, offsety){
    offsetx = offsetx || 0;
    offsety = offsety || 0;

    var nodeLeft = 0,
        nodeTop = 0;
    if ($node){
        nodeLeft = $node.offsetLeft;
        nodeTop = $node.offsetTop;
    }

    var pos = {left: 0, top: 0};

    if (document.selection){
        var range = document.selection.createRange();
        pos.left = range.offsetLeft + offsetx - nodeLeft + 'px';
        pos.top = range.offsetTop + offsety - nodeTop + 'px';
    }else if (window.getSelection){
        var sel = window.getSelection();
        var range = sel.getRangeAt(0).cloneRange();
        try{
            range.setStart(range.startContainer, range.startOffset-1);
        }catch(e){}
        var rect = range.getBoundingClientRect();
        if (range.endOffset == 0 || range.toString() === ''){
            // first char of line
            if (range.startContainer == $node){
                // empty div
                if (range.endOffset == 0){
                    pos.top = '0px';
                    pos.left = '0px';
                }else{
                    // firefox need this
                    var range2 = range.cloneRange();
                    range2.setStart(range2.startContainer, 0);
                    var rect2 = range2.getBoundingClientRect();
                    pos.left = rect2.left + offsetx - nodeLeft + 'px';
                    pos.top = rect2.top + rect2.height + offsety - nodeTop + 'px';
                }
            }else{
                pos.top = range.startContainer.offsetTop+'px';
                pos.left = range.startContainer.offsetLeft+'px';
            }
        }else{
            pos.left = rect.left + rect.width + offsetx - nodeLeft + 'px';
            pos.top = rect.top + offsety - nodeTop + 'px';
        }
    }
    return pos;
};