给博文添加复制链接按钮 发表于 2022-02-14 更新于 2023-01-30
字数总计 1.3k 阅读时长 5分钟 阅读量
更新记录 修复在不支持clipboard
的浏览器中复制内容时会弹出软键盘的问题
注意 该博文是基于Butterfly
主题修改的,不跟我一个主题的不要照搬我添加元素的方法。
本人没有学过前端知识,所以有一些名词可能会用错或者有这个名词但是我不知道,还请各位谅解。
缘由 想要做这个魔改的原因一方面是QQ的分享太过反人类,另一方面是我发现有些浏览器(比如我正在用的)在使用PWA浏览网页时打不开地址栏,这时候想要复制链接简直是难之又难。所以一直想要加一个复制链接的按钮,但是又不会加 。正巧,前段时间看到了群友写的一篇教程,我就在他的基础上修改了一些内容,就有了这篇博文。
魔改步骤 添加按钮 打开themes/[butterfly]/layout/includes/rightside.pug
,修改如下:
1 2 3 4 5 6 7 8 9 10 11 when 'chat' if chat_btn button#chat_btn(type="button" title=_p("rightside.chat_btn")) i.fas.fa-sms when 'comment' if commentsJsLoad a#to_comment(href="#post-comment" title=_p("rightside.scroll_to_comment")) i.fas.fa-comments + when 'share' + button#share-link(type="button" title='分享链接') + i.fa.fa-share-alt
1 2 3 4 5 #rightside - const { enable, hide, show } = theme.rightside_item_order - const hideArray = enable ? hide && hide.split(',') : ['readmode','translate','darkmode','hideAside'] - - const showArray = enable ? show && show.split(',') : ['toc','chat','comment'] + - const showArray = enable ? show && show.split(',') : ['toc','chat','comment', 'share']
添加JS 新建:[butterfly]\source\js\custom\share.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 document. addEventListener ( 'DOMContentLoaded' , ( ) => { const copyText = text => { const success = ( ) => btf. snackbarShow ( GLOBAL_CONFIG . copy. success) const noSupport = ( ) => btf. snackbarShow ( GLOBAL_CONFIG . copy. noSupport) const commandCopy = ( ) => { if ( document. queryCommandSupported && document. queryCommandSupported ( 'copy' ) ) { const input = document. createElement ( 'p' ) if ( navigator. userAgent. includes ( 'Firefox' ) ) input. textContent = text else input. innerText = text document. body. appendChild ( input) const selection = getSelection ( ) selection. removeAllRanges ( ) const range = document. createRange ( ) range. selectNodeContents ( input) selection. addRange ( range) document. execCommand ( 'copy' ) document. body. removeChild ( input) selection. removeAllRanges ( ) success ( ) } else noSupport ( ) } const clipboard = navigator. clipboard if ( clipboard) clipboard. writeText ( text) . then ( success) . catch ( commandCopy) else commandCopy ( ) } const getText = ( ) => { const url = location. protocol + '//' + location. host + location. pathname return ` ${ document. title} :\r\n ${ url} ` } document. getElementById ( 'rightside' ) . addEventListener ( 'click' , event => { const element = event. target. id ? event. target : event. target. parentNode if ( element?. id === 'share-link' ) copyText ( getText ( ) ) } ) } )
同时我们可以发现 BF 其实也内置了一个复制功能,不过其被隐藏在了main.js
的内部,外部无法访问,读者可以把我写的copyText
提取到外部,然后将main.js
中的代码改为调用copyText
,然后将main.js
中包含的复制函数删掉,可以节省一点空间。
然后在配置文件中引入 JS:
1 2 3 inject: bottom: + - <script defer src="/js/custom/share.js"></script>
原理介绍 向剪切板添加数据常见的方案有两种,一种是使用浏览器clipboard
接口,另一种是使用copy
命令。两种方案各有优劣,前者是异步接口,后者是同步接口。通常建议优先使用前者(后者已经被标记为废弃但是能用) ,但是由于部分浏览器不兼容,所以也要写上后者以防不备之需。
clipboard
接口的用法很简单,看一段示例程序:
1 2 3 navigator. clipboard. writeText ( '测试数据' ) . then ( ( ) => console. log ( '复制成功' ) ) . catch ( ( ) => console. error ( '复制失败' ) )
clipboard
中包含以下几个函数:
write
- 写入任意数据到剪切板,返回一个Promise
writeText
- 写入一个字符串到剪切板,返回一个Promise
read
- 从剪切板读取任意数据,返回一个Promise
readText
- 从剪切板读取一个字符串,返回一个Promise
更多内容见:MDN 文档
copy
命令的用法同样很简单,大体思路就是通过代码模拟用户选取文本,然后执行复制命令即可。
不过需要注意的是,要复制的内容一定保存在已经存在于DOM中且display
不为none
的元素中,不然是无法选中的。同样,个人建议使用p
标签存储文本,因为使用document.createTextNode
的话是无法把换行符正确的添加到剪切板中的,使用input
标签会导致移动端弹出输入法(虽然只是闪一下,但是很烦人) 。
大体方法如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 if ( document. queryCommandSupported && document. queryCommandSupported ( 'copy' ) ) { const text = '测试数据' const input = document. createElement ( 'p' ) if ( navigator. userAgent. includes ( 'Firefox' ) ) input. textContent = text else input. innerText = text document. body. appendChild ( input) const selection = getSelection ( ) selection. removeAllRanges ( ) const range = document. createRange ( ) range. selectNodeContents ( input) selection. addRange ( range) document. execCommand ( 'copy' ) document. body. removeChild ( input) selection. removeAllRanges ( ) console. log ( '复制成功' ) } else console. error ( '复制失败' )
然后把代码结合起来就好了。
给博文添加复制链接按钮 空 梦 | 山岳库博
更新于 2023-01-30
发布于 2022-02-14