浏览器的 Copy 事件

需求

很多分享都有一个点击复制当前链接的功能,所以我们需要一个按钮,点击出现弹框并显示已复制的链接

实现

第一版

根据网上关于浏览器的 Copy 事件实现第一版的复制按钮,点击会出现弹框,并显示已复制到剪切板的链接:

点击我查看

代码

<span id="copyBtn" class="item">
    <i class="iconfont icon-link"></i>
    <span class="social_name">CopyButton 1</span>
</span>
document.getElementById('copyBtn').onclick = function () {
    document.execCommand('copy');
    document.getElementById('modal-container').setAttribute('class', 'sketch')
}

document.getElementById('copyBtn').oncopy = function (event) {
    if (!-[1,]) {
        if (window.clipboardData) {
            window.clipboardData.setData('Text', window.location.href);
            document.getElementById('link').textContent = window.clipboardData.getData('Text')
        }
    } else {
        event.preventDefault()
        if (event.clipboardData) {
            event.clipboardData.setData('text/plain', window.location.href);
            document.getElementById('link').textContent = event.clipboardData.getData('text')
        }
    }
}

测试

Chrome 上一切正常,Perfect !!

但是拿到 Safari 上试了一下,发现不行,没有触发复制事件,Oh My God !!

第二版

经过再三查询与尝试找到了 Safari 不能复制的原因,Safari 需要先选中某部分文本才能触发 Copy 事件

修改实现第二版:

点击我查看

代码

<span id="copyBtn" class="item">
    <i class="iconfont icon-link"></i>
    <span class="social_name">CopyButton 1</span>
+   <textarea id="selection" style="display: none">window.location.href</textarea>
</span>
document.getElementById('copyBtn').onclick = function () {
+   document.getElementById('selection').select();
    document.execCommand('copy');
    document.getElementById('modal-container').setAttribute('class', 'sketch')
}

测试

现在 Chrome 和 Safari 都表现正常,试下移动端

发现安卓正常,至少我测试的几个浏览器还算正常

但是!! ios 的 Safari 浏览器又出现未触发复制事件的问题

第三版

又一次再三查询与尝试,发现移动端的 Safari 浏览器并不能触发 oncopy 事件,需要使用 setSelectionRange 选中复制的文本,而且这个文本区域必须可见,且不能被其他元素遮挡…

上面针对桌面端实现的代码中我加了一个 textarea 标签用于选中,但是设置 display: none 为不可见,因为我并不需要这个选中文本,只是为了选中后能触发 Copy 事件;

而移动端如果设置这个文本区域不可见的话无法选中并复制,经过尝试需要使用 setSelectionRange 和一个随用随删的 input 标签来实现复制

修改后效果,也是最终效果:

点击我查看

代码

<span id="copyBtn" class="item">
    <i class="iconfont icon-link"></i>
    <span class="social_name">CopyButton 1</span>
    <textarea id="selection" style="display: none">url</textarea>
</span>
document.getElementById('copyBtn').onclick = function () {
    var input = document.createElement('input');
    input.setAttribute('readonly', 'readonly');
    input.setAttribute('value', window.location.href);
    document.body.appendChild(input);

    if (!!navigator.userAgent.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/)) { // fix ios safari copy event
        input.setSelectionRange(0, input.value.length);
        document.getElementById('link').textContent = window.location.href;
    } else { // fix desktop safari copy event
        document.getElementById('selection').select();
    }

    document.execCommand("copy") || (document.getElementById("link").textContent = "Failed!");
    document.getElementById('modal-container').setAttribute('class', 'sketch');
    document.body.removeChild(input);
}

document.getElementById('copyBtn').oncopy = function (event) {
    if (!-[1,]) {
        if (window.clipboardData) {
            window.clipboardData.setData('Text', window.location.href);
            document.getElementById('link').textContent = window.clipboardData.getData('Text')
        }
    } else {
        event.preventDefault()
        if (event.clipboardData) {
            event.clipboardData.setData('text/plain', window.location.href);
            document.getElementById('link').textContent = event.clipboardData.getData('text')
        }
    }
}

测试

第三版在主流浏览器上都能满足需求了

文章目录
  1. 需求
  2. 实现
    1. 第一版
      1. 代码
      2. 测试
    2. 第二版
      1. 代码
      2. 测试
    3. 第三版
      1. 代码
      2. 测试