为代码pre code元素添加一件复制功能

Jаvascript

为代码块添加一个"复制代码"按钮,并实现点击按钮后将代码块的内容复制到剪贴板中。

  1. 首先通过document.querySelectorAll('pre')获取所有<pre>元素(即代码块)。
  2. 使用forEach方法遍历每个代码块。
  3. 创建一个文本元素 copyButton,设置其class为"copy",并将显示文本设置为"复制代码"。
  4. 创建一个容器元素 container,设置其class为"code-container",并将复制按钮添加到容器元素内。
  5. 将容器元素插入到代码块之前。
  6. 设置容器元素样式,使其定位为相对定位(position: relative)。
  7. 设置复制按钮样式,使其绝对定位于容器元素的右上角。
  8. 为复制按钮添加点击事件监听器。
  9. 在点击事件处理函数中,获取代码块的文本内容。
  10. if (navigator.clipboard && window.isSecureContext)以此判断使用不同的复制方法,使用navigator.clipboard.writeText(code).then(() => {}).catch(() => {});或采用document.execCommand('copy'); 这里需要借助创建textarea
  11. 创建一个临时的 <textarea> 元素,并将代码块的内容设置为其值。
  12. <textarea> 元素追加到 <body> 中。
  13. 选中 <textarea> 中的文本。
  14. 执行复制操作,将选中的文本复制到剪贴板中。
  15. 移除临时的 <textarea> 元素。
  16. 修改复制按钮文本为"复制成功"。

这段代码的作用是为网页中的代码块添加一个复制按钮,方便复制代码片段。

CSS

用于设置复制按钮和代码块的样式。具体样式如下:

  1. .code-wrapper 类选择器用于设置包裹代码块的容器元素的样式。在这里设置了相对定位(position: relative)。
  2. .code-block 类选择器用于设置代码块的样式。在这里设置了相对定位(position: relative)。
  3. .copy 类选择器用于设置复制按钮的样式。具体样式如下:
    • font-size:设置字体大小为 13px。
    • transition:设置颜色变化的过渡效果为 0.1秒。
    • color:设置按钮的颜色为带透明度的红色color: hsl(165.03deg 19.14% 92.37% / 97%);,背景为灰色background: #1b45bede;。
    • border:去掉按钮的边框。
    • border-radius:设置按钮的圆角为4px。
    • cursor:设置鼠标悬停在按钮上时的样式为指针。
    • z-index:将复制按钮的层级置于顶层,确保按钮显示在其他内容之上。

这些样式可以使用在前面提到的 jаvascript 脚本中的相关元素上,以实现更好的外观和交互效果。

js文件,直接在html中引用 ,如果是在vue中使用,需要在渲染html的方法中使用下面的js。

javascript 复制代码
(function () {
  "use strict"
  // 获取<pre>元素
  var codeBlocks = document.querySelectorAll('pre');
  var codeContainer = document.querySelectorAll(".code-container");
  if (codeBlocks && codeContainer.length === 0) {
    codeBlocks.forEach(function (codeBlock) {
      // 创建新的ol元素
      // const ol = document.createElement('ol');
      // // 获取所有<code>标签中的文本行
      // const codeLines = codeBlock.textContent.split('\n');
      // // 移除<pre>中的所有内容
      // codeBlock.innerHTML = '';
      // // 为每行代码添加序号并重新添加到<pre>中
      // codeLines.forEach((line, index) => {
      //     const lineNumber = index + 1;
      //     const lineElement = document.createElement('li');
      //     lineElement.textContent = `${line}`;//${lineNumber}. 
      //     ol.appendChild(lineElement);
      //     // codeBlock.innerHTML = `<ol><li>${codeBlock.innerHTML.replace(/\n/g,`</li><li class="line">`)}</li></ol>`;
      // });
      // codeBlock.appendChild(ol);

      var copyButton = document.createElement('span');
      copyButton.className = 'copy';
      copyButton.textContent = '复制代码';

      // 创建包裹代码块和按钮的容器元素
      var container = document.createElement('div');
      container.className = 'code-container';

      // 将按钮添加到容器元素内
      container.appendChild(copyButton);

      // 将容器元素插入到代码块之前
      codeBlock.parentNode.insertBefore(container, codeBlock);

      // 设置容器元素样式,使其定位为相对定位(position: relative)
      container.style.position = 'relative';

      // 设置复制按钮样式,使其绝对定位于容器元素的右上角
      copyButton.style.position = 'absolute';
      copyButton.style.top = '3px';
      copyButton.style.right = '6px';

      copyButton.addEventListener('click', function () {
        // 获取代码块的文本内容textContent
        var code = codeBlock.innerText;

        if (navigator.clipboard && window.isSecureContext) {
          try {
            navigator.clipboard.writeText(code).then(() => {
              // 修改复制按钮文本为"已复制"
              this.textContent = '复制成功';
            }).catch(() => {
              this.textContent = '复制失败';
            });
          } catch (err) {
            this.textContent = '复制失败';
          }
        } else {
          // 创建一个临时的textarea元素,并将代码块的内容设置为其值
          var textarea = document.createElement('textarea');
          textarea.value = code;
          // 将textarea元素追加到body中
          document.body.appendChild(textarea);
          // 选中textarea中的文本
          textarea.select();
          // 执行复制操作
          document.execCommand('copy');
          // 移除临时的textarea元素
          document.body.removeChild(textarea);
          this.textContent = '复制成功';
        }
        //一定时间后吧按钮名改回来
        setTimeout(() => {
          this.textContent = "复制代码";
        }, 1800);
      });
    });
  }

  if (document.getElementById("copy-code-styles")) return; // 避免重复添加样式
  const css = `
  .code-wrapper {
    position: relative;
  }

  .code-block {
    position: relative;
  }

  .copy {
    font-size: 13px;
    transition: color 0.1s;
    color: hsl(165.03deg 19.14% 92.37% / 97%);
    background: #1b45bede;
    padding: 0 3px;
    border: none;
    border-radius: 4px;
    cursor: pointer;
    z-index: 1;
  }`;
  const style = document.createElement("style");
  style.id = "copy-code-styles";
  style.textContent = css;
  document.head.appendChild(style);
}());
相关推荐
她似晚风般温柔7893 小时前
Uniapp + Vue3 + Vite +Uview + Pinia 分商家实现购物车功能(最新附源码保姆级)
开发语言·javascript·uni-app
Jiaberrr4 小时前
前端实战:使用JS和Canvas实现运算图形验证码(uniapp、微信小程序同样可用)
前端·javascript·vue.js·微信小程序·uni-app
everyStudy4 小时前
JS中判断字符串中是否包含指定字符
开发语言·前端·javascript
Ylucius5 小时前
动态语言? 静态语言? ------区别何在?java,js,c,c++,python分给是静态or动态语言?
java·c语言·javascript·c++·python·学习
200不是二百5 小时前
Vuex详解
前端·javascript·vue.js
滔滔不绝tao5 小时前
自动化测试常用函数
前端·css·html5
LvManBa5 小时前
Vue学习记录之三(ref全家桶)
javascript·vue.js·学习
深情废杨杨5 小时前
前端vue-父传子
前端·javascript·vue.js
司篂篂7 小时前
axios二次封装
前端·javascript·vue.js
姚*鸿的博客7 小时前
pinia在vue3中的使用
前端·javascript·vue.js