在页面上启用剪切板,一直是一个常见而又头疼的问题。我说的是自定义需要复制/剪切的内容。
以前,有如下几种解决方案:
如果需要复制的内容来自页面上已有标签(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/