使用原生 JavaScript 实现一键选择并复制范围的功能

大家好,
我是开发团队野生队的成员 Mandai。
ZeroClipboard实现了一个功能,即按下按钮即可将默认字符串复制到剪贴板
Zero Clipboard 是一个库,只需安装并加载 JavaScript 和 SWF 文件即可创建复制按钮,我记得它的安装非常容易。
然而,最近我感觉它好像不太对劲,突然意识到
谷歌浏览器默认禁用了 Flash!
并不是说你不能玩Flash游戏。
谷歌浏览器默认禁用Flash,但并非完全忽略它。
只要配置得当,Flash仍然可以正常工作。
简单来说,点击网址栏右侧的三个竖点,选择“设置”,然后点击左上角的汉堡菜单,选择“高级设置”,再选择“隐私和安全
”。Flash 行为设置位于“内容设置”类别下,请根据需要进行调整。
把它放在这样的地方似乎是一种恶意之举,但谷歌认为这样做存在太多安全漏洞,这种说法也合情合理。
虽然目前它还能得到这样的支持,但我认为它未来不会流行起来,所以我希望尽快摆脱 Flash。
近年来,JavaScript 的规范已经标准化,API 也得到了改进。
或许是由于 JavaScript 近来流行,浏览器对 JavaScript 的实现正以惊人的速度发展。jQuery
最近经常被诟病会拖慢网站渲染速度,但实际上,现在已经可以勉强使用它了。
我认为它之所以经常被引入,更多是因为 CSS 框架都使用它,而你别无选择。
我们今天要介绍的任务是将字符串复制到剪贴板,这是一个典型的例子,说明以前仅使用 JavaScript 无法完成的事情,现在可以完成了!
这时“原生JS”就派上用场了。
好了,介绍就到这里,接下来我想尝试使用纯原生 JavaScript 进行复制到剪贴板的操作。
处理顺序是
- 选择要复制的文本
- 复制
就这样。
选择要复制的文本
选择字符串比复制字符串需要更多步骤,所以一旦你理解了这部分,你就掌握了所有技巧。
与选择文本相关的对象有两个:Range 对象和 Selection 对象。
Range 对象是一个存储信息的对象,用于指示页面上的哪个区域被选中。Selection
对象是一个管理 Range 对象并包含一个或多个 Range 对象的对象。
由于是 Range 对象选择文本,因此可以通过从 Selection 对象中提取 Range 对象或创建一个新的 Range 对象来获得 Range 对象。
// 创建一个新的 Range 对象 var range = document.createRange(); // 从 Selection 对象获取 Range 对象 var selection = window.getSelection(); var range = selection.getRangeAt(0);
无论使用哪种方法,范围变量的内容都将是同一个 Range 对象,因此您可以随意准备 Range 对象。
这次,我们将尝试使用从 Selection 对象中提取的 Range 对象来实现它。
假设包含您要复制的字符串的标签如下所示:
<div id="hoge">要复制的字符串</div>
使用 getElementById() 方法获取 DOM。
var hoge = document.getElementById('hoge');
接下来,指定选择范围。
有两种方法可以指定。如果要复制 DOM 元素的全部内容,请使用 Range 对象的 selectNodeContents() 方法。
range.selectNodeContents(hoge);
此外,如果您只想复制 DOM 元素的一部分,可以使用 Range 对象的 setStart() 方法指定起始点,使用 setEnd() 方法指定结束点。
需要注意的是,如果您只想复制 DOM 的一部分,直接将使用 getElementById() 方法获取的 DOM 传递给 setStart() 和 setEnd() 方法通常会导致错误,因此您需要从 DOM 中提取字符串节点并将其传递给 setStart() 和 setEnd() 方法。
range.setStart(hoge, 7); range.setEnd(hoge, 15); // 发生错误 // Uncaught IndexSizeError: Failed to execute 'setStart' on 'Range': There is no child at offset 7.
此错误中的 IndexSize 指的是 hoge 对象中 DOM 数组的索引,它指出没有第七个节点。我们原本以为传递的是一个字符串,并从第七个字符开始计数,但显然存在误解。
因此,你需要将hoge对象中包含的文本节点作为第一个参数传递给setStart()和setEnd()方法。获取文本节点的标准方法是通过firstChild属性。
var hoge = document.getElementById('hoge'); var hogeTextNode = hoge.firstChild; range.setStart(hogeTextNode, 7); range.setEnd(hogeTextNode, 15);
指定选择范围后,剩下的就是选择它,但这里也存在一个陷阱。
要选择对象,只需使用 addRange() 方法将指定选择范围的 Range 对象添加到 Selection 对象即可。
selection.addRange(range); // 发生错误 // 不支持不连续选择。.
您说不支持不连续选择,但是不连续是什么意思呢?
在这个例子中,Range 对象是从 Selection 对象中提取出来的,这就是上述错误的含义。
Selection 对象已经有一个 Range 对象,因此使用 addRange() 方法添加一个 Range 对象将导致有两个 Range 对象,这就是错误所指示的不连续 Selection 状态。
由于我们要将后来添加的 Range 对象指定为选择范围,因此最快的方法是删除 Selection 对象最初拥有的 Range 对象,然后添加一个 Range 对象,使其只剩下一个 Range 对象。
selection.removeAllRanges(); // 正如方法名称所示,移除所有 Range 对象 selection.addRange(range);
这将选中文本。
总而言之,选中屏幕上文本的代码如下:
// 从 Selection 对象中获取 Range 对象 var selection = window.getSelection(); var range = selection.getRangeAt(0); var textNode = document.getElementById('hoge').firstChild; // 选择 DOM 中的所有文本 range.selectNodeContents(textNode); // 使用 selectNodeContents() 方法,无需提取文本节点 // 仅选择 DOM 的一部分 range.setStart(textNode, 7); range.setEnd(textNode, 15); // 通过 Selection 对象进行选择 selection.removeAllRanges(); selection.addRange(range);
将字符串复制到剪贴板
要对选定的字符串执行“Ctrl + C”,请使用下面的 execCommand() 方法。
document.execCommand('copy');
现在选定的文本已经复制到剪贴板,您只需在任何位置按 Ctrl + V 即可。
概括
我在选择字符串方面花了不少篇幅,但你觉得怎么样?
Stack Overflow 和其他地方有一些相关的文章,但理解所需的信息并不完整,所以我不知道为什么会出现错误,也不太习惯在 JavaScript 中使用剪贴板。但如果你能理解错误背后的逻辑,那就没什么可怕的了,对吧?
就这样。
1