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

大家好,
我是开发团队野生队的成员 Mandai。

ZeroClipboard实现了一个功能,即按下按钮即可将默认字符串复制到剪贴板

Zero Clipboard 是一个库,只需安装并加载 JavaScript 和 SWF 文件即可创建复制按钮,我记得它的安装非常容易。

然而,最近我感觉它好像不太对劲,突然意识到
谷歌浏览器默认禁用了 Flash!

并不是说你不能玩Flash游戏。

谷歌浏览器默认禁用Flash,但并非完全忽略它。
只要配置得当,Flash仍然可以正常工作。

简单来说,点击网址栏右侧的三个竖点,选择“设置”,然后点击左上角的汉堡菜单,选择“高级设置”,再选择“隐私和安全
”。Flash 行为设置位于“内容设置”类别下,请根据需要进行调整。

把它放在这样的地方似乎是一种恶意之举,但谷歌认为这样做存在太多安全漏洞,这种说法也合情合理。

虽然目前它还能得到这样的支持,但我认为它未来不会流行起来,所以我希望尽快摆脱 Flash。

 

近年来,JavaScript 的规范已经标准化,API 也得到了改进。

或许是由于 JavaScript 近来流行,浏览器对 JavaScript 的实现正以惊人的速度发展。jQuery
最近经常被诟病会拖慢网站渲染速度,但实际上,现在已经可以勉强使用它了。
我认为它之所以经常被引入,更多是因为 CSS 框架都使用它,而你别无选择。

我们今天要介绍的任务是将字符串复制到剪贴板,这是一个典型的例子,说明以前仅使用 JavaScript 无法完成的事情,现在可以完成了!

 

这时“原生JS”就派上用场了。

好了,介绍就到这里,接下来我想尝试使用纯原生 JavaScript 进行复制到剪贴板的操作。

处理顺序是

  1. 选择要复制的文本
  2. 复制

就这样。

 

选择要复制的文本

选择字符串比复制字符串需要更多步骤,所以一旦你理解了这部分,你就掌握了所有技巧。

与选择文本相关的对象有两个: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
加载中...
1票,平均分:1.00/11
2,279
X Facebook Hatena书签 口袋

这篇文章的作者

关于作者

万代洋一

我的主要工作是开发社交游戏的Web API,但我也很荣幸能够从事其他各种工作,包括市场营销。
我在Beyond中的肖像权采用CC0协议。