欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2024-03-04 13:35:35
...

一 兼容性

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

二 整体思路

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

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

三 clipboard.js使用

<!-- 复制内容节点 -->
<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再用吧,怎么判断这里就不说了。另外手机端如何复制到图片还没有方案。

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