clipboard.js 实现代码一键复制功能
Synopsis: 使用 Python-Markdown 将 markdown 原文转换为 HTML 内容后,借助于 clipboard.js(不依赖 Flash)将代码块复制到剪贴板
1. 思路整理
1.1 icon 固定到 div 的右上角
使用 Python-Markdown 将 markdown 原文转换为 HTML 内容后,大致格式如下:
<div> <div class="codehilite"> <pre> codes... </pre> </div> ... <div class="codehilite"> <pre> codes... </pre> </div> ... <div class="codehilite"> <pre> codes... </pre> </div> </div>
为了让 复制
图标 <a><i class="fa fa-clone"></i></a>
位于每个代码块 <div class="codehilite">
的右上角,要使用 position
来定位,比如:
<div> <div class="codehilite" style="position: relative;"> <a style="position: absolute; top: .3em; right: .5em;"><i class="fa fa-clone"></i></a> <pre> codes... </pre> </div> ... <div class="codehilite" style="position: relative;"> <a style="position: absolute; top: .3em; right: .5em;"><i class="fa fa-clone"></i></a> <pre> codes... </pre> </div> ... <div class="codehilite"> <a style="position: absolute; top: .3em; right: .5em;"><i class="fa fa-clone"></i></a> <pre> codes... </pre> </div> </div>
其中 <a><i class="fa fa-clone"></i></a>
和 <pre>codes...</pre>
属于兄弟节点,它们都是 <div class="codehilite">
的子节点
1.2 clipboard.js 介绍
官方文档: https://clipboardjs.com/
我们给上面的 HTML 中每个 <a>
标签添加 .copyicon
,比如:
<a class="copyicon" style="position: absolute; top: .3em; right: .5em;"><i class="fa fa-clone"></i></a>
用于表示 clipboard.js 中的 trigger
当用户点击 复制
图标后,如何选择要复制的内容 target
?
2. 初步方案
假设使用 <div class="codehilite">
表示 clipboard.js 中的 target
的话,由于 HTML 中有多个代码块,所以需要为每个代码块指定唯一的 id(id="code{}"
),复制时通过 data-clipboard-target="#code{}"
选中对应的代码块
# 使用 Python-Markdown 将 markdown 原文转换为 HTML 内容(self.content_html),语法高亮是 markdown.extensions.codehilite 插件(依赖 pygments 模块) # 为每个代码块添加 [复制] 按钮,然后前端页面再通过 clipboard.js 实现复制功能 n = self.content_html.count('<div class="codehilite">') for i in range(n): self.content_html = re.sub(r'<div class="codehilite">', '<div class="codehilite" style="position: relative;" id="code{}">' '<a class="u-link-v5 g-color-main g-color-primary--hover copyicon" style="position: absolute; top: .3em; right: .5em;" data-clipboard-action="copy" data-clipboard-target="#code{}"><i class="fa fa-clone"></i></a>'.format(i, i), self.content_html, 1)
增加 JS 代码:
<script src="dist/clipboard.min.js"></script> <script> var clipboard = new Clipboard('.copyicon'); clipboard.on('success', function(e) { // console.log(e) Swal({ toast: true, position: 'top', showConfirmButton: false, timer: 3000, type: 'success', title: '复制成功' }); e.clearSelection(); // 清除文本的选中状态 }); clipboard.on('error', function(e) { // console.log(e); Swal({ toast: true, position: 'top', showConfirmButton: false, timer: 3000, type: 'error', title: '复制失败' }); e.clearSelection(); // 清除文本的选中状态 }); </script>
存在问题: 复制的内容前面多出一个空行
因为复制了完整的 <div class="codehilite">
导致包含 <a><i class="fa fa-clone"></i></a>
的缘故,它就是空行(如果 i 标签内部有文字,那么就不是空行,而是文字行)
2. 最终方案
官方文档提到可以设置 target
为 trigger
的下一个兄弟节点(<pre>codes...</pre>
):
<script src="dist/clipboard.min.js"></script> <script> var clipboard = new Clipboard('.copyicon', { target: function(trigger) { return trigger.nextElementSibling; } }); clipboard.on('success', function(e) { // console.log(e) Swal({ toast: true, position: 'top', showConfirmButton: false, timer: 3000, type: 'success', title: '复制成功' }); e.clearSelection(); // 清除文本的选中状态 }); clipboard.on('error', function(e) { // console.log(e); Swal({ toast: true, position: 'top', showConfirmButton: false, timer: 3000, type: 'error', title: '复制失败' }); e.clearSelection(); // 清除文本的选中状态 }); </script>
不再需要为每个代码块指定唯一 id,而且 trigger 也可以省去 data-clipboard-target
属性:
# 使用 Python-Markdown 将 markdown 原文转换为 HTML 内容(self.content_html),语法高亮是 markdown.extensions.codehilite 插件(依赖 pygments 模块) # 为每个代码块添加 [复制] 按钮,然后前端页面再通过 clipboard.js 实现复制功能 self.content_html = re.sub(r'<div class="codehilite">', '<div class="codehilite" style="position: relative;">' '<a class="u-link-v5 g-color-main g-color-primary--hover copyicon" style="position: absolute; top: .3em; right: .5em;" data-clipboard-action="copy"><i class="fa fa-clone"></i></a>', self.content_html)
0 条评论
评论者的用户名
评论时间暂时还没有评论.