Hugo添加代码复制功能

点击按钮复制 #

JS部分 #

位置:./themes/YourThemeName/static/clipboard.js

// buttons
const svgCopy =
  '<svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true"><path fill-rule="evenodd" d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 010 1.5h-1.5a.25.25 0 00-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 00.25-.25v-1.5a.75.75 0 011.5 0v1.5A1.75 1.75 0 019.25 16h-7.5A1.75 1.75 0 010 14.25v-7.5z"></path><path fill-rule="evenodd" d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0114.25 11h-7.5A1.75 1.75 0 015 9.25v-7.5zm1.75-.25a.25.25 0 00-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 00.25-.25v-7.5a.25.25 0 00-.25-.25h-7.5z"></path></svg>';
const svgCheck =
  '<svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true"><path fill-rule="evenodd" d="M13.78 4.22a.75.75 0 010 1.06l-7.25 7.25a.75.75 0 01-1.06 0L2.22 9.28a.75.75 0 011.06-1.06L6 10.94l6.72-6.72a.75.75 0 011.06 0z"></path></svg>';
// add button function
const addCopyButtons = (clipboard) => {
    // 1. Look for pre > code elements in the DOM
    document.querySelectorAll("pre > code").forEach((codeBlock) => {
      // 2. Create a button that will trigger a copy operation
      const button = document.createElement("button");
      button.className = "copy-code-button";
      button.type = "button";
      button.title = "Copy";
      button.innerHTML = svgCopy;
      button.addEventListener("click", () => {
        clipboard.writeText(codeBlock.innerText).then(
          () => {
            button.blur();
            button.innerHTML = svgCheck;
            setTimeout(() => (button.innerHTML = svgCopy), 2000);
          },
          (error) => (button.innerHTML = "Error")
        );
      });
      // 3. Append the button after the pre tag (.highlight > pre > button > code)
      const pre = codeBlock.parentNode;
      pre.parentNode.insertBefore(button, pre.nextSibling);
      // 4. Listen to keyboard press
      const highlight = pre.parentNode;
      highlight.addEventListener('keydown', function(event) {
        if (
          event.key === " " ||
          event.key === "Spacebar" ||
          event.code === "Space" ||
          event.key === "Enter" ||
          event.code === "Enter"
        ) {
          clipboard.writeText(codeBlock.innerText).then(
            () => {
              button.blur();
              button.innerHTML = svgCheck;
              setTimeout(() => (button.innerHTML = svgCopy), 2000);
            },
            (error) => (button.innerHTML = "Error")
          );
        }
      });
    });
  };
// trigger function
if (navigator && navigator.clipboard) {
  addCopyButtons(navigator.clipboard);
} else {
  const script = document.createElement("script");
  script.src =
    "https://cdnjs.cloudflare.com/ajax/libs/clipboard-polyfill/3.0.3/promise/clipboard-polyfill.promise.min.js";
  script.integrity = "sha512-O9Q+AhI1w7LT1/tHysPWDwwrgB1fKJ/nXPNLC30i8LF6RdSz4dGZyWB9WySag3DZMdGuK5yHJEdKXMKI2m5uSQ==";
  script.crossOrigin = "anonymous";
  script.referrerpolicy = "no-referrer";
  script.onload = () => addCopyButtons(clipboard);
  document.body.appendChild(script);
}

Hugo处理部分 #

位置:./themes/YourThemeName/layouts/partials/footer.html

{{ if (findRE "<code" .Content 1) }}
    <script src="{{"/js/clipboard.js" | relURL}}"></script>
{{ end }}

CSS部分 #

.highlight {
    position: relative;
  }
  .copy-code-button {
    color: var(--white);
    background-color: rgba(255,255,255,50%);
    border: none;
    border-radius: 6px;
    padding: 5px;
    font-size: 1rem;
    position: absolute;
    z-index: 1;
    right: 0;
    top: 0;
    margin: 10px;
    transition: .1s;
    opacity: 0.5;
  }
  .copy-code-button > svg {
    fill: var(--white);
  }
  .copy-code-button:hover,
  .copy-code-button:focus,
  pre:active ~ .copy-code-button,
  pre:focus ~ .copy-code-button,
  div.highlight:active > .copy-code-button,
  div.highlight:focus > .copy-code-button {
    cursor: pointer;
    opacity: 1;
  }

点击代码块复制 #

JS部分 #

位置:./themes/YourThemeName/assets/clipboard.js

(function () {
  function select(element) {
    const selection = window.getSelection();

    const range = document.createRange();
    range.selectNodeContents(element);

    selection.removeAllRanges();
    selection.addRange(range);
  }

  document.querySelectorAll("pre code").forEach(code => {
    code.addEventListener("click", function (event) {
      if (window.getSelection().toString()) {
        return;
      }
      select(code.parentElement);

      if (navigator.clipboard) {
        navigator.clipboard.writeText(code.parentElement.textContent);
      }
    });
  });
})();

Hugo处理部分 #

位置:./themes/YourThemeName/layouts/partials/footer.html

{{ $script := resources.Get "clipboard.js" | resources.Minify }}
{{ with $script.Content }}
  <script>{{ . | safeJS }}</script>
{{ end }}