一、页面HTML
页面结构代码如下:
<div ref="blogContentRef" v-html="blogInfo.content"></div>
二、实现
- 初始化时,通过 ref 获取文章内容;
- 遍历文章内容节点,找出所有 pre 标签;
- 遍历 pre 标签,给每个 pre 标签添加复制按钮;
- 给复制按钮绑定点击事件;
- 默认隐藏复制按钮;
- 鼠标移动到代码块,显示复制按钮;
- 点击复制按钮,调用复制方法,复制内容到剪贴板;
- 复制成功,1s后恢复复制按钮。
// 初始化,获取内容后调用
init() {
this.$nextTick(() => {
// 根据ref来获取文章的内容
const articleContent = this.$refs.blogContentRef
// 遍历文章内容节点
articleContent.childNodes.forEach((e, index) => {
// 每个代码块标签添加复制按钮
if (e.nodeName === 'PRE') {
// 创建 button 节点
const copyButton = document.createElement('button')
// 设置类名
copyButton.setAttribute('class', 'btn-pre-copy')
// 设置按钮名称
copyButton.innerHTML = '复制'
// 绑定点击事件
copyButton.onclick = () => {
// 获取代码块内容
const copyData = e.firstChild.innerText
// 调用复制方法
this.copyToClipboard(copyData)
// 更改按钮名称
copyButton.innerHTML = '复制成功'
// 恢复按钮名称
setTimeout(() => {
copyButton.innerHTML = '复制'
}, 1000)
}
// 将节点加入pre标签下
e.appendChild(copyButton)
}
})
})
},
// js复制到剪贴板
copyToClipboard(content) {
if (window.clipboardData) {
window.clipboardData.setData('text', content)
} else {
;(content => {
document.oncopy = e => {
e.clipboardData.setData('text', content)
e.preventDefault()
document.oncopy = null
}
})(content)
document.execCommand('Copy')
}
},
三、样式调整
// 代码块
/deep/ pre {
font-family: Consolas;
text-align: left;
padding: 1em;
padding-left: 3.5em; // 0.8em
border-radius: 5px;
counter-reset: line;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
line-height: 1.5;
overflow: auto;
position: relative;
// 鼠标经过pre显示复制按钮
&:hover .btn-pre-copy {
display: block;
}
// 复制按钮样式,默认隐藏
.btn-pre-copy {
position: absolute;
top: 10px;
right: 10px;
font-size: 12px;
line-height: 1;
cursor: pointer;
color: #3a3a3a;
padding: 5px 8px;
box-sizing: border-box;
background-color: #ffffff;
border: 0;
border-radius: 2px;
display: none;
}
}