返回

从 clipboard.js 核心代码一窥浏览器复制功能的秘密

前端

当我们谈论如何在浏览器中实现文本复制功能时,首先需要了解的是,浏览器本身就提供了一些 API 可以帮助我们实现这个功能。其中最常用的 API 就是 document.execCommand('copy')。这个 API 可以让浏览器复制选定的文本到剪贴板。

clipboard.js 就是一个基于这个 API 的库,它提供了更简单、更方便的方法来复制文本。我们只需要在需要复制文本的元素上添加一个 data-clipboard-text 属性,然后调用 clipboard.js 的方法,就可以轻松地复制文本。

为了更好地理解 clipboard.js 的工作原理,我们来看一下它的核心代码:

(function (root, factory) {
  if (typeof define === 'function' && define.amd) {
    define(['exports'], factory);
  } else if (typeof exports !== 'undefined') {
    factory(exports);
  } else {
    root.ClipboardJS = factory({});
  }
}(this, function (exports) {
  var ClipboardJS = function (target, options) {
    if (!target) {
      throw new Error('Target required');
    }

    this.target = target;
    this.text = target.getAttribute('data-clipboard-text');

    this.options = Object.assign({}, ClipboardJS.defaults, options);
    this.handlers = [];

    this._bindClick();
  };

  ClipboardJS.defaults = {
    container: document.body,
    trigger: 'click',
    text: null,
    html: null,
    target: null,
    action: null,
    emitter: null,
    template: '<button type="button" class="btn btn-primary" data-clipboard-action="copy" title="Copy to clipboard">{text}</button>'
  };

  ClipboardJS.prototype.bind = function () {
    var that = this;
    this.handlers = [];
    this._bindClick();
  };

  ClipboardJS.prototype._bindClick = function () {
    var that = this;

    this.handlers.push(
      addEventListener(this.target, this.options.trigger, function (e) {
        that.selectTarget();
        that._copyText();
        e.preventDefault();
      })
    );
  };

  ClipboardJS.prototype._copyText = function () {
    var that = this;
    var selectedText = window.getSelection().toString();
    var success = false;

    if (!this.options.text && !this.options.html) {
      this.options.text = this.target.getAttribute('data-clipboard-text');
    }

    if (this.options.text) {
      success = _copyToClipboard(this.options.text);
    } else if (this.options.html) {
      success = _copyToClipboard(this.options.html);
    } else if (selectedText) {
      success = _copyToClipboard(selectedText);
    }

    if (success) {
      this.emit('success');
    } else {
      this.emit('error');
    }

    document.body.removeEventListener('keydown', this._keydown);
  };

  function _copyToClipboard(text) {
    var tempElem = document.createElement('textarea');
    tempElem.style.position = 'absolute';
    tempElem.style.left = '-99999px';
    tempElem.style.top = '-99999px';
    tempElem.value = text;
    document.body.appendChild(tempElem);
    tempElem.select();
    var success = document.execCommand('copy');
    document.body.removeChild(tempElem);
    return success;
  }

  ClipboardJS.prototype.remove = function () {
    var handler;
    while (handler = this.handlers.shift()) {
      handler.removeEventListener();
    }
  };

  ClipboardJS.prototype.emit = function (type) {
    var handler;

    if (typeof type !== 'string') {
      throw new Error('Type must be a string');
    }

    type = new CustomEvent(type);

    if (typeof this.options.emitter === 'function') {
      this.options.emitter(type);
    } else {
      while (handler = this.handlers.shift()) {
        handler.dispatchEvent(type);
      }
    }
  };

  exports.ClipboardJS = ClipboardJS;
  return ClipboardJS;
}));

从这段代码中,我们可以看到 clipboard.js 的核心功能就是通过调用 document.execCommand('copy') 来复制文本。这个 API 可以让浏览器复制选定的文本到剪贴板。

success = _copyToClipboard(text);

我们重点看一下 _copyToClipboard 函数。这个函数首先创建一个临时元素(一个 textarea 元素),然后将需要复制的文本设置为这个临时元素的 value。接下来,它将这个临时元素添加到文档中,并将其选中。最后,它调用 document.execCommand('copy') 来复制选定的文本到剪贴板。

success = document.execCommand('copy');

复制完成后,它会将临时元素从文档中移除。

document.body.removeChild(tempElem);

最后,它返回一个布尔值,表示复制操作是否成功。

return success;

通过阅读 clipboard.js 的核心代码,我们可以了解到如何在浏览器中实现文本复制功能的原理。我们也可以了解到 clipboard.js 是如何使用这个原理来实现文本复制功能的。