【问题标题】:contenteditable selection of text not workingcontenteditable 文本选择不起作用
【发布时间】:2017-04-05 16:30:39
【问题描述】:

我面临以下问题:当我尝试在 contenteditable 元素中选择文本并且选择的结尾是元素内容的开始时,则不会触发 select 事件并且没有 Selection 和 @ 987654329@ 个对象。

有人可以就为什么会发生这种情况或如何防止这种情况给我任何建议吗?

负责获取选择范围的代码:

$('div[contenteditable="true"]').bind("mouseup keyup touchend", function() {
  lastCaretIndex = getSelectionRange();
});

function getSelectionRange() {
  var sel;
  if (window.getSelection) {
    sel = window.getSelection();

    console.log(sel); // this doesn't print anything event empty string

    if (sel.rangeCount) {
      return sel.getRangeAt(0);
    }
  } else if (document.selection) {
    return document.createRange();
  }

  return null;
}
<div id="main-input" contenteditable="true">Hello world!</div>
<script type="text/javascript" src="https://code.jquery.com/jquery-2.2.4.min.js"></script>

JSFiddle(打开您的浏览器控制台以确保选择不会被记录)。

【问题讨论】:

  • 这个问题用example code会好很多。如果您将其发布在jsfiddlestack snippet,我们可以立即看到您使用的代码,并从那里开始。
  • @phihag 你好,我已经添加了负责获取用户选择范围的代码
  • 请创建一个工作代码示例来显示您所面临的问题。我确定您的代码示例中上面的unction() 需要工作,我只是不想挖掘错别字...
  • @caramba 我添加了 jsfiddle 链接

标签: javascript range selection


【解决方案1】:

问题是您仅在 contenteditable 元素上发生特定事件时记录选择更改。更具体地说,你有

$('div[contenteditable="true"]').bind("mouseup keyup touchend", // ...

特别是mouseup 事件通常会在选择更改时触发。除非它没有。当您在可编辑的 div 之外释放鼠标(在您的示例中就是这样做的!),那么 div 将永远不会收到 mouseup 事件,因此永远不会记录选择。

有两种解决方法:

  1. 监听整个body 的事件。缺点是您会收到更多不影响选择的事件,并且仍然可以在页面外获得mouseup 事件。
  2. 收听selectionchange 事件。

document.addEventListener('selectionchange', function(event) {
  console.log(event.type);
});
&lt;div contenteditable="true"&gt;Hello world!&lt;/div&gt;

当然,您仍然可以像当前在此事件处理程序中那样访问选择。每次选择更改时都会触发此事件,因此您可能需要throttle它。

可以在下面找到完整的实现。

function handler() {
  // do whatever you want here
  // this shows the selection and all ranges it consists of
  var sel = window.getSelection(),
      ranges = Array(sel.rangeCount).fill(0).map((_, i) => sel.getRangeAt(i));
  ranges = ranges.map((r) => `${r.startOffset}-${r.endOffset}`).join(';');
  console.log(`Selection [${ranges}:"${sel.toString()}"]`);
}

function throttle(func) {
  var timeoutId = false,
      called = false,
      wrap = function() {
        if (!called) {
          clearInterval(timeoutId);
          timeoutId = false;
        } else {
          func();
        }
        called = false;
      };
  return function() {
    if (timeoutId === false) {
      func();
      timeoutId = setInterval(wrap, 500);
    } else {
      called = true;
    }
  };
}

document.addEventListener('selectionchange', throttle(handler));
&lt;div contenteditable="true"&gt;Hello world!&lt;/div&gt;

【讨论】:

  • 哦,不清楚为什么会出现这个问题。非常感谢,现在我将尝试改用文档侦听器
  • @excluded 我刚刚更新了我的答案以包含节流的演示。
【解决方案2】:

您的实际代码完美运行并在控制台中记录一个Selection 对象,即使选择的结尾是元素内容的开头。

确实,您需要记录此 Selection 文本,而不是记录整个 object,它反映了每个事件的整个 Selection 对象更改。

我更新了您的 sn-p 以使用 Selection.toString() 记录选择的文本,您可以在此处看到它的工作原理:

$('div[contenteditable="true"]').bind("mouseup keyup touchend", function() {
  lastCaretIndex = getSelectionRange();
});

function getSelectionRange() {
  var sel;
  if (window.getSelection) {
    sel = window.getSelection();

    console.log(sel.toString()); // this doesn't print anything event empty string

    if (sel.rangeCount) {
      return sel.getRangeAt(0);
    }
  } else if (document.selection) {
    return document.createRange();
  }

  return null;
}
<div id="main-input" contenteditable="true">Hello world!</div>
<script type="text/javascript" src="https://code.jquery.com/jquery-2.2.4.min.js"></script>

您可以查看this answer,它显示并解释了获取文本选择的完美方式。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-08-18
    • 1970-01-01
    • 1970-01-01
    • 2013-07-04
    • 2012-10-06
    • 2015-04-25
    • 2020-01-21
    相关资源
    最近更新 更多