Получить координаты положения каретки относительно окна (x,y)

Абстрактный

Я хотел бы получить положение окна (в пикселях) курсора (когда пользователь начинает печатать).

Полный рассказ

Там есть многострочный элемент contentEditable со сложной структурой HTML внутри него.
Когда пользователь начинает печатать в любом месте внутри него, при первом нажатии клавиши я хотел бы поместить элемент с позиционированием absolute под курсором . обязательно, чтобы вновь добавленный элемент был внедрен в тег <body>, а не как DOM-узел внутри элемента contentEditable.

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

Мой код

Обычно вопрос должен включать некоторый код, который пробовал ОП и с которым требуется помощь, но в этом случае у меня нет идей. Событие DOM input DOM не< /em> показать координаты. Я по крайней мере предоставлю конечный результат того, что мне нужно:

.info{
  border: 1px solid gold;
  padding: 8px;
  background: rgba(255,255,224, .8);
  position: absolute;
  z-index: 9999;
  max-width: 180px;
}
<h2>contentEditable:</h2>
<div contentEditable>
  <p>
    Lorem ipsum dolor sit amet, consectetur adipiscing elit, 
    sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. 
    <strong>Ut enim ad minim veniam</strong>, 
    quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. 
  </p>

  <p>
    Imagine the caret is somewhere here and the info element is right under it... <div>reprehenderit <em>in</em> voluptate</div> 
    velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat 
    cupidatat non proident, sunt in culpa qui officia deserunt <small>mollit anim</small> 
    id est laborum.
  </p>
</div>
<div class='info' style='top:150px; left:60px;'>Extra info with a long list of some content goes here</div>


Отказ от ответственности:

Я довольно много копался в этом вопросе, но, к сожалению, не смог найти ответ. Некоторые вопросы кажутся похожими, но если посмотреть глубже, то они совсем не такие, а некоторые очень старые и устаревшие.

Спасибо!


person vsync    schedule 21.11.2019    source источник


Ответы (1)


Еще немного покопавшись, я нашел Gist-файл, который делал именно то, что я хотел,
Итак, вот работа, которую я немного подправил:

/**
 * Get the caret position, relative to the window 
 * @returns {object} left, top distance in pixels
 */
function getCaretGlobalPosition(){
    const r = document.getSelection().getRangeAt(0)
    const node = r.startContainer
    const offset = r.startOffset
    const pageOffset = {x:window.pageXOffset, y:window.pageYOffset}
    let rect,  r2;

    if (offset > 0) {
        r2 = document.createRange()
        r2.setStart(node, (offset - 1))
        r2.setEnd(node, offset)
        rect = r2.getBoundingClientRect()
        return { left:rect.right + pageOffset.x, top:rect.bottom + pageOffset.y }
    }
}

/////////////////[ DEMO ]\\\\\\\\\\\\\\\\\\\\

const contenteditable = document.querySelector('[contenteditable]')
const infoElm = document.querySelector('.info')

contenteditable.addEventListener('input', onInput)

function onInput(){
  const caretGlobalPosition = getCaretGlobalPosition()

  infoElm.style.cssText = `top:${caretGlobalPosition.top}px;
                           left:${caretGlobalPosition.left}px;`
}
.info{
  border: 1px solid gold;
  padding: 8px;
  background: rgba(255,255,224, .8);
  position: absolute;
  z-index: 9999;
  max-width: 180px;
  display:none;
}

.info[style]{ display:block; }
<h2>Place caret somewhere and type:</h2>
<div contenteditable>
  <p>
    Lorem ipsum dolor sit amet, consectetur adipiscing elit, 
    sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. 
    <strong>Ut enim ad minim veniam</strong>, 
    quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. 
  </p>

  <h2>
    Imagine the caret is somewhere here and the info element is right under it... <div>reprehenderit <em>in</em> voluptate</div> 
    velit esse cillum dolore eu fugiat f nulla pariatur. Excepteur sint occaecat 
    cupidatat non proident, sunt in culpa qui officia deserunt <small>mollit anim</small> 
    id est laborum.
  </h2>
</div>
<div class='info'>Extra info with a long list of some content goes here</div>


Другое решение, которое я нашел: https://github.com/component/textarea-caret-position

person vsync    schedule 22.11.2019