0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Markdown表示のコードスニペットのコピー機能をNuxt.jsアプリに実装してみる

Posted at

ソースコードシンタックスハイライトに対応した前回の記事の続きで、今回はコードをクリップボードにコピーする機能を追加します。

ちょうどいいパッケージを探したのですが、見つかったパッケージは長らくメンテされてないようで、試したのですが動きませんでした。ほかに見つからなかったので、結局フルスクラッチで書きました。

HTMLの中で $md.render(content) と書いていたところを renderMarkdown(content) に置き換えて、 renderMarkdown を独自実装することで対応させます。

<div class="markdown" v-html="renderMarkdown(content)"></div>

Markdownで生成したDOM要素に対して、クリックイベントなどを拾えるようにする初期設定を renderMarkdown の中から呼び出します。

  methods: {
    renderMarkdown(text) {
      setTimeout(() => {
        this.initializeMarkdownDOM();
      }, 10);
      return this.$md.render(text);
    },
    initializeMarkdownDOM() {
      document.querySelectorAll('.markdown pre').forEach((preElement) => {
        if (preElement.dataset.initialized) {
          return;
        }
        preElement.dataset.initialized = "true";
        this.initializeMarkdownCodeBlock(preElement);
      });
    },
    initializeMarkdownCodeBlock(preElement) {
      const buttonAreaElem = document.createElement("div");
      buttonAreaElem.classList.add("btn-area");
      buttonAreaElem.style.display = "none";
      preElement.insertAdjacentElement("afterbegin", buttonAreaElem);

      const copyButton = document.createElement("a");
      copyButton.innerHTML = '<i aria-hidden="true" class="v-icon notranslate mdi mdi-content-copy theme--dark primary--text"></i>';
      copyButton.href = "#";
      copyButton.addEventListener("click", (event) => {
        event.preventDefault();
        const codeElem = preElement.querySelector("code");
        const text = codeElem.innerText;
        this.copyToClipboard(text);
      });
      buttonAreaElem.insertAdjacentElement("beforeend", copyButton);

      preElement.addEventListener("mouseenter", () => {
        buttonAreaElem.style.display = "block";
      });
      preElement.addEventListener("mouseleave", () => {
        buttonAreaElem.style.display = "none";
      });
    },
    copyToClipboard(text) {
      navigator.clipboard.writeText(text);
    },
  },

CSSには以下を加えます。これはコピーボタンを <pre> エリアの右上に配置するための記述です。

.markdown pre {
  position: relative;
}
.markdown pre .btn-area {
  position: absolute;
  box-sizing: border-box;
  width: 100%;
  padding-right: 10px;
  text-align: right;
}

これで、コード上にマウスカーソルを乗せたときに右上にコピーボタンが現れ、クリックするとクリップボードにコードがコピーされます。

image.png

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?