Metin ve resimler için daha güvenli, engelsiz pano erişimi
Sistem panosuna erişmek için geleneksel olarak kullanılan yöntem
document.execCommand()
kullanabilirsiniz. Bu yöntem geniş çapta desteklense de,
yapıştırmanın bir maliyeti vardı: pano erişimi eşzamanlıydı ve yalnızca okuyabiliyordu
DOM'ye yazmam gerekecek.
Küçük boyutlu metinlerde sorun yoktur ancak
sayfası kötü bir deneyim. Zaman alan arındırma ya da
İçeriğin güvenli bir şekilde yapıştırılabilmesi için resim kodunun çözülmesi gerekebilir. Tarayıcı
yapıştırılan bir dokümandan bağlantılı kaynakları yüklemesi veya satır içine alması gerekebilir. Bu,
diskte veya ağda beklerken sayfayı engelleyebilir. Yeni bir web sitesi için
Buna, istekte bulunurken tarayıcının sayfayı engellemesi gerekir.
pano erişimi. Aynı zamanda, uygulamalar konusundaki izinler
Pano etkileşimi için document.execCommand()
genel olarak tanımlanmıştır ve değişiklik gösterir
yardımcı olabilir.
İlgili içeriği oluşturmak için kullanılan Eşzamansız Pano API'si Bu sorunlara çözüm sunar ve sayfayı engelleyebilirsiniz. Eş zamansız Clipboard API'si, metin ve resimleri işleme ile sınırlıdır çoğu tarayıcıda çalışır; ancak destek farklılık gösterir. Tarayıcınızı dikkatli bir şekilde inceleyin uyumluluk özetine göz atabilirsiniz.
Kopyala: panoya veri yazma
writeText()
Metni panoya kopyalamak için writeText()
komutunu çağırın. Bu API,
eşzamansızsa writeText()
işlevi,
isteği, geçirilen metnin başarılı bir şekilde kopyalanıp kopyalanmadığına bağlı olarak reddedilir:
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);
}
}
write()
Aslında, writeText()
yalnızca genel write()
için kolaylık yöntemidir
yöntemini kullanarak aynı zamanda resimleri panoya da kopyalayabilirsiniz. writeText()
gibi,
eşzamansızdır ve bir Promise döndürür.
Panoya bir resim yazmak için resmin
blob
. Bunu yapmanın
Bunun için fetch()
kullanarak bir sunucudan resim isteyip
blob()
tıklayın.
Sunucudan resim istenmesi,
çeşitli nedenleri vardır. Neyse ki resmi tuvale çizebilir ve
tuvali çağır
toBlob()
yöntemidir.
Sonra, write()
öğesine parametre olarak bir ClipboardItem
nesne dizisini iletin.
yöntemidir. Şu anda tek seferde yalnızca bir resim iletebilirsiniz ancak
gelecekte birden fazla resim desteği sunabilir. ClipboardItem
, şununla bir nesneyi alıyor:
resmin MIME türünü anahtar ve değer olarak blob'u seçin. Blob için
fetch()
veya canvas.toBlob()
, blob.type
özelliğinden alınan nesneler
otomatik olarak bir resim için doğru MIME türünü 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, ClipboardItem
nesnesine bir taahhüt yazabilirsiniz.
Bu kalıp için önceden verilerin 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);
}
.
Kopyalama etkinliği
Kullanıcının bir pano kopyası başlatması durumunda
ve preventDefault()
çağrılamazsa
copy
etkinlik
, öğelerin zaten doğru biçimde olduğu bir clipboardData
özelliği içerir.
Kendi mantığınızı uygulamak istiyorsanız preventDefault()
öğesini çağırmanız gerekir:
kendi uygulamanızın lehine ilerlemesini önlemek için
Bu durumda, clipboardData
boş olur.
Metin ve resim içeren bir sayfa düşünün; kullanıcı tüm seçili öğeleri
bir pano kopyası başlatırsa özel çözümünüz metni silip yalnızca
resmi kopyalayın. Bunu aşağıdaki kod örneğinde gösterildiği gibi yapabilirsiniz.
Bu örnekte ele alınmayan, öncekine nasıl döneceğinizdir.
Clipboard API'nin desteklenmediği API'ler.
<!-- 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);
}
});
copy
etkinliği için:
ClipboardItem
için:
Yapıştır: Panodaki veriler okunuyor
readText()
Panodaki metni okumak için navigator.clipboard.readText()
numaralı telefonu arayıp bekleyin
şunların çözülmesi gerekiyor:
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);
}
}
read()
navigator.clipboard.read()
yöntemi de eşzamansızdır ve bir
sözü. Panodaki bir resmi okumak için şunların listesini alın:
ClipboardItem
ve bu nesneler üzerinde yinelemeler yapın.
Her ClipboardItem
, içeriğini farklı türlerde koruyabilir. Bu nedenle
tür listesi üzerinde yine bir for...of
döngüsü kullanarak yineleme gerçekleştirin. Her tür için
öğesini elde etmek için geçerli türe sahip getType()
yöntemini bağımsız değişken olarak
olması gerekir. Daha önce olduğu gibi, bu kod resimlere bağlı değildir ve
gelecekteki diğer dosya türleriyle çalışın.
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);
}
}
Yapıştırılan dosyalarla çalışılıyor
Kullanıcıların ctrl+c ve ctrl+v. Chromium, aşağıda açıklandığı gibi panodaki salt okunur dosyaları gösterir. Bu işlem, kullanıcı işletim sisteminin varsayılan yapıştırma kısayoluna bastığında tetiklenir veya kullanıcı tarayıcının menü çubuğunda Düzenle'yi, ardından Yapıştır'ı tıkladığında ya da vardır. Başka bir sıhhi tesisat koduna gerek yoktur.
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());
});
Yapıştırma etkinliği
Daha önce de belirttiğimiz gibi, Clipboard API'si ile çalışmak için etkinlikler sunmayı planlıyoruz.
ancak şimdilik mevcut paste
etkinliğini kullanabilirsiniz. Yeni
panodaki metni okumak için eşzamansız yöntemler. copy
etkinliğinde olduğu gibi
preventDefault()
numarayı aramayı unut.
document.addEventListener('paste', async (e) => {
e.preventDefault();
const text = await navigator.clipboard.readText();
console.log('Pasted text: ', text);
});
Birden fazla MIME türünü işleme
Çoğu uygulama, tek bir kesme işlemi için birden fazla veri biçimini panoya yerleştirir veya kopyalama işlemi. Bunun iki nedeni vardır: Bir uygulama geliştirici olarak kullanıcının metin veya resimleri kopyalamak istediği uygulamanın özelliklerini bilmenin mümkün olmadığını unutmayın. Ayrıca birçok uygulama, yapılandırılmış verilerin düz metin olarak yapıştırılmasını destekler. Bu genelde kullanıcılara Yapıştır ve eşleşme stili veya Biçimlendirme olmadan yapıştır'ı seçin.
Aşağıdaki örnekte bunun nasıl yapılacağı gösterilmektedir. Bu örnekte, şu verileri almak için fetch()
kullanılmıştır:
ama bu veriler farklı bir dilden de
<canvas>
veya File System Access API'yi kullanabilirsiniz.
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 sorunu oluşturmuştur. Yok:
bir sayfa, izin verilmeyen her tür kötü amaçlı içeriği sessizce
kullanıcının panosuna yapıştırır.
rm -rf /
veya bir dosyayı sessizce kopyalayan bir web sayfası
dekompresyon bombası resmi
panonuza yapıştırın.
![Tarayıcı istemi, kullanıcıdan pano izni istiyor.](https://web.developers.google.cn/static/articles/async-clipboard/image/browser-prompt-asking-us-40b4cf43bf01.png?authuser=5&hl=tr)
Web sayfalarına panoya kesintisiz okuma erişimi vermek daha da iyidir zahmetli. Kullanıcılar şifre ve e-posta adresi gibi hassas bilgileri düzenli olarak kopyalar panoya kopyalayabilirsiniz; bunlar daha sonra herhangi bir sayfa gerektirmeden bilmek kadar harika bir his yok.
Birçok yeni API'de olduğu gibi Clipboard API yalnızca HTTPS'ye dokunun. Kötüye kullanımın önüne geçmek için pano erişimine yalnızca bir sayfa yalnızca etkin sekme. Etkin sekmelerdeki sayfalar panoya ancak panodan okuma işlemi için her zaman izni gerekir.
Kopyalama ve yapıştırma izinleri
Permissions API.
clipboard-write
izni, izin verilen sayfalara otomatik olarak verilir.
etkin sekme. clipboard-read
izninin istenmesi gerekir. Bunu yapabilirsiniz.
panodaki verileri okumaya çalışarak. 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, kesme veya kesmeyi çağırmak için bir kullanıcı hareketinin gerekip
yapıştırırken allowWithoutGesture
seçeneğini kullanabilirsiniz. Bu değer için varsayılan
tarayıcıya göre değiştiğinden bunu her zaman dahil etmeniz gerekir.
Clipboard API'sinin eşzamansız doğası işte tam olarak burada işe yarar: pano verilerini okumaya veya yazmaya çalışırken kullanıcıdan otomatik olarak izin verilmemesini sağlar. API vaat temelli olduğundan bu tamamen şeffaftır ve bir kullanıcının pano iznini reddetmesi yanıt verebilmesi için reddetme taahhüdü vermelidir.
Tarayıcılar pano erişimine yalnızca sayfa etkin sekme olduğunda izin verdiği için
buradaki örneklerden bazılarının doğrudan
geliştirici araçlarının kendisi etkin sekme olduğu için tarayıcının konsolunda Önemli bir konu: erteleyin
setTimeout()
tuşlarını kullanarak pano erişimini kullanın, ardından sayfanın içini tıklayarak
fonksiyonlar çağrılmadan önce odaklamasını sağlar:
setTimeout(async () => {
const text = await navigator.clipboard.readText();
console.log(text);
}, 2000);
İzin politikası entegrasyonu
API'yi iframe'lerde kullanmak için API'yi
İzin Politikası,
Bu aşama, kullanıcının seçmeli şekilde etkinleştirmesine ve
çeşitli tarayıcı özelliklerini ve API'leri devre dışı bırakmak. Somut olarak, karşınızdaki paydaşların
Uygulamanızın ihtiyaçlarına bağlı olarak clipboard-read
veya clipboard-write
.
<iframe
src="index.html"
allow="clipboard-read; clipboard-write"
>
</iframe>
.
Özellik algılama
Async Clipboard API'sini tüm tarayıcıları desteklerken kullanmak için
navigator.clipboard
ve önceki yöntemlere geri dönebilirsiniz. Örneğin, aşağıdaki gibi
diğer tarayıcıları içerecek şekilde yapıştırmayı 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);
});
Hikayenin tamamı bundan ibaret değil. Async Clipboard API'sinden önce
web tarayıcılarında farklı kopyalama ve yapıştırma uygulamaları. Çoğu tarayıcıda
tarayıcının kendi kopyalama ve yapıştırma işlevi
document.execCommand('copy')
ve document.execCommand('paste')
. Metin
DOM'de bulunmayan bir dizeyse, bu dizenin
DOM ve seçilenler:
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
Aşağıdaki demolarda Async Clipboard API'sini kullanabilirsiniz. Glitch you'de metin demosunu remiksleyebilir veya resim demosunu izleyin. bunlarla denemeler yapabilirsiniz.
İlk örnekte metnin pano üzerinde ve dışına taşınması gösterilmektedir.
API'yi resimlerle denemek için bu demoyu kullanın. Yalnızca PNG'lerin desteklendiğini unutmayın. ve yalnızca şurada: birkaç tarayıcıda.
İlgili bağlantılar
Teşekkür
Eşzamansız Clipboard API, Darwin Huang ve Gary Kačmarčík ile de uyumlu. Darwin de demoyu sundu. Bu katkı için Kyarik ve tekrar Gary Kačmarčík'e teşekkür ederiz. bu makalenin bölümlerini gözden geçirin.
Markus Winkler'ın sunduğu hero resim Lansmanı kaldırın.