재우니의 블로그

 

 

문제

 

JavaScript에서 클립보드에 복사하려고 합니다. 어느 사용자가 버튼을 클릭할 때 텍스트 또는 이미지 스니펫을 복사하도록 허용하려고 합니다. 어떻게 해야 할까요?

 

 

해결책:

 

현대 브라우저만 지원해도 된다면 Clipboard Web API를 사용하세요. 이를 통해 시스템 클립보드에서 비동기적으로 읽고 쓸 수 있습니다. 네비게이터 전역 인터페이스를 통해 시스템 클립보드에 액세스할 수 있습니다.

Clipboard API는 비교적 새로운 기술이며 여러 브라우저에 통합이 아직 진행 중입니다. 기술적 문제와 잠재적 보안 문제로 인해 여러 브라우저에서 Clipboard API 메서드의 브라우저 호환성을 확인할 수 있습니다.

 

Clipboard API는 이전의 Web API document.execCommand 메서드의 대체품입니다. document.execCommand 메서드를 사용하지 않는 것이 권장되며 이 메서드는 언제든지 작동을 중단할 수 있습니다. 오래된 브라우저나 특정 브라우저의 Clipboard 메서드를 지원해야 하는 경우 clipboard-polyfill 라이브러리를 사용할 수 있습니다. 또한 이 예제 대체 기능을 시도해볼 수도 있습니다.

 

대부분의 브라우저에서 Clipboard API는 텍스트와 이미지를 처리하는 데로 제한되어 있습니다. 브라우저는 일반적으로 보안 조치로 복사된 클립보드 데이터를 정리합니다. 예를 들어 내장된 스크립트 요소를 제거합니다. Chrome 버전 104 이상에서는 Web 사용자 지정 형식이 지원되어 개발자가 클립보드에 정제되지 않은 데이터를 작성할 수 있습니다. 클립보드에 비정제 데이터를 가지는 경우에 유용한 경우도 있습니다:

 

  1. 응용 프로그램이 자체적으로 정리해야 하는 경우
  2. 복사된 데이터가 붙여넣은 데이터와 동일해야 하는 경우

 

 

이에 대해 더 자세히 알아보려면 다음 기사를 읽어보세요: Async Clipboard API의 Web 사용자 지정 형식.

텍스트를 클립보드에 복사하기: 아래 예제의 copyTextToClipboard 함수는 클립보드에 복사할 텍스트를 인수로 받아 clipboard.writeText() 메서드를 사용하여 텍스트를 클립보드에 복사합니다.

 

 

async function copyTextToClipboard(textToCopy) {
  try {
    if (navigator?.clipboard?.writeText) {
      await navigator.clipboard.writeText(textToCopy);
    }
  } catch (err) {
    console.error(err);
  }
}

 

 

이 비동기 함수는 navigator, navigator.clipboard 및 navigator.clipboard.writeText가 존재하는지 확인하기 위해 try...catch 블록을 사용합니다. 이는 브라우저 호환성을 확인합니다. writeText() 함수는 전달된 텍스트가 클립보드에 성공적으로 복사되었는지에 따라 해결되거나 거부된 Promise를 반환합니다.

 

copyTextToClipboard 함수는 writeText() 함수의 Promise가 해결되거나 거부되기를 기다리는 대신에 Promise를 반환하도록 작성할 수 있습니다:

 

 

function copyTextToClipboard(textToCopy) {
  if (navigator?.clipboard?.writeText) {
    return navigator.clipboard.writeText(textToCopy);
  }
  return Promise.reject('The Clipboard API is not available.');
}

 

 

이 함수는 클립보드의 내용이 업데이트된 경우에 해결되는 Promise를 반환합니다.

writeText() 메서드를 호출하려면 사용자가 최근에 페이지와 상호 작용해야 합니다. 일시적 사용자 활성화가 필요합니다. 예를 들어 사용자가 copyTextToClipboard 함수를 호출하는 버튼을 클릭한 경우입니다. 이것은 악성 코드가 API를 남용하는 것을 방지하는 보안 기능입니다. 클립보드로 복사는 사용자가 페이지와 상호 작용할 때만 발생해야 합니다.

텍스트를 클립보드에 쓰려면 페이지는 HTTPS로 제공되어야 하며, 권한 API의 실험적인 "clipboard-write" 권한이 필요합니다. 이 권한은 브라우저 권한을 지원하는 브라우저에서 자동으로 페이지에 부여됩니다. 권한 API는 "clipboard-read" 및 "clipboard-write" 권한 상태를 결정하기 위해 쿼리될 수 있습니다.

 

 

 

Clipboard 에 이미지 복사하기

 

Clipboard write() 메서드는 이미지와 같은 임의의 데이터를 클립보드에 작성합니다. 이 메서드는 클립보드에 작성될 데이터를 포함하는 ClipboardItem 객체의 배열을 인수로 받습니다. 이미지를 클립보드에 쓰려면 이미지를 blob 형식으로 가지고 있어야 합니다. 서버에서 가져온 이미지와 같은 이미지 URL을 blob으로 변환하려면 fetch()를 사용하여 이미지를 가져오고 응답에서 blob() 메서드를 호출합니다. 또한 이미지를 캔버스에 그리고 캔버스 요소의 toBlob() 메서드를 사용하여 이미지 blob을 생성할 수도 있습니다.

아래의 copyImgToClipboard 함수는 fetch()와 blob() 메서드를 사용하여 이미지 URL에서 이미지를 클립보드로 복사합니다:

 

async function copyImgToClipboard(imgUrl) {
  try {
    const data = await fetch(imgUrl);
    const blob = await data.blob();
    await navigator.clipboard.write([
      new ClipboardItem({
        [blob.type]: blob,
      }),
    ]);
    console.log('Image copied.');
  } catch (err) {
    console.error(err.name, err.message);
  }
}

 

 

이 함수를 Safari 브라우저에서 작동하도록 수정해야 합니다. 이에 관한 자세한 내용은 다음 기사에서 확인할 수 있습니다: 

 

Unblocking clipboard access.

 

Safari 브라우저에서 클립보드 액세스를 언블록하는 방법에 대한 정보를 참고하여 함수를 수정할 수 있습니다. 주로 Safari에서는 클립보드 액세스에 대한 추가적인 사용자 상호 작용이 필요할 수 있습니다. Safari의 정책과 요구 사항을 따르도록 코드를 수정해야 합니다.

 

 


 

구현해 본  vue.js 의 cdn 코드

 

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Vue Clipboard Example</title>
  <!-- Add Vue.js CDN -->
  <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
</head>
<body>

<div id="app">
  <ul>
    <!-- Loop through your list and create a click event for each item -->
    <li v-for="(item, index) in myList" :key="index" @click="copyToClipboard(item)">
      {{ item }}
    </li>
  </ul>
</div>

<script>
new Vue({
  el: '#app',
  data: {
    myList: ['Item 1', 'Item 2', 'Item 3'] // Replace with your list data
  },
  methods: {
    async copyToClipboard(text) {
      try {
        // Copy the text using the Clipboard API
        await navigator.clipboard.writeText(text);

        // You can add some visual feedback or notification here
        alert(`Copied: ${text}`);
      } catch (err) {
        console.error('Failed to copy text: ', err);
      }
    }
  }
});
</script>

</body>
</html>