Świadomość posiadania czegoś łechce zmysły każdego z nas. Wszyscy lubią coś mieć, czasem nawet niepotrzebnego. Kupujemy rzeczy, których nie będziemy używać. Ściągamy pliki, których nigdy nie otworzymy, ale zgrabnie wypełnią ostatnią wolną przestrzeń niedawno posprzątanego pulpitu. Kreujemy pliki, które inni będą ściągać. I o ile wiemy jak to zrobić po stronie serwera, to czasem zachodzi potrzeba nieangażowania strony serwerowej. A jest to możliwe tylko i wyłącznie w JavaScript.
<A>2[download]2
Jakiś czas temu (spory) pojawił się atrybut download dla tagu A. Dodanie go powoduje pobranie zawartości spod URL, zamiast otwierania. Jeśli jednak atrybut href będzie kierował do lokalizacji na serwerze, to oznacza, że musielibyśmy wpierw plik wygenerowany po stronie JS zapisać na serwerze, aby móc go pobrać. Nie ma to sensu. Ale przecież href oprócz standardowych URL może zawierać treść w postaci data URI. Tak więc plik, dla którego chcemy wymusić pobranie, trzeba wtłoczyć do atrybutu href w takiej postaci. Zacznijmy od najprostszego przykładu:
/* link początkowo
będzie ukryty
*/
a.hidden {
display: none;
}
+
<textarea></textarea>
<a download class="hidden">Pobierz</a>
+
document
.querySelector("textarea")
.addEventListener("keypress", function() {
document.querySelector("a").href = "data:text/plain," + encodeURIComponent(this.value);
document.querySelector("a").classList.remove("hidden");
});
Mamy tu tag A początkowo ukryty, odkrywamy go kiedy TEXTAREA zapełni się jakimś tekstem. I kiedy go zapełniamy tekstem, to automatycznie generujemy data URI dla linku. Kodowanie base64 nie jest wymagane dla data URI. Używa się go najczęściej przy przesyłaniu danych binarnych. My wysyłamy dane ASCII, więc wystarczy, że zakodujemy znaki specjalne. W tym momencie jeszcze plik nie jest automatycznie pobierany na dysk użytkownika - trzeba kliknąć w link. Zauważysz jeszcze pewnie fakt, że plik zapisuje się pod domyślną nazwą.
I'm your filename!
Nadanie nazwy dla pobieranego pliku jest również możliwe. Atrybut download może przyjąć jakąś wartość. A ta wartość to nic innego jak nazwa pliku. Nazwę możemy więc ustawić "na sztywno" lub nadawać w trakcie odkrywania linku. I znów przykłady. W pierwszym plik tekstowy będziemy zapisywać pod nazwą "plik.txt", w drugim będziemy generować dane binarne (obrazek), wtedy nazwa przyjmie wartość losową, a z rozszerzeniem ".png".
W pierwszym zmienia się tylko:
<textarea></textarea>
<a download="plik.txt" class="hidden">Pobierz</a>
Drugi:
a.hidden {
display: none;
}
+
<canvas width="320" height="320"></canvas>
<a class="hidden">Pobierz</a>
+
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
/* tworzymy tu 3 okręgi
o losowym położeniu
i promieniu
*/
for (let i = 0; i < 3; i++) {
ctx.beginPath();
ctx.arc(
Math.random() * 320,
Math.random() * 320,
Math.random() * 10 + 10,
0,
Math.PI * 2,
false
);
ctx.fillStyle = "#9cf000";
ctx.fill();
}
const a = document.querySelector("a");
/* nadajemy losową nazwę */
a.download = Date.now() + ".png";
/* metoda toDataURL
wygeneruje gotowy
data URI (z mime
i kodowaniem base64)
*/
a.href = canvas.toDataURL();
a.classList.remove("hidden");
The Force.
Wszystkie te przykłady nie wymuszają pobierania pliku, a przecież rycerze J(asnej)S(trony) czekają na to od początku. Jesteśmy o krok od przywrócenia pokoju. Wystarczy wywołać kliknięcie na link metodą click i gotowe.
a.hidden {
display: none;
}
+
<canvas width="320" height="320"></canvas>
<button>Wygeneruj i pobierz</button>
<a class="hidden"></a>
+
/* tym razem generowanie
obrazka podpinamy
pod przycisk
*/
document.querySelector("button").addEventListener("click", function() {
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
for (let i = 0; i < 3; i++) {
ctx.beginPath();
ctx.arc(
Math.random() * 320,
Math.random() * 320,
Math.random() * 10 + 10,
0,
Math.PI * 2,
false
);
ctx.fillStyle = "#9cf000";
ctx.fill();
}
const a = document.querySelector("a");
a.download = Date.now() + ".png";
a.href = canvas.toDataURL();
/* po wygenerowaniu obrazka
i data URI wymuszamy
kliknięcie
*/
a.click();
});
Mam dobre przeczucia, że niedługo pojawi się kolejny wpis. Bez próbowania.
Przydatne linki:
Tag A i atrybut download
Metoda click dla tagu HTML
Metoda toDataURL dla Canvas