问题描述
我有一个内容可编辑的div,其跨度如下:
I have a content editable div with a span like this:
<div contenteditable="true">some <span>spanned</span> text</div>
我想知道是否可以将任何事件侦听器附加到 span
元素本身,该元素可用于检测插入符号是否在 span
内移动元素.
And I would like to know if there are any event listeners I can attach to the span
element itself that can be used to detect if the caret moves inside the span
element.
我不是要寻找在 div
上附加了侦听器的答案,而是每次 div
中有活动时都进行检查,例如解决方案这个答案:
I am not looking for an answer where there are listeners attached to the div
, running a check every time there is activity in the div
, such as the solution to this answer:
推荐答案
了解用户输入位置的最简单方法是 document.getSelection()
,它提供了一些节点引用,例如 baseNode
和当前的 focusNode
以及有用的偏移量信息.
Easiest way to know where user inputs is document.getSelection()
which gives a few node references like the baseNode
and the current focusNode
along with useful offset informations.
然后,您可以在 document
上使用 selectionchange
事件来了解光标何时移动,而无需检查是否正在移动/单击鼠标或不使用键盘事件.
You can then use a selectionchange
event on the document
to know when the cursor moves around without checking if the mouse is being moved/clicked nor using keyboard events.
var out, itm; // saved to spare processor time
document.addEventListener('selectionchange',
function(ev) { // called whenever keycursor moves
// find and save our main HTML objects
if (!out) out = document.getElementById('out');
if (!itm) itm = document.querySelector('span');
// get the user selection informations
let grab = document.getSelection(),
text = grab.baseNode ||0, // <-- clicked here
node = text.parentNode; // <-- container
out.innerHTML = // now print where we're at~
// nowhere near the span, showing a hint
!node?"Well, try moving around the span ..":
// peaking inside the output, wrong way
node == out?"You're grabbing me out ...":
// checked around, let's check for the node
(node == itm?'inside ': // inside span itself
// check if we're selecting the whole node
grab.containsNode(itm)?'found in ':
// check if at least we selected a part of it
grab.containsNode(itm.firstChild)?'partial ':
'other ') + // seemingly somewhere else ...
node.nodeName + // write which node we found
' > ' + // and show a bit of the contents
(text.data || text.innerText).substr(0, 24);
})
body > div {border: 1px solid; font-size: xlarge;}
#out {background: black; color: white; margin: 1em}
div > span {color: red;} * {padding: 1ex 1em}
<div contenteditable>
This is a text before
<span>this span</span>
in middle of the text
</div>
<div id="out">focus NODE > contents ...</div>
现在,这可能会使100个节点检查起来非常混乱...您不希望绑定/定时侦听器或自定义节点,因此我个人建议使用经典事件侦听器.
Now this might get very confusing with 100's of nodes to check... You didn't want bound/timed listeners or custom nodes, so I'd personally recommend going with the classic event listeners.
您可以使用以下命令在选择开始节点上生成插入符
事件:
You can generate caret
events on the selection-start node, with :
然后使用经典的HTML侦听器:
Then use the classic HTML listeners :
请注意,您必须检查neightbor-HTML-children中的插入符移动,才能知道这种方法是否超出您的范围;存储哪个节点处于活动状态可能很有趣,因此您可以按照Daniel的答案中的建议在 caretIn
和 caretOut
中进行操作...这是一个简单的实现:
Note that you'll have to check for a caret move in neightbor-HTML-children to know whether it goes off your span with this approach; it might be interesting to store which node is active so you can caretIn
and caretOut
as proposed in Daniel's answer ... Here is a simple implementation :
document.addEventListener('selectionchange', ev => {
var node = (document.getSelection().baseNode||0).parentNode,
old = document.lastGrab; if (node === old) return;
if (old) old.dispatchEvent(new Event('caretOut'));
(document.lastGrab = node).dispatchEvent(new Event('caretIn'));
});
var node = document.querySelector('span'); // find it the way you want
node.addEventListener('caretIn', function callback() { /* ... */ });
node.addEventListener('caretOut', function callback() { /* ... */ });
希望您现在拥有所需的东西;快乐的编码:)
Hope you now have what you needed; Happy coding :)
这篇关于插入符在contenteditable div中输入span元素时引发事件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!