Sistem panosuna erişmenin geleneksel yolu şuydu: document.execCommand()
Pano etkileşimleri için. Geniş çapta desteklenmesine rağmen, bu kesme ve yapıştırma yönteminin bir bedeli vardı: Pano erişimi senkronizeydi ve yalnızca DOM’u okuyup yazabiliyordu.
Bu, küçük metin parçaları için iyidir, ancak panoya aktarım için sayfayı engellemenin kötü bir deneyim olduğu birçok durum vardır. İçeriğin güvenli bir şekilde yapıştırılabilmesi için zaman alıcı temizleme veya görüntü çözme işlemleri gerekebilir. Tarayıcının yapıştırılan bir belgeden bağlantılı kaynakları yüklemesi veya satır içi yapması gerekebilir. Bu, diskte veya ağda beklerken sayfayı engeller. Karışıma, tarayıcının pano erişimi isterken sayfayı engellemesini gerektiren izinler eklediğinizi hayal edin. Aynı zamanda, etrafında yer alan izinler document.execCommand()
pano etkileşimi için genel olarak tanımlanmıştır ve tarayıcılar arasında değişiklik gösterir.
bu Eşzamansız Pano API’sı sayfayı engellemeyen iyi tanımlanmış bir izin modeli sağlayarak bu sorunları giderir. Zaman Uyumsuz Pano API’si, çoğu tarayıcıda metin ve resimleri işlemekle sınırlıdır, ancak destek değişiklik gösterir. Aşağıdaki bölümlerin her biri için tarayıcı uyumluluğuna genel bakışı dikkatle incelediğinizden emin olun.
Kopyala: verileri panoya yazma #
Metin yaz() #
Pano çağrısına metin kopyalamak için writeText()
. Bu API eşzamansız olduğundan, writeText()
işlevi, iletilen metnin başarıyla kopyalanıp kopyalanmadığına bağlı olarak çözümleyen veya reddeden bir Promise döndürür:
async function copyPageUrl() {
try {
await navigator.clipboard.writeText(location.href);
console.log('Page URL copied to clipboard');
} catch (err) {
console.error('Failed to copy: ', err);
}
}
- Chrome 66, Desteklenir 66
- Firefox 63, Desteklenir 63
- Kenar 79, Desteklenen 79
- Safari 13.1, Desteklenir 13.1
yazmak() #
Aslında, writeText()
jenerik için sadece bir kolaylık yöntemidir write()
görüntüleri panoya kopyalamanıza da izin veren yöntem. Beğenmek writeText()
zaman uyumsuzdur ve bir Promise döndürür.
Panoya bir resim yazmak için, resmin bir blob
. Bunu yapmanın bir yolu, görüntüyü kullanarak bir sunucudan istemektir. fetch()
ardından arama blob()
yanıt üzerinde.
Sunucudan bir görüntü talep etmek, çeşitli nedenlerle istenmeyebilir veya mümkün olmayabilir. Neyse ki, görüntüyü bir tuvale de çizebilir ve tuvale ‘ toBlob()
yöntem.
Ardından, bir dizi geçirin ClipboardItem
nesneleri bir parametre olarak write()
yöntem. Şu anda bir defada yalnızca bir resim iletebilirsiniz, ancak gelecekte birden fazla resim için destek eklemeyi umuyoruz. ClipboardItem
Anahtar olarak görüntünün MIME türü ve değer olarak blob ile bir nesne alır. Şuradan elde edilen blob nesneleri için: fetch()
veya canvas.toBlob()
, blob.type
özelliği, bir görüntü için doğru MIME türünü otomatik olarak içerir.
try {
const imgURL = '/images/generic/file.png';
const data = await fetch(imgURL);
const blob = await data.blob();
await navigator.clipboard.write([
new ClipboardItem({
// The key is determined dynamically based on the blob's type.
[blob.type]: blob
})
]);
console.log('Image copied.');
} catch (err) {
console.error(err.name, err.message);
}
Alternatif olarak, bir taahhüt yazabilirsiniz. ClipboardItem
nesne. Bu model için önceden verinin MIME türünü bilmeniz gerekir.
try {
const imgURL = '/images/generic/file.png';
await navigator.clipboard.write([
new ClipboardItem({
// Set the key beforehand and write a promise as the value.
'image/png': fetch(imgURL).then(response => response.blob()),
})
]);
console.log('Image copied.');
} catch (err) {
console.error(err.name, err.message);
}
- Chrome 66, Desteklenir 66
- Firefox 87, Bir bayrağın arkasında
- Kenar 79, Desteklenen 79
- Safari 13.1, Desteklenir 13.1
kopyalama olayı #
Bir kullanıcının panoya kopyalama başlatması ve Olumsuz Arama preventDefault()
, copy
etkinlik içerir clipboardData
zaten doğru biçimde olan öğelerle özellik. Kendi mantığınızı uygulamak istiyorsanız, aramanız gerekir. preventDefault()
kendi uygulamanızın lehine varsayılan davranışı önlemek için. Bu durumda, clipboardData
boş olacak Metin ve resim içeren bir sayfa düşünün ve kullanıcı tümünü seçip panoya kopyalamayı başlattığında, özel çözümünüz metni atmalı ve yalnızca resmi kopyalamalıdır. Aşağıdaki kod örneğinde gösterildiği gibi bunu başarabilirsiniz. Bu örnekte ele alınmayan, Pano API’si desteklenmediğinde önceki API’lere nasıl geri dönüleceğidir.
<!-- The image we want on the clipboard. -->
img src="kitten.webp" alt="Cute kitten.">
<!-- Some text we're not interested in. -->
p>Lorem ipsum</p>
document.addEventListener("copy", async (e) => {
// Prevent the default behavior.
e.preventDefault();
try {
// Prepare an array for the clipboard items.
let clipboardItems = [];
// Assume `blob` is the blob representation of `kitten.webp`.
clipboardItems.push(
new ClipboardItem({
[blob.type]: blob,
})
);
await navigator.clipboard.write(clipboardItems);
console.log("Image copied, text ignored.");
} catch (err) {
console.error(err.name, err.message);
}
});
İçin copy
etkinlik:
İçin ClipboardItem
:
- Chrome 76, Desteklenir 76
- Firefox 87, Bir bayrağın arkasında
- Kenar 79, Desteklenen 79
- Safari 13.1, Desteklenir 13.1
Yapıştır: panodan veri okuma #
metni oku() #
Panodan metin okumak için arayın navigator.clipboard.readText()
ve iade edilen sözün çözülmesini bekleyin:
async function getClipboardContents() {
try {
const text = await navigator.clipboard.readText();
console.log('Pasted content: ', text);
} catch (err) {
console.error('Failed to read clipboard contents: ', err);
}
}
Okumak() #
bu navigator.clipboard.read()
yöntem ayrıca eşzamansızdır ve bir söz verir. Panodan bir görüntüyü okumak için bir liste edinin. ClipboardItem
nesneler, ardından üzerlerinde yineleme yapın.
Her biri ClipboardItem
içeriğini farklı türlerde tutabilir, bu nedenle türler listesi üzerinde tekrar bir a kullanarak yinelemeniz gerekir. for...of
döngü. Her tür için getType()
karşılık gelen blob’u elde etmek için geçerli türle bir argüman olarak yöntem. Daha önce olduğu gibi, bu kod resimlere bağlı değildir ve gelecekteki diğer dosya türleriyle çalışacaktır.
async function getClipboardContents() {
try {
const clipboardItems = await navigator.clipboard.read();
for (const clipboardItem of clipboardItems) {
for (const type of clipboardItem.types) {
const blob = await clipboardItem.getType(type);
console.log(URL.createObjectURL(blob));
}
}
} catch (err) {
console.error(err.name, err.message);
}
}
- Chrome 86, Desteklenir 86
- Firefox 90, Bir bayrağın arkasında
- Kenar 79, Desteklenen 79
- Safari 13.1, Desteklenir 13.1
Yapıştırılan dosyalarla çalışma #
Kullanıcıların pano klavye kısayollarını kullanabilmeleri yararlıdır. Ctrl+C Ve Ctrl+v. krom açığa çıkarır Sadece oku Panodaki dosyalar aşağıda belirtildiği gibi. Bu, kullanıcı işletim sisteminin varsayılan yapıştırma kısayoluna bastığında veya kullanıcı tıkladığında tetiklenir. Düzenlemek Daha sonra Yapıştırmak tarayıcının menü çubuğunda. Daha fazla sıhhi tesisat kodu gerekmez.
document.addEventListener("paste", async e => {
e.preventDefault();
if (!e.clipboardData.files.length) {
return;
}
const file = e.clipboardData.files[0];
// Read the file's contents, assuming it's a text file.
// There is no way to write back to it.
console.log(await file.text());
});
- Chrome 3, Desteklenir 3
- Firefox 3.6, Desteklenir 3.6
- Kenar 12, Desteklenen 12
- Safari 4, Desteklenir 4
yapıştırma olayı #
Daha önce belirtildiği gibi, Pano API’si ile çalışmak için etkinlikler sunma planları var, ancak şimdilik mevcut olanı kullanabilirsiniz. paste
etkinlik. Pano metnini okumak için yeni eşzamansız yöntemlerle iyi çalışır. ile olduğu gibi copy
etkinlik, aramayı unutma preventDefault()
.
document.addEventListener('paste', async (e) => {
e.preventDefault();
const text = await navigator.clipboard.readText();
console.log('Pasted text: ', text);
});
- Chrome 1, Desteklenir 1
- Firefox 22, Desteklenir 22
- Kenar 12, Desteklenen 12
- Safari 3, Desteklenir 3
Birden çok MIME türünü işleme #
Çoğu uygulama, tek bir kesme veya kopyalama işlemi için panoya birden çok veri formatı koyar. Bunun iki nedeni vardır: Bir uygulama geliştiricisi olarak, kullanıcının metin veya resim kopyalamak istediği uygulamanın yeteneklerini bilmenin hiçbir yolu yoktur ve birçok uygulama, yapılandırılmış verilerin düz metin olarak yapıştırılmasını destekler. Bu genellikle kullanıcılara bir Düzenlemek gibi bir ada sahip menü öğesi Stili yapıştır ve eşleştir veya biçimlendirmeden yapıştır.
Aşağıdaki örnek bunun nasıl yapılacağını gösterir. Bu örnek kullanır fetch()
Görüntü verilerini elde etmek için, ancak aynı zamanda bir kaynaktan da gelebilir. <canvas>
veya Dosya Sistemi Erişim API’sı.
async function copy() {
const image = await fetch('kitten.png').then(response => response.blob());
const text = new Blob(['Cute sleeping kitten'], {type: 'text/plain'});
const item = new ClipboardItem({
'text/plain': text,
'image/png': image
});
await navigator.clipboard.write([item]);
}
Güvenlik ve izinler #
Pano erişimi, tarayıcılar için her zaman bir güvenlik endişesi oluşturmuştur. Uygun izinler olmadan, bir sayfa her türlü kötü amaçlı içeriği sessizce kullanıcının panosuna kopyalayabilir ve bu yapıştırıldığında feci sonuçlar doğurabilir. Sessizce kopyalayan bir web sayfası hayal edin rm -rf /
veya bir dekompresyon bomba görüntüsü panonuza.
Web sayfalarına panoya sınırsız okuma erişimi vermek daha da zahmetlidir. Kullanıcılar, şifreler ve kişisel ayrıntılar gibi hassas bilgileri rutin olarak panoya kopyalar ve bu bilgiler, kullanıcının bilgisi olmadan herhangi bir sayfa tarafından okunabilir.
Pek çok yeni API’de olduğu gibi, Pano API’si de yalnızca HTTPS üzerinden sunulan sayfalar için desteklenir. Kötüye kullanımı önlemeye yardımcı olmak için, pano erişimine yalnızca bir sayfa etkin sekme olduğunda izin verilir. Etkin sekmelerdeki sayfalar izin istemeden panoya yazabilir, ancak panodan okumak her zaman izin gerektirir.
Kopyalama ve yapıştırma izinleri eklendi. İzinler API’sı. bu clipboard-write
etkin sekme olduklarında sayfalara otomatik olarak izin verilir. bu clipboard-read
panodan veri okumaya çalışarak yapabileceğiniz izin istenmelidir. Aşağıdaki kod ikincisini gösterir:
const queryOpts = { name: 'clipboard-read', allowWithoutGesture: false };
const permissionStatus = await navigator.permissions.query(queryOpts);
// Will be 'granted', 'denied' or 'prompt':
console.log(permissionStatus.state);// Listen for changes to the permission state
permissionStatus.onchange = () => {
console.log(permissionStatus.state);
};
Ayrıca kesmeyi veya yapıştırmayı başlatmak için bir kullanıcı hareketinin gerekip gerekmediğini kontrol edebilirsiniz. allowWithoutGesture
seçenek. Bu değer için varsayılan, tarayıcıya göre değişir, bu nedenle her zaman eklemelisiniz.
Pano API’sinin eşzamansız doğasının gerçekten işe yaradığı yer burasıdır: Pano verilerini okumaya veya yazmaya çalışmak, önceden verilmemişse kullanıcıdan otomatik olarak izin ister. API taahhüt tabanlı olduğundan, bu tamamen şeffaftır ve pano iznini reddeden bir kullanıcı, sayfanın uygun şekilde yanıt verebilmesi için taahhüdün reddedilmesine neden olur.
Tarayıcılar yalnızca bir sayfa etkin sekme olduğunda pano erişimine izin verdiğinden, geliştirici araçlarının kendileri etkin sekme olduğundan, buradaki örneklerin bazılarının doğrudan tarayıcının konsoluna yapıştırıldığında çalışmadığını göreceksiniz. Bir numara var: kullanarak pano erişimini erteleyin setTimeout()
ardından işlevler çağrılmadan önce odaklanmak için sayfanın içine hızlıca tıklayın:
setTimeout(async () => {
const text = await navigator.clipboard.readText();
console.log(text);
}, 2000);
İzin ilkesi entegrasyonu #
API’yi iframe’lerde kullanmak için şununla etkinleştirmeniz gerekir: İzin Politikası, çeşitli tarayıcı özelliklerini ve API’leri seçerek etkinleştirmeye ve devre dışı bırakmaya izin veren bir mekanizmayı tanımlar. Somut olarak, birini veya her ikisini birden geçmeniz gerekir. clipboard-read
veya clipboard-write
uygulamanızın ihtiyaçlarına bağlı olarak.
iframe
src="index.html"
allow="clipboard-read; clipboard-write"
>
</iframe>
Özellik algılama #
Async Clipboard API’yi tüm tarayıcıları desteklerken kullanmak için şunu test edin: navigator.clipboard
ve önceki yöntemlere geri dönün. Örneğin, diğer tarayıcıları dahil etmek için yapıştırmayı şu şekilde uygulayabilirsiniz.
document.addEventListener('paste', async (e) => {
e.preventDefault();
let text;
if (navigator.clipboard) {
text = await navigator.clipboard.readText();
}
else {
text = e.clipboardData.getData('text/plain');
}
console.log('Got pasted text: ', text);
});
Bütün hikaye bu değil. Zaman Uyumsuz Pano API’sinden önce, web tarayıcıları arasında farklı kopyala ve yapıştır uygulamalarının bir karışımı vardı. Çoğu tarayıcıda, tarayıcının kendi kopyalama ve yapıştırma özelliği kullanılarak tetiklenebilir. document.execCommand('copy')
Ve document.execCommand('paste')
. Kopyalanacak metin DOM’da olmayan bir dize ise, DOM’a eklenmeli ve seçilmelidir:
button.addEventListener('click', (e) => {
const input = document.createElement('input');
input.style.display = 'none';
document.body.appendChild(input);
input.value = text;
input.focus();
input.select();
const result = document.execCommand('copy');
if (result === 'unsuccessful') {
console.error('Failed to copy text.');
}
input.remove();
});
Demolar #
Async Clipboard API ile aşağıdaki demolarda oynayabilirsiniz. Glitch’te remix yapabilirsiniz metin demosu veya görüntü demosu Onlarla deney yapmak için.
İlk örnek, hareketli metni panoda ve panodan gösterir.
API’yi resimlerle denemek için bu demoyu kullanın. Yalnızca PNG’lerin desteklendiğini ve yalnızca birkaç tarayıcı.
teşekkürler #
Eşzamansız Pano API’si tarafından uygulandı Darwin Huang Ve Gary Kaçmarcik. Darwin demoyu da sağladı. Sayesinde Kyarik ve yine bu makalenin bölümlerini gözden geçirdiği için Gary Kačmarčík.
Kahraman görseli Markus Winkler Açık Unsplash.