Clipboard API

183 阅读7分钟

我们先来提几个场景,比如我们想要在网页上复制一段文字,结果会提示不允许复制;还有某音或者某宝分享的时候也是发一段文字过去,复制以后打开就会跳转到对应页面;还有就是复制一段文字,粘贴的时候发现除了原有文字还会给你加上一些东西。这些操作都可以通过Clipboard API去完成。

Clipboard API分为两个部分,一个部分是一个对象,放在navigator.clipnoard中,这里面提供了一些方法供我们操作剪贴板。除了这个对象以外,还提供了一套事件,就是当用户在页面进行复制或者粘贴的时候,会触发相应的事件。我们通过这两个东西就可以完成绝大部分的操作了。

1.不允许复制

这个时候我们就要去监听它的复制事件了,复制事件是copy

document.addEventListener('copy', (e) => {
    console.log('内容已复制到剪贴板!');
});

动画.gif

如果我们不想让其被复制,我们可以组织事件的默认行为,让其不能被复制。

document.addEventListener('copy', (e) => {
    // 阻止默认行为
    e.preventDefault();
});

动画.gif

我们先去复制一条别的内容,然后再复制我们网页上的内容,在粘贴的时候会发现粘贴的还是上一次的内容,因为网页上的内容不会进入剪贴板,这么一来就不能被复制了。

2.往剪贴板里面去添加东西

我们可以通过navigator.clipnoard的一些方法去操作剪贴板,比如不让用户复制内容,但是往剪贴板里面添加一段文字,让其在粘贴的时候粘贴上去的是我们添加的文字,一般用于版权相关的操作。

document.addEventListener('copy', (e) => {
    e.preventDefault();
    navigator.clipboard.writeText('版权归月亮所有,翻版必究!');
});

动画.gif

我们也可以让其复制内容,不过在末尾加上我们的自定义内容。

<template>
    <div class="screen-view">
        <div class="txt">我是要被复制的内容!</div>
    </div>
</template>
<script>
export default {
    name: 'Clipboard',
    data() {
        return {}
    },
    mounted() {
        let txt = document.querySelector('.txt');
        document.addEventListener('copy', () => {
            // 因为文本是divDOM节点,所以要用innerText获取文本内容,如果是input或者textarea,则用value获取文本内容
            navigator.clipboard.writeText(txt.innerText + '版权归月亮所有,翻版必究!');
        });
    },
}
</script>

动画.gif

而且navigator.clipboard.writeText返回的是一个promise,所以我们可以在后面添加then方法或者catch方法。

        let txt = document.querySelector('.txt');
        document.addEventListener('copy', () => {
            // 因为文本是divDOM节点,所以要用innerText获取文本内容,如果是input或者textarea,则用value获取文本内容
            navigator.clipboard.writeText(txt.innerText + '版权归月亮所有,翻版必究!').then(() => {
                console.log('复制成功');
            }).catch(err => {
                console.log('复制失败', err);
            });
        });

动画.gif

3.读取剪贴板内容,然后做出相应事件

这一点就用于某音或者某宝分享东西了,首先我们要先读取剪贴板,我们可以通过navigator.clipboard.readText()事件去读取,这返回的也是一个promise,所以我们通过then方法去做一些后续操作,比如跳转某个页面啊,我这里的是把剪贴板的内容复制到页面上,因为这个方法我直接写在mounted事件里的,所以需要刷新一下页面去触发。

    mounted() {
        let txt = document.querySelector('.txt');
        navigator.clipboard.readText().then(res => {
            // 读取剪贴板内容赋值到txt
            txt.innerText = res
        })
    },

动画.gif

4.复制图片

平时图片我们也可以直接复制到页面上。

<template>
    <div class="screen-view">
        <!-- contenteditable属性可以让div变成可编辑状态 -->
        <div class="editor" contenteditable></div>
    </div>
</template>
<script>
export default {
    name: 'Clipboard',
    data() {
        return {}
    },
    mounted() {

    },
}
</script>
<style lang='scss'>
.screen-view {
    height: 100%;
    padding: 10px;
    box-sizing: border-box;

    .editor {
        width: 400px;
        height: 300px;
        border: 1px solid #ccc;

        img {
            max-width: 100% !important;
        }
    }
}
</style>

动画.gif

但是这有两个缺陷,一是不能保证所有浏览器都有这个功能,二是这个只能复制截图,我们要是复制一个别的图片比如放在桌面上的图片,这么一来就复制不上去了。

动画.gif

那么我们该怎么做呢,首先我们要去监听一个事件叫做粘贴事件paste,在这里它会提供一个对象叫做clipboardData,当我们粘贴的是类似于图片这种东西的时候clipboardData会有一个属性叫做files。我们打印看一下。

        document.addEventListener('paste', (e) => {
            console.log(e.clipboardData.files);
        });

当我们粘贴的是一个文本的时候,会发现这个files长度为0,没有任何东西。

动画.gif

当我们粘贴的是一个图片的时候,会发现里面有东西了,每一项都是你粘贴的图片文件,打开就是文件的信息。

动画.gif

image.png

所以我们就可以获取files里的东西去操作,让其复制到页面上,首先得阻止事件的默认行为,就是不用浏览器的粘贴方式,然后获取文件,前面我们看到文件信息里有一个属性叫做type,我们可以根据这个去判断是图片还是文档还是什么别的东西,然后进行对应操作。

<template>
    <div class="screen-view">
        <!-- contenteditable属性可以让div变成可编辑状态 -->
        <div class="editor" contenteditable></div>
    </div>
</template>
<script>
export default {
    name: 'Clipboard',
    data() {
        return {}
    },
    mounted() {
        document.addEventListener('paste', (e) => {
            // 大于0表示剪贴板中有文件
            if (e.clipboardData.files.length > 0) {
                // 首先阻止浏览器的默认粘贴行为,不用浏览器默认粘贴方式
                e.preventDefault();

                // 获取粘贴的文件
                const file = e.clipboardData.files[0];

                // startsWith() 方法用于检测字符串是否以指定的子字符串开头
                if (file.type.startsWith('image/')) {
                    // 如果是图片文件,创建一个URL并插入到编辑器中
                    // URL.createObjectURL() 静态方法会创建一个 DOMString,其中包含表示参数对象的 URL
                    const imgURL = URL.createObjectURL(file);
                    const img = document.createElement('img');
                    // 将创建的URL赋值给img的src属性
                    img.src = imgURL;
                    document.querySelector('.editor').appendChild(img);

                    // 当不再需要该对象URL时,应该通过调用 URL.revokeObjectURL() 来释放它
                    img.onload = () => {
                        URL.revokeObjectURL(imgURL);
                    };
                } else {
                    alert('仅支持粘贴图片');
                }
            }
        });
    },
}
</script>
<style lang='scss'>
.screen-view {
    height: 100%;
    padding: 10px;
    box-sizing: border-box;

    .editor {
        width: 400px;
        height: 300px;
        border: 1px solid #ccc;

        img {
            max-width: 100% !important;
        }
    }
}
</style>

动画.gif

可以看到这样就可以把图片复制到页面上了,关于图片的操作还有一种是使用读取器的方法。

        document.addEventListener('paste', (e) => {
            // 大于0表示剪贴板中有文件
            if (e.clipboardData.files.length > 0) {
                // 首先阻止浏览器的默认粘贴行为,不用浏览器默认粘贴方式
                e.preventDefault();

                // 获取粘贴的文件
                const file = e.clipboardData.files[0];

                // startsWith() 方法用于检测字符串是否以指定的子字符串开头
                if (file.type.startsWith('image/')) {
                    // 如果是图片
                    // 创建FileReader对象
                    const reader = new FileReader();
                    
                    // 读取文件内容,形成一个base64编码的URL
                    reader.readAsDataURL(file);

                    // 当读取操作完成时触发
                    reader.onload = (event) => {
                        const img = document.createElement('img');
                        // event.target.result就是读取到的图片base64编码
                        img.src = event.target.result;
                        // 将图片插入到可编辑的div中
                        document.querySelector('.editor').appendChild(img);
                    };
                } else {
                    alert('仅支持粘贴图片');
                }
            }
        });

当然除了读取图片以外我们也可以去读取文档,我已经创建好了两个文档,一个是doc文档,一个是docx文档。我们先来看一下这两个文档打印出来的内容是什么。

image.png

image.png

可以看到type都是application/开头的,那么接下来就去做判断就好了。

<template>
    <div class="screen-view">
        <!-- contenteditable属性可以让div变成可编辑状态 -->
        <div class="editor" contenteditable></div>
    </div>
</template>
<script>
export default {
    name: 'Clipboard',
    data() {
        return {}
    },
    mounted() {
        document.addEventListener('paste', (e) => {
            // 大于0表示剪贴板中有文件
            if (e.clipboardData.files.length > 0) {
                // 首先阻止浏览器的默认粘贴行为,不用浏览器默认粘贴方式
                e.preventDefault();

                // 获取粘贴的文件
                const file = e.clipboardData.files[0];
                console.log(file);


                // startsWith() 方法用于检测字符串是否以指定的子字符串开头
                if (file.type.startsWith('image/')) {
                    // 如果是图片
                    // 创建FileReader对象
                    const reader = new FileReader();

                    // 读取文件内容,形成一个base64编码的URL
                    reader.readAsDataURL(file);

                    // 当读取操作完成时触发
                    reader.onload = (event) => {
                        const img = document.createElement('img');
                        // event.target.result就是读取到的图片base64编码
                        img.src = event.target.result;
                        // 将图片插入到可编辑的div中
                        document.querySelector('.editor').appendChild(img);
                    };

                } else if (file.type.startsWith('application/')) {
                    // 如果是文件
                    // 创建FileReader对象
                    const reader = new FileReader();
                    // 读取文件内容,形成一个base64编码的URL
                    reader.readAsDataURL(file);
                    // 当读取操作完成时触发
                    reader.onload = (event) => {
                        const link = document.createElement('a');
                        // event.target.result就是读取到的文件base64编码
                        link.href = event.target.result;
                        link.download = file.name; // 设置下载文件名
                        link.textContent = `点击下载 ${file.name}`;
                        // 将链接插入到可编辑的div中
                        // 不插入到editor这个div 是因为有了 contenteditable 属性以后就没法点击了
                        document.querySelector('.screen-view').appendChild(link);

                    };

                } else {
                    alert('请粘贴图片或文件');
                }
            }
        });
    },
}
</script>
<style lang='scss'>
.screen-view {
    height: 100%;
    padding: 10px;
    box-sizing: border-box;

    .editor {
        width: 400px;
        height: 300px;
        border: 1px solid #ccc;

        img {
            max-width: 100% !important;
        }
    }
}
</style>

动画.gif