选择 API containsNode 似乎与可见选择不一致

问题描述 投票:0回答:0

选择:

containsNode()
方法采用可选的第二个参数,即
partialContainment

当我将其设置为

true
时,它似乎工作正常,但有时会拾取不属于可见选择的相邻元素。我将其设置为
false
以更严格,但它遗漏了元素。

页面上可见的“突出显示”与 API 如何解释“选定”内容之间有区别吗?

在下面的示例中,如果您选择部分文本,则某些字母不会变为活动状态,即使它们明显突出显示。我需要更改什么才能使显示为选中的任何内容的文本变为红色?

const sequences = ['CRABAPPLE', 'ORANGES', 'SQUASH'];

const handleTextSelection = (e) => {
  const selection = window.getSelection();
  const $container = $(e.currentTarget);
  const $sequence = $(e.target).closest('.sequence');
  $sequence.find('.letter').each((i, el) => {
    $(el).toggleClass('letter-active', selection.containsNode(el, false));
  });
  selection.empty();
};

$('#container').append(sequences.map(sequence =>
  $('<div>', { class: 'sequence' }).append(sequence.split('').map(letter =>
    $('<div>', { class: 'letter', text: letter })))));
    
$('#container').on('mouseup', handleTextSelection);
html, body, #container { width: 100%; height: 100%; margin: 0; padding: 0; }
#container { display: flex; flex-direction: row; gap: 0.25rem; align-items: center; justify-content: center; }
.sequence { display: flex; flex-direction: row; }
.sequence:after { content: ','; }
.sequence:last-child:after { content: none; }
.letter-active { color: red; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="container"><div>


更新

以下似乎工作得更好一些,但它仍然将部分(未实际选择的)字母计为所选字母。

const sequences = ['CRABAPPLE', 'ORANGES', 'SQUASH'];

const getLetter = (node) => {
  let letter = node;
  if (node.nodeName === '#text') { node = node.parentElement; }
  return node.classList.contains('letter') ? node : null;
};

const handleTextSelection = (e) => {
  const selection = window.getSelection();
  const range = selection.getRangeAt(0);
  const { startContainer, endContainer } = range
  const $container = $(e.currentTarget);
  const $sequence = $(range.commonAncestorContainer);
  const letterStart = getLetter(startContainer);
  const letterEnd = getLetter(endContainer);
  if (!letterStart || !letterEnd) { return; }
  let active = false;
  $sequence.find('.letter').each((i, el) => {
    if (el === letterStart) { active = true; }
    $(el).toggleClass('letter-active', active);
    if (el === letterEnd) { active = false; }
  });
  selection.empty();
};

$('#container').append(sequences.map(sequence =>
  $('<div>', { class: 'sequence' }).append(sequence.split('').map(letter =>
    $('<div>', { class: 'letter', text: letter })))));
    
$('#container').on('mouseup', handleTextSelection);
html, body, #container { width: 100%; height: 100%; margin: 0; padding: 0; }
#container { display: flex; flex-direction: row; gap: 0.25rem; align-items: center; justify-content: center; }
.sequence { display: flex; flex-direction: row; }
.sequence:after { content: ','; }
.sequence:last-child:after { content: none; }
.letter-active { color: red; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="container"><div>

javascript highlight textselection
© www.soinside.com 2019 - 2024. All rights reserved.