Nama file gumpalan JavaScript tanpa tautan

189

Bagaimana Anda mengatur nama file gumpalan di JavaScript ketika memaksa mengunduhnya melalui window.location?

function newFile(data) {
    var json = JSON.stringify(data);
    var blob = new Blob([json], {type: "octet/stream"});
    var url  = window.URL.createObjectURL(blob);
    window.location.assign(url);
}

Menjalankan kode di atas mengunduh file secara instan tanpa refresh halaman yang terlihat seperti:

bfefe410-8d9c-4883-86c5-d76c50a24a1d

Saya ingin menetapkan nama file sebagai my-download.json .

Ash Blue
sumber

Jawaban:

313

Satu-satunya cara yang saya ketahui adalah trik yang digunakan oleh FileSaver.js :

  1. Buat <a>tag tersembunyi .
  2. Atur hrefatributnya ke URL blob.
  3. Setel downloadatributnya ke nama file.
  4. Klik pada <a>tag.

Berikut adalah contoh sederhana ( jsfiddle ):

var saveData = (function () {
    var a = document.createElement("a");
    document.body.appendChild(a);
    a.style = "display: none";
    return function (data, fileName) {
        var json = JSON.stringify(data),
            blob = new Blob([json], {type: "octet/stream"}),
            url = window.URL.createObjectURL(blob);
        a.href = url;
        a.download = fileName;
        a.click();
        window.URL.revokeObjectURL(url);
    };
}());

var data = { x: 42, s: "hello, world", d: new Date() },
    fileName = "my-download.json";

saveData(data, fileName);

Saya menulis contoh ini hanya untuk mengilustrasikan ide, dalam kode produksi menggunakan FileSaver.js sebagai gantinya.

Catatan

  • Browser lama tidak mendukung atribut "unduh", karena itu bagian dari HTML5.
  • Beberapa format file dianggap tidak aman oleh browser dan unduhan gagal. Menyimpan file JSON dengan ekstensi txt berfungsi untuk saya.
kol
sumber
2
@AshBlue Atribut "unduh" membutuhkan HTML5. Kode saya hanya sebuah contoh, Anda juga dapat mencoba halaman demo FileSaver.js: eligrey.com/demos/FileSaver.js
kol
1
Menariknya, jika Anda berulang kali mencoba mengunduh txt dengan cara ini (dengan menekan tombol Run di jsfiddle.net berulang kali), unduhan tersebut terkadang gagal.
kol
2
Hanya ingin menyebutkan bahwa solusi ini tidak akan berfungsi untuk file dengan ukuran lebih besar dari ambang tertentu. misalnya-> 2 MB untuk chrome. Ukuran ini bervariasi dari browser ke browser.
manojadams
3
Ini tidak berfungsi untuk saya karena saya perlu membuka file di tab baru. Saya harus menunjukkan PDF di Chrome, tetapi saya harus menunjukkan nama yang ramah pengguna di bilah alat URL, dan jika pengguna ingin mengunduh melalui ikon unduhan, saya harus memasukkan nama ramah pengguna yang sama dalam file.
Adrian Paredes
1
Hanya untuk menambahkan, Anda tidak perlu memasang tag ke badan agar dapat berfungsi (coba sekarang di Chrome)
luar kode
52

Saya hanya ingin memperluas jawaban yang diterima dengan dukungan untuk Internet Explorer (sebagian besar versi modern, lagian), dan untuk merapikan kode menggunakan jQuery:

$(document).ready(function() {
    saveFile("Example.txt", "data:attachment/text", "Hello, world.");
});

function saveFile (name, type, data) {
    if (data !== null && navigator.msSaveBlob)
        return navigator.msSaveBlob(new Blob([data], { type: type }), name);
    var a = $("<a style='display: none;'/>");
    var url = window.URL.createObjectURL(new Blob([data], {type: type}));
    a.attr("href", url);
    a.attr("download", name);
    $("body").append(a);
    a[0].click();
    window.URL.revokeObjectURL(url);
    a.remove();
}

Berikut ini contoh Fiddle . Semoga berhasil .

Alexandru
sumber
Bekerja dengan sempurna.
N8allan
1
Saya menggunakan solusi yang diterima tetapi tidak berhasil di firefox! Saya masih tidak tahu mengapa. Solusi Anda berhasil di firefox. Terima kasih.
elahehab
@elahehab Solusi saya selalu berhasil;)
Alexandru
27

Prinsip yang sama dengan solusi di atas. Tapi saya punya masalah dengan Firefox 52.0 (32 bit) di mana file besar (> 40 MBytes) terpotong pada posisi acak. Menjadwalkan ulang panggilan revokeObjectUrl () memperbaiki masalah ini.

function saveFile(blob, filename) {
  if (window.navigator.msSaveOrOpenBlob) {
    window.navigator.msSaveOrOpenBlob(blob, filename);
  } else {
    const a = document.createElement('a');
    document.body.appendChild(a);
    const url = window.URL.createObjectURL(blob);
    a.href = url;
    a.download = filename;
    a.click();
    setTimeout(() => {
      window.URL.revokeObjectURL(url);
      document.body.removeChild(a);
    }, 0)
  }
}

contoh jsfiddle

Kim Nyholm
sumber
1
Saya menemukan bahwa hack setTimeout () ini memperbaiki MS Edge, di mana file tidak mau mengunduh sama sekali. Namun, hanya panggilan untuk mencabutObjectURL () yang perlu ditunda.
Russell Phillips
Saya menemukan bahwa "if (window.navigator.msSaveOrOpenBlob)" adalah apa yang bisa saya lakukan
Jacques Olivier
23

Terlambat, tetapi karena saya memiliki masalah yang sama saya menambahkan solusi saya:

function newFile(data, fileName) {
    var json = JSON.stringify(data);
    //IE11 support
    if (window.navigator && window.navigator.msSaveOrOpenBlob) {
        let blob = new Blob([json], {type: "application/json"});
        window.navigator.msSaveOrOpenBlob(blob, fileName);
    } else {// other browsers
        let file = new File([json], fileName, {type: "application/json"});
        let exportUrl = URL.createObjectURL(file);
        window.location.assign(exportUrl);
        URL.revokeObjectURL(exportUrl);
    }
}
ben
sumber
5
@Ben terima kasih. Ini bekerja dengan baik. Tidak ada elemen dom, tidak ada yang suka memicu seperti acara klik. Ini hanya berfungsi luar biasa dengan ekstensi yang tepat. Tetapi nama file yang diberikan tidak dipertimbangkan, mengunduh "<object_url_id> .csv" alih-alih "<myfileName> .csv"
Ram Babu S
3
Memanggil revokeObjectURLsetelah location.assignberfungsi dengan baik di Firefox, tetapi merusak unduhan di Chrome.
Fred
Perhatikan bahwa "Edge tidak mendukung konstruktor File." Ref. caniuse.com/#feat=fileapi
user1477388
Ini seharusnya jawaban yang benar. Tidak ada gunanya membuat objek yang tidak berguna di pohon DOM
Luiz Felipe
Sekarang sudah, sejak Jan '20
Luiz Felipe
6
saveFileOnUserDevice = function(file){ // content: blob, name: string
        if(navigator.msSaveBlob){ // For ie and Edge
            return navigator.msSaveBlob(file.content, file.name);
        }
        else{
            let link = document.createElement('a');
            link.href = window.URL.createObjectURL(file.content);
            link.download = file.name;
            document.body.appendChild(link);
            link.dispatchEvent(new MouseEvent('click', {bubbles: true, cancelable: true, view: window}));
            link.remove();
            window.URL.revokeObjectURL(link.href);
        }
    }
Jean-Philippe
sumber
apakah ada cara untuk membukanya di jendela baru?
Enrique Altuna
Saya pikir Anda dapat menelepon link.click()daripada mengirim acara mouse.
Fred
2

Contoh kerja tombol unduh, untuk menyimpan foto kucing dari url sebagai "cat.jpg":

HTML:

<button onclick="downloadUrl('https://i.imgur.com/AD3MbBi.jpg', 'cat.jpg')">Download</button>

JavaScript:

function downloadUrl(url, filename) {
  let xhr = new XMLHttpRequest();
  xhr.open("GET", url, true);
  xhr.responseType = "blob";
  xhr.onload = function(e) {
    if (this.status == 200) {
      const blob = this.response;
      const a = document.createElement("a");
      document.body.appendChild(a);
      const blobUrl = window.URL.createObjectURL(blob);
      a.href = blobUrl;
      a.download = filename;
      a.click();
      setTimeout(() => {
        window.URL.revokeObjectURL(blobUrl);
        document.body.removeChild(a);
      }, 0);
    }
  };
  xhr.send();
}
pengguna1032613
sumber
1

window.location.assign tidak berfungsi untuk saya. itu mengunduh dengan baik tetapi unduhan tanpa ekstensi untuk file CSV pada platform Windows. Berikut ini bekerja untuk saya.

    var blob = new Blob([csvString], { type: 'text/csv' });
    //window.location.assign(window.URL.createObjectURL(blob));
    var link = window.document.createElement('a');
    link.href = window.URL.createObjectURL(blob);
    // Construct filename dynamically and set to link.download
    link.download = link.href.split('/').pop() + '.' + extension; 
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
Sacky San
sumber
0

Ini solusi saya. Dari sudut pandang saya, Anda tidak dapat melewati <a>.

function export2json() {
  const data = {
    a: '111',
    b: '222',
    c: '333'
  };
  const a = document.createElement("a");
  a.href = URL.createObjectURL(
    new Blob([JSON.stringify(data, null, 2)], {
      type: "application/json"
    })
  );
  a.setAttribute("download", "data.json");
  document.body.appendChild(a);
  a.click();
  document.body.removeChild(a);
}
<button onclick="export2json()">Export data to json file</button>

dabeng
sumber