为了账号安全,请及时绑定邮箱和手机立即绑定

我可以使用什么来使用多个文本节点可靠地获取 Javascript 中单击的字符偏移量?

我可以使用什么来使用多个文本节点可靠地获取 Javascript 中单击的字符偏移量?

GCT1015 2023-11-02 21:27:07
当用户单击某些文本时,我使用Window.getSelection获取用户单击位置的字符偏移量。当只有一个文本节点时,这非常有效,并且关于如何做到这一点有很多很好的答案。但是,当我有两个或多个文本节点彼此相邻呈现时,我遇到了问题。这是一个复制问题的小提琴,但我将在这里介绍它:用例:我正在构建一个文本编辑器,并使用对用户按键做出反应的 Javascript 控制 DOM,而不是使用 contentEditable 容器。我想跟踪(并显示)用户的“光标”在文本中的位置(即,如果他们开始输入,将输入文本的位置),并让他们单击文本中的任意位置以手动设置光标到他们点击的地方。HTML:<p class="sentence">  <span class="word" index="0">There </span><span class="word" index="1">is </span><span class="word" index="2">a </span><span class="word" index="3">big, </span><span class="word" index="4">wonderful </span><span class="word" index="5">world.</span></p>JavaScript:$('.word').click(function() {  let word_index = $(this).attr('index');    let selection  = window.getSelection();  let char_index = selection.focusOffset;  console.log('Clicked to set a new cursor @');  console.log('Word index = ' + word_index.toString() +              ' / char index = ' + char_index.toString() );});简而言之,此代码打印 aword index和 acharacter index表示光标在文本中的位置,就好像它是可编辑输入一样。如果你点击“There”中“T”的左半部分,它会打印Clicked to set a new cursor @Word index = 0/ char index = 0单击“T”的右侧(这样光标将放置在其之后但“h”之前)将打印相同的单词索引,但字符索引为 1,因为光标现在放置在一个字符上,等等。这也很有效......除了单击任何单词(第一个除外)的第一个字符的左半部分。单击“is”中“i”的左半部分(在单词索引 1、字符索引 0 处设置插入符号)会打印单词索引 1(正确)和字符索引 6(前一个单词的长度)。当存在多个彼此相邻的文本节点时Window.getSelection(或更具体地说, )不是计算这种字符偏移量的正确方法吗?selection.focusOffset我需要使用其他库或方法吗?解决该问题的一个“解决方案”是在每个单词周围应用边距,以在它们之间放置不可点击的间隙。在这种情况下,单击“i”的左半部分会给出正确的单词/字符索引(1,0 而不是 1,6),但会产生空格的副作用,如果用户不小心单击那里,则不会发生任何情况(此应用程序中存在严重的副作用,因此它并不是真正可行的“修复”)。看起来至少 3px 的边距总是返回正确的值,而 2px 或更小的边距总是返回错误的值。我正在 Chrome 中进行测试,因为我最终将构建一个 Electron 应用程序,所以我想我只需要它在 Blink 中工作,但如果解决方案对于 Web 版本也与浏览器无关,那就太好了。
查看完整描述

2 回答

?
潇潇雨雨

TA贡献1833条经验 获得超4个赞

我能够通过实施以下两个额外的护栏来实现此目的:

https://img1.sycdn.imooc.com/6543a3d200014c7b04290373.jpg

要使其跨浏览器,还有更多工作要做,但这里有一个更新的小提琴,它使用这些调整来获取 Chrome 中所需的值。



查看完整回答
反对 回复 2023-11-02
?
子衿沉夜

TA贡献1828条经验 获得超3个赞

默认行为取决于浏览器,因此您需要进行一些检查才能给出一致的结果。

这是一个简单的示例,它将event.target元素与parentElement返回的文本节点的进行比较selection.focusNode,如果不匹配,它会检查焦点节点的兄弟节点是否匹配并相应地调整偏移量。

您需要使其更加稳健。您还需要处理方向性(从左到右选择会产生反向焦点,并且选择从右到左的锚节点)。您也可以看看Selection.containsNode()

function handleSelection(e) {

  const selection = window.getSelection();

  

  const fNode = selection.focusNode;

  

  const fElement = fNode.parentElement;

  const tElement = e.target;

  

  let word_index = tElement.dataset.index;

  let char_index = selection.focusOffset;

  

  if (!fElement.isEqualNode(tElement) 

    && fElement.nextElementSibling.isEqualNode(tElement)) {

    char_index=0;

  }

  

  console.log(

    'fNode: ', fNode.parentElement.innerText,

    ' tNode: ', tElement.innerText,

    ' char: ', char_index,

    ' word: ', word_index

  );


}


const words = document.querySelectorAll('.word');

words.forEach((w, i) => (

  w.dataset.index = i+1, 

  w.addEventListener('click', handleSelection)));

.word {

  border: 1px solid gray;

  font-size: 2rem;

}

<p class="sentence">

  <span class="word">Hello </span><span class="word">wonderful</span><span class="word"> world.</span>

</p>


查看完整回答
反对 回复 2023-11-02
  • 2 回答
  • 0 关注
  • 57 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信