在页面上启用剪切板,一直是一个常见而又头疼的问题。我说的是自定义需要复制/剪切的内容。
以前,有如下几种解决方案:
如果需要复制的内容来自页面上已有标签(input
、textarea
等),先调用该标签的 .select()
选中文本,然后调用 document.execCommand('copy')
复制至剪切板;
如果需要复制的内容不来自页面上已有标签(比如拼接字符串),可以先创建一个 input
或 textarea
,赋值需要复制的内容,append 到页面上,调用 document.execCommand('copy')
复制至剪切板,再从页面上 remove;
把需要复制的内容,使用 window.prompt
弹出来,再提示用户按 Ctrl
+ C
;
使用第三方插件,具体内部原理因插件不同而不同。大概 4、5 年前依稀记得有一款插件还需要依赖 Flash
???现在与时俱进了,有一款不依赖 Flash
和其他 framework 的插件 clipboard.js ;
不过如果仅仅是自定义需要复制内容的话,完全没必要引入第三方库。有了 Clipboard 的新 API,使用剪切板将变得炒鸡方便啦。
先看一下目前(2020/9/7)的兼容性 。
(仅看最重要的 writeText 的情况)
嗯,还行,82.33% 啦。如果不需要其他 API(readText、监听 ClipboardEvent 等),不考虑 IE 用户的话,足够了!
说干就干。那就从本博客的源代码复制开始着手吧。
Hexo 的默认主题 landscape 不支持源代码复制功能,那就手撸一个吧。
先更改 themes/landscape/source/js/script.js
,在末尾处添加如下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 if (navigator.clipboard) { const className_shining = "shining" ; const copySourceCode = async () => { const $elem = event.currentTarget; const sourceCode = $elem.parentElement.querySelector(".code" ).innerText; await navigator.clipboard.writeText(sourceCode); const $msg = $elem.querySelector("span" ); const duration = 512 ; $elem.classList.add(className_shining); setTimeout(() => { $msg.innerText = $msg.dataset.afterMsg; }, duration / 2 ); setTimeout(() => { $elem.classList.remove(className_shining); void $elem.offsetWidth; $elem.classList.add(className_shining); setTimeout(() => { $msg.innerText = $msg.dataset.beforeMsg; }, duration / 2 ); setTimeout(() => { $elem.classList.remove(className_shining); }, duration); }, duration * 4 ); }; Array .from( document .querySelectorAll(".article-entry figure.highlight" ) ).forEach($fig => { const $fa = document .createElement("i" ); $fa.classList.add("copy" ); $fa.classList.add("fa" ); $fa.classList.add("fa-files-o" ); const beforeMsg = `👈 tap this icon to copy the code snippet` ; const afterMsg = `copied` ; const $msg = document .createElement("span" ); $msg.classList.add("msg" ); $msg.innerText = beforeMsg; $msg.dataset.beforeMsg = beforeMsg; $msg.dataset.afterMsg = afterMsg; const $row = document .createElement("div" ); $row.classList.add("source-clipboard" ); $row.appendChild($fa); $row.appendChild($msg); $row.addEventListener("click" , copySourceCode); $fig.appendChild($row); }); }
更改 themes/landscape/source/css/_partial/article.styl
,设置样式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 figure &.highlight .source-clipboard margin-top : 0.5em border-top : 1px solid gray padding-top : 0.5em .msg display : inline-block padding : 0 0.5em opacity : 1 &.shining .msg animation-name : shining animation-duration : 0.512s animation-iteration-count : 1 animation-timing-function : ease-in-out animation-fill-mode : forwards animation-direction : alternative @keyframes shining{ 0% { opacity : 1 ;} 50% { opacity : 0 ;} 100% { opacity : 1 ;} }
使用了点 CSS 3 animation 新特性。🙂
友情提醒 The clipboard-write permission is granted automatically to pages when they are in the active tab. The clipboard-read permission must be requested, which you can do by trying to read data from the clipboard.
展示
参考链接
本文链接:
content_copy
https://zxs66.github.io/2020/09/07/javascript-clipboard-API/