Uczymy się korzystać z nowego clipboard API dostępnego teraz w obiekcie navigator. Plus pewne sztuczki z setTimeout i prostym efektem pokazującym, że element został skopiowany do schowka.
Oto nasz markup HTMLowy:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<p id="lorem">Lorem ipsum dolor sit amet consectetur, adipisicing elit. Sint molestias quis ut perspiciatis ullam, voluptate modi possimus, non repellendus ratione esse eius! Recusandae rerum, exercitationem vero ratione vitae doloremque vel!</p>
<button id="copyBtn">Kopiuj</button>
<script>
window.addEventListener('DOMContentLoaded', function(){
});
</script>
</body>
</html>
Mamy tutaj paragraf z „lorem ipsum” oraz przycisk kopiuj i skrypt. Napiszemy teraz kod wykorzystujący nowy clipboard API z obiektu navigator do przekopiowania tekstu z paragrafu do schowka. Na początek – łapiemy nasze elementy:
window.addEventListener('DOMContentLoaded', function(){
let btn = document.querySelector('#copyBtn');
let para = document.querySelector('#lorem');
Zaczniemy trochę od końca, bowiem napiszemy sobie funkcję buttonEffect, która zamienia tekst przycisku na „Copied!” (na 1.5 sekundy):
function buttonEffect() {
btn.textContent = 'Copied!';
setTimeout(() => {
btn.textContent = "Kopiuj";
}, 1500);
}
buttonEffect();
Po wywołaniu i sprawdzeniu, że działa warto sobie wywołanie buttonEffect zakomentować albo usunąć. Teraz piszemy event-listener dla naszego przycisku, wykorzystujący navigator clipboard API:
btn.addEventListener('click', function(){
navigator.clipboard.writeText(lorem.textContent)
.then(() => {
buttonEffect()
})
.catch(err => {
console.error('Failed to copy text: ', err);
});
});
Działa jak należy. Możemy teraz jeszcze usprawnić sobie buttonEffect – na przykład zablokować możliwość wciskania przycisku przez 1.5 sekundy:
function buttonEffect() {
btn.textContent = 'Copied!';
btn.setAttribute('disabled', true);
setTimeout(() => {
btn.textContent = "Kopiuj";
btn.removeAttribute('disabled');
}, 1500);
}
Nie jest to idealne rozwiązanie – ale działa. Mi chodziło o coś, co sprawiłoby, że po pierwszym wciśnięciu, gdy jeszcze mamy tekst 'Copied1′ zamiast 'Kopiuj’, przez te 1.5 sekundy użytkownik nie może klikać dalej kolejkując kolejne timeouty. Można to osiągnąć na inny sposób:
let timeoutID = null;
function buttonEffect() {
btn.textContent = 'Copied!';
if(timeoutID)
clearTimeout(timeoutID);
timeoutID = setTimeout(() => {
btn.textContent = "Kopiuj";
}, 1500);
}
Jeżeli czujemy się bardzo pewnie, możemy spróbować napisać jakąś animację korzystając z Web Animations API. Ja na szybko coś takiego stworzyłem:
function buttonEffect() {
btn.textContent = 'Copied!';
if(timeoutID)
clearTimeout(timeoutID);
timeoutID = setTimeout(() => {
btn.textContent = "Kopiuj";
}, 800);
btn.animate([
{transform: "scale(1)"},
{transform: "scale(1.4)"},
{transform: "scale(1)"},
], {duration: 200, iterations: 1});
}
Zaczynamy z wielkości normalnej, powiększamy guzik do 1.4 jego oryginalnej wielkości i wracamy, wszystko trwa 200ms, powtórzone 1 raz. O Web Animations API też coś napiszemy w przyszłości, na razie niech nam wystarczy ten przykład.