插入符在contenteditable div中输入span元素时引发事件 [英] Fire event when caret enters span element in contenteditable div

查看:51
本文介绍了插入符在contenteditable div中输入span元素时引发事件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个内容可编辑的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 :

document.addEventListener('selectionchange',ev => document.getSelection().baseNode.parentNode.dispatchEvent(new Event('caret')))

document.addEventListener('selectionchange', ev => document.getSelection().baseNode.parentNode.dispatchEvent(new Event('caret')))

然后使用经典的HTML侦听器:

Then use the classic HTML listeners :

span.addEventListener('caret',function callback(){/* ... */});

span.addEventListener('caret', function callback() { /* ... */ });

请注意,您必须检查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元素时引发事件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆