选择:通过单击所选文本取消选择的 isCollapsed 值不正确

Selection: incorrect isCollapsed value for deselecting by clicking on selected text

问题

我需要根据鼠标事件检测选定的文本。我还需要检测当前选择何时消失。我的下一个代码适用于您选择某些内容并通过在选择之外单击取消选择的情况。但是当您想通过单击所选文本来取消选择时,此代码不起作用。

请测试下一个代码以了解我的意思。

环境

如何重现

  1. 打开带有一些文本的页面(文本应表示为文本节点)。
  2. 将此代码粘贴到控制台:
let mousePressed = false;

document.addEventListener('mousedown', () => {
    mousePressed = true;
});

document.addEventListener('mouseup', () => {
    if (mousePressed) {
        const selection = window.getSelection();
        const isCollapsed = selection.isCollapsed;

        console.log(`Collapsed: ${isCollapsed}`);

        mousePressed = false;
    }
});
  1. 左键双击某个单词。您将看到此折叠序列:falsetrue.
  2. 在所选词外单击鼠标左键(例如,单击页面背景)。您将看到此折叠序列:true。实际选择将消失。
  3. 同 № 3.
  4. 左键单击所选单词。您将看到此折叠序列:false。但实际选择会消失。

发生了什么

注意 № 4 和 № 6 之间的区别。两者都会导致相同的结果:选择将消失。但有一个区别:№ 4 将正确指向该选择已折叠,但 № 6 会将消失的选择视为未折叠。这意味着 window.getSelection() 将提供消失的选择,即使没有实际可见的选择。

两种浏览器都会发生这种情况:Google Chrome 和 Mozilla Firefox。

如何测试错误的事件顺序

使用稍微不同的代码执行所有这些步骤:

let mousePressed = false;

document.addEventListener('mousedown', () => {
    mousePressed = true;
});

document.addEventListener('mouseup', () => {
    if (mousePressed) {
        window.setTimeout(() => {
            const selection = window.getSelection();
            const isCollapsed = selection.isCollapsed;

            console.log(`Collapsed: ${isCollapsed}`);
        }, 1000);

        mousePressed = false;
    }
});

一样,只是现在window.getSelection()会延迟调用。现在 № 6 产生预期结果:true.

为什么会这样

我不知道。我认为不同情况下的事件顺序有所不同。对于第 4 种情况,订单会产生预期的结果。对于第 6 种情况,事件的顺序可能不同,并且该顺序不会产生预期的结果。

我要的是什么

我的代码有问题吗?或者这是应该在 Chromium 和 Bugzilla 上报告的错误?或者这实际上是预期的行为?

我的意思是,我需要为 № 4 和 № 6 获得相同的结果 (Collapsed: true)。

使用此模式解决了问题:

let mousePressed = false;

document.addEventListener('mousedown', () => {
    mousePressed = true;
});

document.addEventListener('mouseup', () => {
    if (mousePressed) {
        window.setTimeout(() => {
            const selection = window.getSelection();
            const isCollapsed = selection.isCollapsed;

            console.log(`Collapsed: ${isCollapsed}`);
        }, 0);

        mousePressed = false;
    }
});

即延迟为 0 毫秒的计时器。

现在 № 4 和 № 6 都被正确处理了。

但我仍然不确定处理这种情况是否正确。也许代码有问题,也许两个浏览器都有错误。