【问题标题】:How to save and restore the browser selection with vanilla Javascript?如何使用 vanilla Javascript 保存和恢复浏览器选择?
【发布时间】:2021-11-07 03:06:42
【问题描述】:

我正在使用一个库,它使用隐藏的输入元素作为副作用。这会导致浏览器选择在激活时丢失。如何保存当前选择并在(同步)操作完成后恢复它?如果可能的话,我想知道如何在 vanilla Javascript 中做到这一点。

// how to save the selection?

doSomethingThatUsesHiddenInput() // removes the selection

// how to restore the selection?

【问题讨论】:

标签: javascript selection


【解决方案1】:

您可以使用getSelection 获取Selection 对象,其中包含所选内容的范围。大多数浏览器仅支持用户与页面交互创建的选择中的单个范围(如果以编程方式完成,则为多个),但基于 Gecko 的浏览器(如 Firefox)允许用户通过在选择时按住 Ctrl 或通过按住 Ctrl 单击来创建多个范围表格单元格以选择它们。

保存:

const selection = window.getSelection();
const savedRanges = [];
for (let i = 0; i < selection.rangeCount; ++i) {
    savedRanges.push(selection.getRangeAt(i));
}

恢复:

不幸的是,当您使用 Ctrl 键单击选择表格单元格 然后按住 Ctrl 键选择文本以及其他元素时,Firefox 会出现奇怪的行为。我们必须通过先恢复表格单元格(startContainer.nodeName"TR"),然后再恢复其他单元格来解决这个问题,以使这项工作在 Firefox 上可靠运行;见下文。

const selection = window.getSelection();
selection.removeAllRanges();
for (const range of savedRanges.filter(({startContainer: {nodeName}}) => nodeName === "TR")) {
    selection.addRange(range);
}
for (const range of savedRanges.filter(({startContainer: {nodeName}}) => nodeName !== "TR")) {
    selection.addRange(range);
}

现场示例:

const plural = (singular, plural) =>
    (number) =>
        `${number} ${number === 1 ? singular : plural}`;
const ranges = plural("range", "ranges");

document.querySelector(".hover").addEventListener("mouseenter", function() {
    // Save selection
    console.log(`Saving selection...`);
    const selection = window.getSelection();
    const savedRanges = [];
    for (let i = 0; i < selection.rangeCount; ++i) {
        savedRanges.push(selection.getRangeAt(i));
    }
    
    // Remove it and report
    selection.removeAllRanges();
    console.log(`${ranges(savedRanges.length)} saved and removed.`);
    
    // Restore it after a moment
    setTimeout(() => {
        console.log(`Restoring ${ranges(savedRanges.length)}...`);
        const selection = window.getSelection();
        selection.removeAllRanges();
        // To support unusual Firefox behavior around a mix of selections
        // inside and outside tables, restore ranges whose start container
        // is TR first, then others
        for (const range of savedRanges.filter(({startContainer: {nodeName}}) => nodeName === "TR")) {
            selection.addRange(range);
        }
        for (const range of savedRanges.filter(({startContainer: {nodeName}}) => nodeName !== "TR")) {
            selection.addRange(range);
        }
        console.log(`Done`);
    }, 800);
});
.hover {
    display: inline-block;
    border: 1px solid black;
    padding: 4px;
}
<p>
Select text in the document, then move your mouse over the <strong>Hover to Run</strong> box below but <strong>don't</strong> click it (because that would remove your selection). The action will happen when your mouse enters the <strong>Hover to Run</strong> area. On Firefox, try doing multiple selections by holding down Ctrl when selecting, or by Ctrl-clicking table cells.
</p>
<table>
    <thead>
        <tr>
            <th>Column 1</th>
            <th>Column 2</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>One</td>
            <td>two</td>
        </tr>
        <tr>
            <td>three</td>
            <td>four</td>
        </tr>
        <tr>
            <td>five</td>
            <td>six</td>
        </tr>
    </tbody>
</table>
<div class="hover">Hover to Run</div>

【讨论】:

    【解决方案2】:

    您可以使用Browser Selection API 并恢复选择范围:

    // save the selection
    const sel = window.getSelection()
    const range = sel?.rangeCount > 0 ? sel?.getRangeAt(0) : null
    
    doSomethingThatUsesHiddenInput() // removes the selection
    
    // restore the selection
    if (range) {
      sel?.removeAllRanges()
      sel?.addRange(range)
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-05-09
      • 2017-01-26
      • 1970-01-01
      • 2021-05-07
      • 2012-02-27
      • 2011-05-22
      • 1970-01-01
      相关资源
      最近更新 更多