鼠标一键点击实现页面文本全选和复制

需求背景

有些页面上的数据用户常常须要全选而后进行复制的工做,用户通常须要两步操做,第一步是选中文本,用户能够经过三次点击或着点击后拖动鼠标来进行选中,第二步则是点击右键选择复制,或者利用键盘快捷键。为了提升用户体验,咱们想要让用户点击相关文字时候,自动全选而且完成复制操做。javascript

自动全选.gif

1. 文本全选实现方案

1.1 利用CSS user-select 属性

CSS属性 user-select 控制用户可否选中文本css

auto | text | none | contain | allhtml

contain 在不少浏览器中例如Chrome中时不支持的,在这里咱们用 user-selet: all 就可以实现文本全选的功能。vue

优点: 能够很是灵活,并且十分简单,一个语句就可完成功能。java

不足: 做为优化需求的时候,须要修改原有代码。也就是若是要在原来的已经写好的页面中加入此功能,须要找到每个具体的位置,而后添加对应的className或者增长css的行间样式。node

1.2 利用Javascript光标对象selection

selection 表明了当前激活选中区,即高亮文本块,和/或文档中用户可执行某些操做的其它元素。正则表达式

export default () => {
  // 监听鼠标的click事件
  document.addEventListener('click', (e: Event) => {
    // 获取到鼠标点击的dom元素
    const span = e.target;
    // 获取dom元素中的的innerText的值
    const value = (span as HTMLElement).innerText;
    // 遍历全部配置的正则表达式
    for (const reg of Object.values(regObject)) {
      if (reg.test(value)) {
        // 验证经过了正则的值是不是span元素或者是div元素,由于不想在输入框也有此功能
        if ((span as HTMLElement).localName === ('span' || 'div')) {
          // 获取一个Selection对象
          const selection = window.getSelection();
          // 先清空一下以选择的内容
          selection?.removeAllRanges();
          // 建立一个range对象
          const range = document.createRange();
          // 让range对象包含一个node的内容
          range.selectNodeContents(span as HTMLElement);
          // 向selection中添加一个区域(range)
          selection?.addRange(range);
        }
      }
    }
  });
};
复制代码

技术方案实现的思路:api

  1. 监听鼠标click事件
  2. 定义文本的正则匹配规则,例如此需求中是为了全选Location ID,正则为/^[A-Z]{3}-[A-Z](-[0-9]{1,2})+$/, 此正则表达式用到的符号的意思为:

^ 表示(脱字符)匹配开头,在多行匹配中匹配行开头
[A-Z] 等价于全部大写字母
{m} 等价于{m,m},表示出现m次
[0-9] 等价于全部数字
{1,2} 等价于前面的内容出现一到两次
+等价于{1,},表示出现至少一次
$(美圆符号)匹配结尾,在多行匹配中匹配行结尾浏览器

  1. 若是文本经过正则校验,那么再判断元素的类型,此例子中只但愿获取div和span元素中的文本,因此利用了 localName 这个属性来判断元素类型了
  2. 一系列校验完成后,咱们获取 selection 对象,利用 removeAllRanges 清空一下内容(至关于初始化
  3. 再经过 createRange 获取range对象,利用 range 对象的 selectNodeContents 来获取范围
  4. 最后使用 addRange 来让文本信息高光

优点: 能够在App.vue入口文件一次添加,不须要修改原有代码markdown

不足: 所须要高亮的数据须要有必定的结构特色,好比数据须要有必定的规则。还有就是全局添加click的监听事件,会增长一点性能消耗

文本全选实现方案总结

两种方案都有优缺点,须要结合具体的场景,需求来选取合适的方案,本文也只是提供一种思路的参考。

2. 自动触发复制的实现方案

实现自动将内容复制到剪贴板中有三种方法:

  • Document.execCommand()方法
  • 异步的 Clipboard API
  • copy事件和paste事件

2.1 Document.execCommand()方法

Document.execCommand() 是操做剪贴板的传统方法,各类浏览器都支持。

它支持复制、剪切和粘贴这三个操做。

document.execCommand('copy')(复制)
document.execCommand('cut')(剪切)
document.execCommand('paste')(粘贴)

Document.execCommand() 方法的缺点是只能复制高亮文本的内容,不能够自定义信息放入剪贴板中, 并且这种方式只支持同步操做。可是对于咱们这个需求,这种方式已经足够了。

2.2 异步的 Clipboard API

Clipboard 对象的全部操做都是异步的,返回 Promise 对象,不会形成页面卡顿。

const clipboardObj = navigator.clipboard;

并且,它能够将任意内容(好比图片)放入剪贴板。拥有如下4个方法:

Clipboard.readText() 方法用于复制剪贴板里面的文本数据。
Clipboard.read() 方法用于复制剪贴板里面的数据,能够是文本数据,也能够是二进制数据
Clipboard.writeText()方法用于将文本内容写入剪贴板
Clipboard.write()方法用于将任意数据写入剪贴板,能够是文本数据,也能够是二进制数据

这样的操做更加灵活,高效。可是缺点是 Chrome 浏览器规定,只有 HTTPS 协议的页面才能使用这个 API, 而咱们这个项目不是这种协议的,因此没法使用此 API。

2.3 copy事件

此方法须要首先利用2.1中的document.execCommand('copy')方法触发一个复制操做,而后利用监听copy进行处理。

document.addEventListener('copy', async (e) => {
      e.preventDefault();
      try {
        let clipText = ''
        ...
        // 将自定义的内容放入剪贴板中 
        e.clipboardData.setData('text/plain', clipText)
      } catch (err) {
        console.log(err);
      }
   });
复制代码

此需求并非这种方法的应用场景,此方法的应用场景以下:

当你但愿自定义放入一些内容在剪贴板中,可是你的项目又并非 HTTPS 的协议,就只有使用这种方法了。但须要注意一点, 因为 2.1 Document.execCommand()方法 是只支持同步的,因此若是在异步操做里面调用是没有用的,那么若是你想放入剪贴板中的内容是须要异步请求的,再请求以后想要直接调用复制操做的话就会失效。举代码例子:

async getData () {
  try {
    await this.getClipboardData();
    // 这里的复制操做触发是无效的
    document.execCommand("Copy")
  }
}
复制代码

因此交互需变成,先保存异步回来的数据,等数据回来之后,再经过一个按钮或其余方式,同步出发复制操做。

自动复制.gif

自动触发复制的实现方案总结

三种方式都有其适合的应用场景,但第三种 copy 事件的方式会污染真正的复制操做,仍是不太建议使用,只能算是一种兜底的方案。

引用

剪贴板操做 Clipboard API 教程
MDN: user-select
MDN: Selection
MDN: Document.createRange()
JS正则表达式完整教程
javascript实现鼠标点击自动选中点击元素内的文字

相关文章
相关标签/搜索