JS一键复制 兼容PC(包括图片)+移动端

一 兼容性

兼容PC+手机端,Chrome 42+、Edge 12+、Firefox 41+、IE、Opera 29+、Safari 10+,PC支持复制图片,手机端友好交互。其中:
- clipboard.jsJS一键复制 兼容PC(包括图片)+移动端_第1张图片
- window.clipboardData 兼容IE
- 友好型补充(主要针对移动端)

二 整体思路

最近做了一个需要 一键复制 功能的网站,也是经历了一番挣扎,下面给出自己的一些总结,欢迎大家补充。

  • ZeroClipboard.js虽然兼容性较好,但需要Flash,本文不考虑。如不在意flash可以尝试
  • 本文主体clipboard.js
  • 针对不兼容的IE版本尝试使用window.clipboardData
  • 交互友好型补充方案(主要针对移动端)

三 clipboard.js使用

  • 官方文档:https://clipboardjs.com/#example-text
  • 使用总结:
    1. 通过npm或者cdn或者直接 引入 clipboard.js
    2. 使用方法@1 行内

<input id="foo" value="https://github.com/zenorocha/clipboard.js.git">


<button class="btn" data-clipboard-action="copy" data-clipboard-target="#foo" data-clipboard-text="我是复制的内容,和前一个属性选其一使用">
    <img src="assets/clippy.svg" alt="Copy to clipboard">
button>

<script>
    // 通过选择触发节点实例化复制/剪切功能(必须)
    var clipboard = new Clipboard('.btn');

    // 复制成功or失败后的回调函数,可以弹窗(toast)提示(可选)
    clipboard.on('success', function(e) {
        console.info('Action:', e.action);
        console.info('Text:', e.text);
        console.info('Trigger:', e.trigger);

        e.clearSelection();
    });
    clipboard.on('error', function(e) {
        console.error('Action:', e.action);
        console.error('Trigger:', e.trigger);
    });
script>

其中

  • 复制内容节点 可以是任何的html标签,只要有id或者class标识,但 cut (剪切)只支持input或textarea
  • data-clipboard-action copy(复制) 或 cut(剪切),默认copy
  • data-clipboard-target 目标节点(复制/剪切的内容)
  • data-clipboard-text 直接定义复制内容,这个和 data-clipboard-target 选其一使用即可(至于同时使用时哪个生效有兴趣的可以研究),这个可以应付多节点复制,当然下面还有其他方案。

3.使用方法@2 function

new Clipboard('.btn', {
    target: function(trigger) {
        return trigger.nextElementSibling; // 目标内容为出发节点的下一个节点
        // return trigger.previousElementSibling; // 前一个节点
        // return trigger.parentElement; // 父节点
        // return document.getElementById('id'); // 直接    }
});

new Clipboard('.btn', {
    text: function(trigger) {
        return trigger.getAttribute('aria-label');
        // return trigger.nextElementSibling.innerText;
        // return document.getElementById('id').innerText;
    }
});

new Clipboard('.btn', {
    container: document.getElementById('modal')
});

这种是实例化的时候添加复制目标,添加目标方式有:

  • target return的是目标节点,当然return之前还可以执行一些其他事件,参数trigger一般是触发节点。这个方法可以支持复制图片
  • text return的是目标内容,不过这里貌似只支持原生JS的方法(innerText/value),我用jQuery的提示无效
  • container 这个我没用过,理解应该是返回复制内容的盒子节点,那就跟target类似了。官方解释是:

    For use in Bootstrap Modals or with any other library that changes the
    focus you’ll want to set the focused element as the container value.

4.clipboard.js的一些其他方法:

  • Clipboard.isSupported(),返回 true/false 可以用于提前检测是否支持clipboard.js

4.针对clipboard.js不支持的IE浏览器

那就是IE8及以下了,因为IE有个clipboardData方法,所以需要兼容的话可以解决,使用这个方法操作的时候会有弹窗提示用户是否允许访问剪贴板

  • 首先是判断何时使用这个,第一反应是获取浏览器种类,想来其实是不用的,看代码
if (Clipboard.isSupported()) {
    // 使用clipboard.js处理
}else if(window.clipboardData){
    var btn = document.getElementById('btn'); // 触发节点
    var copyText = document.getElementById('btn').innerText // 或value,要复制的内容
    btn.onclick = function(){
        window.clipboardData.setData('Text', copyText);
    }
}else{
    alert('您目前的浏览器不支持一键复制,请手动复制使用其他浏览器试试')
}
  • 关于clipboardData,它有3个方法:
    1. clearData(dataFormat) 删除剪贴板中指定格式的数据dataFormat:”text”,”url”
    2. getData(dataFormat) 从剪贴板获取指定格式的数据。 dataFormat:”text”,”url”
    3. setData(dataFormat, data) 给剪贴板赋予指定格式的数据。返回 true 表示操作成功。dataFormat:”text”,”url”,”file”,”html”,”image”;data: 剪贴数据

5. 针对不支持一键复制的友好性设置

当然这部分主要是手机端了,主要是让其更好的完成手动长按复制,那IOS好像有些地方长按并不会有反应(出现复制、全选等)。这种情况一般出现在非input/textarea(个人感觉clipboard.js对input的支持更好一些,但input内容不能换行…textarea移动端有时候会有问题)标签下,比如div,那怎样让其支持呢?

<div contenteditable="true" onkeydown="return false;" onpaste="return false;">
    内容1<br>
    内容2
div>

contenteditable属性可以让盒子内容处于可以编辑状态,我们只要这个状态,而不是让用户真的能编辑onkeydown="return false;" onpaste="return false;" 禁用键盘和右键粘贴

  • 针对IOS的Safari 10以下或者不支持clipboard.js的环境,有更好的用户体验方案,那就是用户点一下复制内容就自动帮其全部选中,这样用户只需点击复制

    针对div contenteditable:

document.addEventListener('selectionchange', function(){
    var t = window.getSelection().anchorNode;
    var tParent = t.parentNode.id == 'mobileCopyText'; //className亦可
    if (t && tParent && t.parentNode.innerText != window.getSelection()) { 
        window.getSelection().selectAllChildren(tParentNode)                                      
    }
})

简单解释一下原理:就是给 选区内容改变(selectionchange)(光标位置也会触发)添加一个监听事件,一旦触发,当(if条件)

  • 选取内容开始位置(t)存在(为真)
  • 其节点为复制内容的节点
  • 选中的区域并不是需要复制内容的全部

这个时候选中 复制内容的父节点(有时候你可能需要parentNode两次)下的所有内容
关于getSelection()感兴趣的可以自己了解更多

针对input:

$('input').focus(function(){
    $(this).select()
})

可能有人会问这么好的事情为什么说是只针对IOS,原因是测试发现Android下有些怪异的现象,那就是通过这种方法全选中后你点复制,但事实上你并没有复制到内容(尴尬)可能是个别浏览器的锅。所以最好还是判断一下IOS再用吧,怎么判断这里就不说了。另外手机端如何复制到图片还没有方案。

以上是我的总结,欢迎交流补充

你可能感兴趣的:(javascript)