2
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?

Clipboard APIで実装するコピー&ペースト機能

2
Posted at

この記事は、ラクスパートナーズ AdventCalendar 2025の5日目の記事です。
(個人で25日連続投稿にチャレンジ中のカレンダーになります)


Web APIのClipboard APIを使ってコピー&ペースト機能を実装する方法をまとめてみました。
(コードはVue.jsのComposition APIのものになります)

HTTPSでないとClipboard APIを利用できないことに注意が必要です(localhostは除きます)。

テキストのコピー&ペースト

まずは、よく見るテキストのコピー&ペースト機能です。

テキストのコピー&ペースト
<script setup>
import { ref } from 'vue'

const text = ref('')

const onCopyText = () => navigator.clipboard.writeText(text.value)

const onPasteText = () => {
  navigator.clipboard.readText().then((clipText) => {
    text.value = clipText
  })
}
</script>

<template>
    <div>
        <input type="text" v-model="text" />
        <button type="button" @click="onCopyText">
            コピー
        </button>
        <button type="button" @click="onPasteText">
          ペースト
        </button>
    </div>
</template>

navigator.clipboard.writeText('コピーしたいテキスト')は、指定したテキストをクリップボードに書き込みます。
navigator.clipboard.readText()は、クリップボードにアクセスし、取得したデータをPromiseオブジェクトで返却します(そのため、thenやasync/awaitで受け取る必要あり)。

上記のコードでは、inputタグに入力したテキストをコピーしたり、逆にinputへコピーした内容をペーストしています。

readText()実行時に、クリップボードへのアクセス権限を許可を求めるポップアップが表示されます(clipboard-read権限の要求)。
こちらを拒否するとペーストすることができません。

画像のコピー&ペースト

画像などの任意のデータをコピー&ペーストすることもできます。
(ほぼMDNのサンプルコードの通りに書いただけですが、例は以下です)

<script setup>
import { ref } from 'vue'
import sampleImage from '@/assets/sample.png'

const imageUrl = sampleImage
const readImage = ref(null)

const onCopyImage = async () => {
  try {
    const blob = await fetch(imageUrl).then((res) => res.blob());

    const item = new ClipboardItem({
      [blob.type]: blob,
    });

    // クリップボードへ書き込む
    await navigator.clipboard.write([item]);
  } catch (e) {
    console.error(e);
  }
};

const onPasteImage = async () => {
  try {
    const items = await navigator.clipboard.read();

    for (const item of items) {
      for (const type of item.types) {
        if (type.startsWith('image/')) {
          const blob = await item.getType(type);

          readImage.value = URL.createObjectURL(blob);
          return;
        }
      }
    }
  } catch (e) {
    console.error(e);
  }
};
</script>

<template>
  <div>
    <div>
      <button @click="onCopyImage">
        画像をコピー
      </button>
      <button @click="onPasteImage">
        画像をペースト
      </button>
    </div>
    <br>
    <div v-if="readImage">
      <img :src="readImage" width="200" />
    </div>
  </div>
</template>

クリップボードへのデータの書き込みにはnavigator.clipboard.write()
クリップボードへのアクセスにはnavigator.clipboard.read()
を使用します。

コピーの処理の流れは以下です。

  1. fetchで画像を取得し、Blob(画像など様々なデータを扱えるオブジェクト)にする
  2. ClipboardItemオブジェクトを作成し、Blobにした画像データを渡す
  3. navigator.clipboard.writeにClipboardItemオブジェクトを渡して、クリップボードに書き込み完了

ペーストの処理の流れは以下です。

  1. navigator.clipboard.read()でクリップボードにアクセス
  2. typeが「image/」で始まるものを探す
  3. ClipboardオブジェクトのgetType()メソッドでBlobオブジェクトを返す
  4. 受け取ったBlobオブジェクトを元に、URL.createObjectURLで画像URLを生成
  5. 生成した画像URLをimgタグのsrc属性に指定し、画像が表示される

read()実行時も、clipboard-read権限を要求するポップアップが表示されます。
こちらも拒否した場合はペーストできません。


以上となります。

テキストのコピー&ペーストはよく実装していたのですが、画像などのデータのコピー&ペーストもClipboard APIで実装できるとは知らず、勉強になりました。是非業務でも活かしていきたいと思います。

ここまで読んでくださり、ありがとうございました。

2
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
2
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?