如何使用 vanilla Javascript 保存和恢复浏览器选择?
How to save and restore the browser selection with vanilla Javascript?
我使用的库使用隐藏的输入元素作为副作用。这会导致浏览器选择在激活时丢失。如何保存当前选择并在(同步)操作完成后恢复它?如果可能的话,我想知道如何在 vanilla Javascript 中做到这一点。
// how to save the selection?
doSomethingThatUsesHiddenInput() // removes the selection
// how to restore the selection?
您可以使用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)
}
您可以使用 getSelection
to get a Selection
对象,它包含 selected 内容的范围。大多数浏览器仅支持用户与页面交互创建的 selection 中的单个范围(如果以编程方式完成,则为多个),但基于 Gecko 的浏览器(如 Firefox)允许用户通过按住 Ctrl 的同时创建多个范围 selecting,或按住 Ctrl 键并单击 table 单元格以 select 它们。
节省:
const selection = window.getSelection();
const savedRanges = [];
for (let i = 0; i < selection.rangeCount; ++i) {
savedRanges.push(selection.getRangeAt(i));
}
正在恢复:
不幸的是,当您使用 Ctrl 键单击 select table 单元格 和 然后按住 Ctrl 键至 select 时,Firefox 会出现奇怪的行为文本也是其他元素。我们必须解决这个问题,首先恢复 table 单元格(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>
我使用的库使用隐藏的输入元素作为副作用。这会导致浏览器选择在激活时丢失。如何保存当前选择并在(同步)操作完成后恢复它?如果可能的话,我想知道如何在 vanilla Javascript 中做到这一点。
// how to save the selection?
doSomethingThatUsesHiddenInput() // removes the selection
// how to restore the selection?
您可以使用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)
}
您可以使用 getSelection
to get a Selection
对象,它包含 selected 内容的范围。大多数浏览器仅支持用户与页面交互创建的 selection 中的单个范围(如果以编程方式完成,则为多个),但基于 Gecko 的浏览器(如 Firefox)允许用户通过按住 Ctrl 的同时创建多个范围 selecting,或按住 Ctrl 键并单击 table 单元格以 select 它们。
节省:
const selection = window.getSelection();
const savedRanges = [];
for (let i = 0; i < selection.rangeCount; ++i) {
savedRanges.push(selection.getRangeAt(i));
}
正在恢复:
不幸的是,当您使用 Ctrl 键单击 select table 单元格 和 然后按住 Ctrl 键至 select 时,Firefox 会出现奇怪的行为文本也是其他元素。我们必须解决这个问题,首先恢复 table 单元格(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>