获取相对于 window (x,y) 的插入符位置坐标
Get caret position coordinates relative to the window (x,y)
摘要
我想获取插入符号(当用户开始输入时)的 window 位置(以像素为单位)。
全文
有一个多行 contentEditable
元素,其中包含复杂的 HTML 结构。
当用户 开始在其中的任何地方键入 时,在第一次击键时,我想在插入符号下方放置一个 absolute
定位元素。 必须新添加的元素会被注入到<body>
标签中,不是作为DOM内的节点contentEditable
元素。
因此我需要插入符号的精确全局坐标。我会清楚没有文本选择。
选择在这里无关紧要,甚至不太可能。
我的代码
通常一个问题应该包括一些 OP 尝试过并需要帮助的代码,但在这种情况下我完全没有想法。 input
DOM 事件 不 暴露坐标。我至少会提供我所追求的最终结果:
.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>
免责声明:
I've done quite a bit of digging on the matter but unfortunately could not find an answer.
Some questions seem similar but looking deeper, they are not at all, and some are extremely old & obsolete
谢谢!
经过更多的挖掘,我发现了一个 Gist file,它完全符合我的要求,
所以这里是我稍微调整了一下的工作:
/**
* 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
摘要
我想获取插入符号(当用户开始输入时)的 window 位置(以像素为单位)。
全文
有一个多行 contentEditable
元素,其中包含复杂的 HTML 结构。
当用户 开始在其中的任何地方键入 时,在第一次击键时,我想在插入符号下方放置一个 absolute
定位元素。 必须新添加的元素会被注入到<body>
标签中,不是作为DOM内的节点contentEditable
元素。
因此我需要插入符号的精确全局坐标。我会清楚没有文本选择。
选择在这里无关紧要,甚至不太可能。
我的代码
通常一个问题应该包括一些 OP 尝试过并需要帮助的代码,但在这种情况下我完全没有想法。 input
DOM 事件 不 暴露坐标。我至少会提供我所追求的最终结果:
.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>
免责声明:
I've done quite a bit of digging on the matter but unfortunately could not find an answer. Some questions seem similar but looking deeper, they are not at all, and some are extremely old & obsolete
谢谢!
经过更多的挖掘,我发现了一个 Gist file,它完全符合我的要求,
所以这里是我稍微调整了一下的工作:
/**
* 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