如何给博客文章的代码块添加复制功能

740 阅读1分钟

一、页面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;
    }
}

四、效果

9XgPiHdgi4gLvzDgfIgJ6XQBDIgJ8RGqQQDxMYgQ2RgRDIDs3QDNbwSRz4fuk3gghoTIplggLILAEBADs=.gif