繁体   English   中英

如何使用 vanilla Javascript 保存和恢复浏览器选择?

[英]How to save and restore the browser selection with vanilla Javascript?

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

// how to save the selection?

doSomethingThatUsesHiddenInput() // removes the selection

// how to restore the selection?

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

保存:

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

恢复:

不幸的是,当您使用 Ctrl 键单击 select 表格单元格然后按住 Ctrl 键到 select 文本也是其他元素时,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>

您可以使用浏览器选择 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)
}

上述保存选区的方式在后退时(当“焦点”position在“锚点”位置之前)时,将无法正确恢复选区。 下面解决这个问题。

function saveSelection() {
    selection = window.getSelection();
    return [selection.anchorNode, selection.anchorOffset, selection.focusNode, selection.focusOffset];
}

function restoreSelection(saved) {
    selection = window.getSelection();
    selection.setBaseAndExtent(saved[0], saved[1], saved[2], saved[3]);
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM