如何使用JS库

本篇内容主要讲解“如何使用JS库”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“如何使用JS库”吧!

创新互联秉承实现全网价值营销的理念,以专业定制企业官网,成都做网站、成都网站制作,微信平台小程序开发,网页设计制作,手机网站开发,成都营销网站建设帮助传统企业实现“互联网+”转型升级专业定制企业官网,公司注重人才、技术和管理,汇聚了一批优秀的互联网技术人才,对客户都以感恩的心态奉献自己的专业和所长。

一、clipboard.js 简介

clipboard.js 是一个用于将文本复制到剪贴板的 JS 库。没有使用 Flash,没有使用任何框架,开启  gzipped 压缩后仅仅只有 3kb。

如何使用JS库

那么为什么会有 clipboard.js 这个库呢?因为作者 zenorocha 认为:

  • 将文本复制到剪贴板应该不难。它不需要几十个步骤来配置,也不需要加载数百 KB 的文件。最最重要的是,它不应该依赖于 Flash 或其他任何框架。

该库依赖于 Selection 和 execCommand API,几乎所有的浏览器都支持 Selection API,然而 execCommand  API 却存在一定的兼容性问题:

如何使用JS库
如何使用JS库

当然对于较老的浏览器,clipboard.js 也可以优雅地降级。好的,现在我们来看一下如何使用 clipboard.js。

二、clipboard.js 使用

在使用 clipboard.js 之前,你可以通过 NPM 或 cdn 的方式来安装它:

NPM

npm install clipboard --save

CDN

clipboard.js 使用起来很简单,一般只要 3 个步骤:

1.定义一些标记

 复制

2.引入 clipboard.js

3.实例化 clipboard

以上代码成功运行之后,当你点击 “复制” 按钮时,输入框中的文字会被选中,同时输入框中的文字将会被复制到剪贴板中,对应的效果如下图所示:

如何使用JS库

除了 input 元素之外,复制的目标还可以是 div 或 textarea 元素。在以上示例中,我们复制的目标是通过 data-* 属性  来指定。此外,我们也可以在实例化 clipboard 对象时,设置复制的目标:

// https://github.com/zenorocha/clipboard.js/blob/master/demo/function-target.html let clipboard = new ClipboardJS('.btn', {   target: function() {     return document.querySelector('div');   } });

如果需要设置复制的文本,我们也可以在实例化 clipboard 对象时,设置复制的文本:

// https://github.com/zenorocha/clipboard.js/blob/master/demo/function-text.html let clipboard = new ClipboardJS('.btn', {   text: function() {     return 'to be or not to be';   } });

关于 clipboard.js 的使用,阿宝哥就介绍到这里,感兴趣的小伙伴可以查看 Github 上 clipboard.js 的使用示例。

由于 clipboard.js 底层依赖于 Selection 和 execCommand API,所以在分析 clipboard.js  源码前,我们先来了解一下 Selection 和 execCommand API。

三、Selection 与 execCommand API

3.1 Selection API

Selection  对象表示用户选择的文本范围或插入符号的当前位置。它代表页面中的文本选区,可能横跨多个元素。文本选区由用户拖拽鼠标经过文字而产生。如果要获取用于检查或修改的  Selection 对象,可以调用 window.getSelection 方法。

Selection 对象所对应的是用户所选择的 ranges (区域),俗称 拖蓝。默认情况下,该函数只针对一个区域,我们可以这样使用这个函数:

let selection = window.getSelection(); let range = selection.getRangeAt(0);

以上示例演示了如何获取选区中的第一个区域,其实除了获取选区中的区域之外,我们还可以通过 createRange API  创建一个新的区域,然后将该区域添加到选区中:

大家好,我是阿宝哥。欢迎关注全栈修仙之路
 

以上代码用于选中页面中所有的 strong 元素,但需要注意的是,目前只有使用 Gecko 渲染引擎的浏览器,比如 Firefox  浏览器实现了多个区域。

 如何使用JS库

在某些场景下,你可能需要获取选中区域中的文本。针对这种场景,你可以通过调用 Selection 对象的 toString  方法来获取被选中区域中的纯文本。

3.2 execCommand API

document.execCommand API 允许运行命令来操作网页中的内容,常用的命令有  bold、italic、copy、cut、delete、insertHTML、insertImage、insertText 和 undo 等。下面我们来看一下该  API 的语法:

bool = document.execCommand(aCommandName, aShowDefaultUI, aValueArgument)

相关的参数说明如下:

  • aCommandName:字符串类型,用于表示命令的名称;

  • aShowDefaultUI:布尔类型,用于表示是否展示用户界面,一般为 false;

  • aValueArgument:额外参数,一些命令(比如 insertImage)需要额外的参数(提供插入图片的 URL),默认为 null。

调用 document.execCommand 方法后,该方法会返回一个布尔值。如果是 false 的话,表示操作不被支持或未被启用。对于  clipboard.js 这个库来说,它会通过 document.execCommand API 来执行 copy 和  cut命令,从而实现把内容复制到剪贴板。

那么现在问题来了,我们有没有办法判断当前浏览器是否支持 copy 和cut 命令呢?答案是有的,即使用浏览器提供的 API ——  Document.queryCommandSupported,该方法允许我们确定当前的浏览器是否支持指定的编辑命令。

clipboard.js 这个库的作者,也考虑到了这种需求,所以提供了一个静态的 isSupported  方法,用于检测当前的浏览器是否支持指定的命令:

// src/clipboard.js static isSupported(action = ['copy', 'cut']) {   const actions = (typeof action === 'string') ? [action] : action;   let support = !!document.queryCommandSupported;    actions.forEach((action) => {     support = support && !!document.queryCommandSupported(action);   });    return support; }

Document.queryCommandSupported 兼容性较好,大家可以放心使用,具体的兼容性如下图所示:

如何使用JS库

(图片来源:https://caniuse.com/?search=queryCommandSupported)

介绍完 Selection、execCommand 和 queryCommandSupported API,接下来我们开始分析 clipboard.js  的源码。

四、clipboard.js 源码解析

4.1 Clipboard 类

看源码的时候,阿宝哥习惯从最简单的用法入手,这样可以快速地了解内部的执行流程。下面我们来回顾一下前面的示例:

  复制   

通过观察以上的代码,我们可以快速地找到切入点 —— new ClipboardJS('.btn')。在 clipboard.js 项目内的  webpack.config 配置文件中,我们可以找到 ClipboardJS 的定义:

module.exports = {   entry: './src/clipboard.js',   mode: 'production',   output: {     filename: production ? 'clipboard.min.js' : 'clipboard.js',     path: path.resolve(__dirname, 'dist'),     library: 'ClipboardJS',     globalObject: 'this',     libraryExport: 'default',     libraryTarget: 'umd'   },   // 省略其他配置信息 }

基于以上的配置信息,我们进一步找到了 ClipboardJS 指向的构造函数:

import Emitter from 'tiny-emitter'; import listen from 'good-listener';  class Clipboard extends Emitter {   constructor(trigger, options) {     super();     this.resolveOptions(options);     this.listenClick(trigger);   } }

在示例中,我们并没有设置 Clipboard 的配置信息,所以我们先不用关心 this.resolveOptions(options)  的处理逻辑。顾名思义 listenClick 方法是用来监听 click 事件,该方法的具体实现如下:

listenClick(trigger) {   this.listener = listen(trigger, 'click', (e) => this.onClick(e)); }

在 listenClick 方法内部,会通过一个第三方库 good-listener 来添加事件处理器。当目标触发 click  事件时,就会执行对应的事件处理器,该处理器内部会进一步调用 this.onClick 方法,该方法的实现如下:

// src/clipboard.js onClick(e) {   const trigger = e.delegateTarget || e.currentTarget;    // 为每次点击事件,创建一个新的ClipboardAction对象   if (this.clipboardAction) {     this.clipboardAction = null;   }   this.clipboardAction = new ClipboardAction({     action    : this.action(trigger),     target    : this.target(trigger),     text      : this.text(trigger),     container : this.container,     trigger   : trigger,     emitter   : this   }); }

在 onClick 方法内部,会使用事件触发目标来创建 ClipboardAction对象。当你点击本示例 复制 按钮时,创建的  ClipboardAction 对象如下所示:

如何使用JS库

相信看完上图,大家对创建 ClipboardAction 对象时,所使用到的方法都有了解。那么 this.action、this.target 和  this.text 这几个方法是在哪里定义的呢?通过阅读源码,我们发现在 resolveOptions方法内部会初始化上述 3 个方法:

// src/clipboard.js resolveOptions(options = {}) {   this.action = (typeof options.action === 'function')      ? options.action :  this.defaultAction;   this.target = (typeof options.target === 'function')      ? options.target : this.defaultTarget;   this.text = (typeof options.text === 'function')     ? options.text : this.defaultText;   this.container = (typeof options.container === 'object')        ? options.container : document.body; }

在 resolveOptions 方法内部,如果用户自定义了处理函数,则会优先使用用户自定义的函数,否则将使用 clipboard.js  中对应的默认处理函数。由于我们在调用 Clipboard 构造函数时,并未设置 options 参数,所以将使用默认的处理函数:

如何使用JS库

由上图可知在 defaultAction、defaultTarget 和 defaultText 方法内部都会调用 getAttributeValue  方法来获取事件触发对象上自定义属性,而对应的 getAttributeValue 方法也很简单,具体代码如下:

// src/clipboard.js function getAttributeValue(suffix, element) {   const attribute = `data-clipboard-${suffix}`;   if (!element.hasAttribute(attribute)) {     return;   }   return element.getAttribute(attribute); }

介绍完 Clipboard 类,接下来我们来重点分析一下 ClipboardAction类,该类会包含具体的复制逻辑。

4.2 ClipboardAction 类

在 clipboard.js 项目中,ClipboardAction 类被定义在 src/clipboard-action.js 文件内:

// src/clipboard-action.js class ClipboardAction {   constructor(options) {     this.resolveOptions(options);     this.initSelection();   } }

与 Clipboard 类的构造函数一样,ClipboardAction 类的构造函数会优先解析 options 配置对象,然后调用  initSelection 方法,来初始化选区。在 initSelection 方法中会根据 text 和 target 属性来选择不同的选择策略:

initSelection() {   if (this.text) {     this.selectFake();   } else if (this.target) {     this.selectTarget();   } }

对于前面的示例,我们是通过 data-* 属性 来指定复制的目标,即 data-clipboard-target="#foo",相应的代码如下:

 复制

所以接下来我们先来分析含有 target 属性的情形,如果含有 target属性,则会进入 else if 分支,然后调用  this.selectTarget 方法:

// src/clipboard-action.js selectTarget() {   this.selectedText = select(this.target);   this.copyText(); }

在 selectTarget 方法内部,会调用 select 函数获取已选中的文本,该函数是来自 clipboard.js 作者开发的另一个 npm  包,对应的代码如下:

// https://github.com/zenorocha/select/blob/master/src/select.js function select(element) {   var selectedText;    if (element.nodeName === 'SELECT') {     element.focus();     selectedText = element.value;   }   else if (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA') {     var isReadOnly = element.hasAttribute('readonly');      if (!isReadOnly) {       element.setAttribute('readonly', '');     }      element.select();     element.setSelectionRange(0, element.value.length);      if (!isReadOnly) {       element.removeAttribute('readonly');     }        selectedText = element.value;     }   else {     // 省略相关代码    }   return selectedText; }

因为在以上示例中,我们复制的目标是 input 元素,所以我们先来分析该分支的代码。在该分支中,使用了 HTMLInputElement 对象的  select 和 setSelectionRange 方法:

  • select:用于选中一个