copy-to-clipboard 源码解析,隐藏的内容比想象的要多

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介: copy-to-clipboard 是一个 js 的剪切板库,可用来复制内容到剪切板,看源码后发现其中隐藏的内容着实不少,今天一起来解读下其源码。

网络异常,图片无法展示
|

本文针对的源码版本为:193826f

copy-to-clipboard 是一个 js 的剪切板库,可用来复制内容到剪切板,看源码后发现其中隐藏的内容着实不少,今天一起来解读下其源码。

使用方式

我们先看下使用方式:

import copy from 'copy-to-clipboard';
copy('Text');
// Copy with options
copy('Text', {
    debug: true,
    message: 'Press #{key} to copy'
});
复制代码

可以看到 API 非常简单。

该库只抛出一个 copy 函数,函数接口为:copy(text: string, options: object): boolean。

第一个参数为一个文本值为用来复制的内容。

options 包含 4 个参数:

  • debug - 是否开启调试模式,开启后会将复制信息打印到 console 中
  • message - 通过 prompt 模式兼容时的提示信息
  • format - 设置复制内容的 mime type
  • onCopy - 复制后的回调,接口为:function onCopy(clipboardData: object): void

源码解读

该库源码比较简单,其中使用到了一个依赖库:toggle-selection,作用是取消和恢复当前选中的文本的选中状态。

主体方案

先看看主体部分:

reselectPrevious = deselectCurrent();
range = document.createRange();
selection = document.getSelection();
mark = document.createElement('span');
mark.textContent = text;
// ...
mark.addEventListener('copy', function (e) {
    // ...
});
document.body.appendChild(mark);
range.selectNodeContents(mark);
selection.addRange(range);
var successful = document.execCommand('copy');
if (!successful) {
    throw new Error('copy command was unsuccessful');
}
success = true;
复制代码

这部分首先取消了当前页面中已有的选择状态,然后创建了一个 range,range 可用来包含文本或节点片段。随后通过 getSelection 获得了一个 Selection 对象,该对象包含当前用户选中的或鼠标所在的内容。

然后它创建了一个 span 元素,将要复制的内容设置为该元素的文本,然后通过各种样式设置等,主要是为了避免该元素被发现、被读取、无法复制等问题。随后它在该元素中添加了 copy 事件,将元素添加到 body,然后通过 range.selectNodeContents 和 selection.addRange 选中该元素,并通过 document.execCommand 调用 copy 命令即可将选中的内容进行复制。

下面再看一下 copy 事件的处理:

e.stopPropagation();
if (options.format) {
    e.preventDefault();
    if (typeof e.clipboardData === 'undefined') {
        // IE 11
        debug && console.warn('unable to use e.clipboardData');
        debug && console.warn('trying IE specific stuff');
        window.clipboardData.clearData();
        var format = clipboardToIE11Formatting[options.format] || clipboardToIE11Formatting['default'];
        window.clipboardData.setData(format, text);
    } else {
        // all other browsers
        e.clipboardData.clearData();
        e.clipboardData.setData(options.format, text);
    }
}
if (options.onCopy) {
    e.preventDefault();
    options.onCopy(e.clipboardData);
}
复制代码

主要是分两部分,一部分是当存在自定义 format 时会组织默认的复制行为,然后通过 clipboardData.setData 重新设置内容格式,其中包含一部分 IE 兼容的代码。第二部分则是调用 onCopy 回调,这里要注意,使用 onCopy 后它会阻止默认事件,此时你需要自己将内容设置到剪切板中。

兼容方案

在上述使用 execCommand 报错后,它会尝试使用 clipboardData 做第二次尝试,这个主要是针对 IE 所做的兼容:

window.clipboardData.setData(options.format || 'text', text);
options.onCopy && options.onCopy(window.clipboardData);
success = true;
复制代码

如果该方案依旧失败,则会降级到终极方案 - prompt:

message = format('message' in options ? options.message : defaultMessage);
window.prompt(message, text);
复制代码

其中 format 主要是为了让 prompt 框的提示信息中的 ctrl 在 mac 中替换为 command。

在老浏览器中 prompt 会弹出弹窗,内容区域显示要复制的信息,然后提示区域提示用户 ctrl+c 复制。

收尾

复制完成后,它会将之前的 selection、range 和 mark 进行清理,并通过 reselectPrevious 恢复之前的选择状态。

if (selection) {
    if (typeof selection.removeRange == 'function') {
        selection.removeRange(range);
    } else {
        selection.removeAllRanges();
    }
}
if (mark) {
    document.body.removeChild(mark);
}
reselectPrevious();
复制代码

兼容性

该库兼容几乎所有的主流浏览器版本,包括 IE,因为 execCommand 虽然被废弃,但是兼容性很高,然后它还使用了 clipboardData 做 IE 兼容,并且使用了 prompt 做降级方案。

不过文档中提示在一些老的 IOS 设备中,由于无法定制 prompt 内容,所以无法兼容。

总结

该库虽然源码很简短,但是用到了相当多平时编程中很少甚至不会用到的 API,如:

  • Range
  • Selection
  • execCommand
  • clipboardData
  • style.all
  • style.clip

不过代码依然有优化的空间,如大量引用 mark.style 处可创建引用、随处可见的 debug 可做成预处理函数、兼容方案中 onCopy 行为不一致等。

相关文章
|
3月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
124 2
|
2月前
|
设计模式 存储 安全
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
创建型模式的主要关注点是“怎样创建对象?”,它的主要特点是"将对象的创建与使用分离”。这样可以降低系统的耦合度,使用者不需要关注对象的创建细节。创建型模式分为5种:单例模式、工厂方法模式抽象工厂式、原型模式、建造者模式。
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
|
2月前
|
存储 设计模式 算法
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。行为型模式分为类行为模式和对象行为模式,前者采用继承机制来在类间分派行为,后者采用组合或聚合在对象间分配行为。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象行为模式比类行为模式具有更大的灵活性。 行为型模式分为: • 模板方法模式 • 策略模式 • 命令模式 • 职责链模式 • 状态模式 • 观察者模式 • 中介者模式 • 迭代器模式 • 访问者模式 • 备忘录模式 • 解释器模式
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
|
2月前
|
设计模式 存储 安全
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
结构型模式描述如何将类或对象按某种布局组成更大的结构。它分为类结构型模式和对象结构型模式,前者采用继承机制来组织接口和类,后者釆用组合或聚合来组合对象。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象结构型模式比类结构型模式具有更大的灵活性。 结构型模式分为以下 7 种: • 代理模式 • 适配器模式 • 装饰者模式 • 桥接模式 • 外观模式 • 组合模式 • 享元模式
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
|
21天前
|
自然语言处理 数据处理 索引
mindspeed-llm源码解析(一)preprocess_data
mindspeed-llm是昇腾模型套件代码仓,原来叫"modelLink"。这篇文章带大家阅读一下数据处理脚本preprocess_data.py(基于1.0.0分支),数据处理是模型训练的第一步,经常会用到。
40 0
|
3月前
|
缓存 监控 Java
Java线程池提交任务流程底层源码与源码解析
【11月更文挑战第30天】嘿,各位技术爱好者们,今天咱们来聊聊Java线程池提交任务的底层源码与源码解析。作为一个资深的Java开发者,我相信你一定对线程池并不陌生。线程池作为并发编程中的一大利器,其重要性不言而喻。今天,我将以对话的方式,带你一步步深入线程池的奥秘,从概述到功能点,再到背景和业务点,最后到底层原理和示例,让你对线程池有一个全新的认识。
72 12
|
2月前
|
PyTorch Shell API
Ascend Extension for PyTorch的源码解析
本文介绍了Ascend对PyTorch代码的适配过程,包括源码下载、编译步骤及常见问题,详细解析了torch-npu编译后的文件结构和三种实现昇腾NPU算子调用的方式:通过torch的register方式、定义算子方式和API重定向映射方式。这对于开发者理解和使用Ascend平台上的PyTorch具有重要指导意义。
|
2月前
|
安全 搜索推荐 数据挖掘
陪玩系统源码开发流程解析,成品陪玩系统源码的优点
我们自主开发的多客陪玩系统源码,整合了市面上主流陪玩APP功能,支持二次开发。该系统适用于线上游戏陪玩、语音视频聊天、心理咨询等场景,提供用户注册管理、陪玩者资料库、预约匹配、实时通讯、支付结算、安全隐私保护、客户服务及数据分析等功能,打造综合性社交平台。随着互联网技术发展,陪玩系统正成为游戏爱好者的新宠,改变游戏体验并带来新的商业模式。
|
3月前
|
存储 安全 Linux
Golang的GMP调度模型与源码解析
【11月更文挑战第11天】GMP 调度模型是 Go 语言运行时系统的核心部分,用于高效管理和调度大量协程(goroutine)。它通过少量的操作系统线程(M)和逻辑处理器(P)来调度大量的轻量级协程(G),从而实现高性能的并发处理。GMP 模型通过本地队列和全局队列来减少锁竞争,提高调度效率。在 Go 源码中,`runtime.h` 文件定义了关键数据结构,`schedule()` 和 `findrunnable()` 函数实现了核心调度逻辑。通过深入研究 GMP 模型,可以更好地理解 Go 语言的并发机制。
|
3月前
|
消息中间件 缓存 安全
Future与FutureTask源码解析,接口阻塞问题及解决方案
【11月更文挑战第5天】在Java开发中,多线程编程是提高系统并发性能和资源利用率的重要手段。然而,多线程编程也带来了诸如线程安全、死锁、接口阻塞等一系列复杂问题。本文将深度剖析多线程优化技巧、Future与FutureTask的源码、接口阻塞问题及解决方案,并通过具体业务场景和Java代码示例进行实战演示。
75 3

推荐镜像

更多