ชื่อไฟล์ blob JavaScript ไม่มีลิงก์


189

คุณจะตั้งชื่อไฟล์ blob ใน JavaScript อย่างไรเมื่อบังคับให้ดาวน์โหลดผ่าน 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);
}

การรันโค้ดด้านบนจะดาวน์โหลดไฟล์ทันทีโดยไม่ต้องรีเฟรชหน้าเว็บที่มีลักษณะดังนี้:

bfefe410-8d9c-4883-86c5-d76c50a24a1d

ฉันต้องการตั้งชื่อไฟล์เป็นmy-download.jsonแทน

คำตอบ:


312

วิธีเดียวที่ฉันรู้คือเคล็ดลับที่ใช้โดยFileSaver.js :

  1. สร้าง<a>แท็กที่ซ่อนอยู่
  2. ตั้งค่าhrefแอตทริบิวต์เป็น URL ของ blob
  3. ตั้งค่าdownloadคุณสมบัติเป็นชื่อไฟล์
  4. คลิกที่<a>แท็ก

นี่คือตัวอย่างที่ง่าย ( 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);

ฉันเขียนตัวอย่างนี้เพื่ออธิบายแนวคิดในโค้ดการผลิตใช้ FileSaver.js แทน

หมายเหตุ

  • เบราว์เซอร์รุ่นเก่าไม่รองรับแอตทริบิวต์ "ดาวน์โหลด" เนื่องจากเป็นส่วนหนึ่งของ HTML5
  • รูปแบบไฟล์บางรูปแบบถือว่าเบราว์เซอร์ไม่ปลอดภัยและการดาวน์โหลดล้มเหลว การบันทึกไฟล์ JSON ด้วยส่วนขยาย txt นั้นใช้ได้สำหรับฉัน

2
@AshBlue แอตทริบิวต์ "download" ต้องการ HTML5 รหัสของฉันเป็นเพียงตัวอย่างคุณยังสามารถลองหน้าตัวอย่างของ FileSaver.js: eligrey.com/demos/FileSaver.js
kol

1
ที่น่าสนใจถ้าคุณพยายามดาวน์โหลด txt ด้วยวิธีนี้ซ้ำ ๆ (โดยการกดปุ่ม Run บน jsfiddle.net ซ้ำแล้วซ้ำอีก) การดาวน์โหลดบางครั้งก็ล้มเหลว
kol

2
แค่อยากจะพูดถึงว่าวิธีนี้จะไม่ทำงานสำหรับไฟล์ที่มีขนาดใหญ่กว่าเกณฑ์ที่กำหนด เช่น -> 2 MB สำหรับ chrome ขนาดนี้จะแตกต่างกันไปในแต่ละเบราว์เซอร์
manojadams

3
สิ่งนี้ใช้ไม่ได้สำหรับฉันเพราะฉันต้องเปิดไฟล์ในแท็บใหม่ ฉันต้องแสดง PDF ใน Chrome แต่ฉันต้องแสดงชื่อผู้ใช้ที่เป็นมิตรในแถบเครื่องมือ URL และหากผู้ใช้ต้องการดาวน์โหลดผ่านไอคอนดาวน์โหลดฉันต้องใส่ชื่อที่เป็นมิตรกับผู้ใช้ในไฟล์
Adrian Paredes

1
เพียงเพิ่มคุณไม่จำเป็นต้องติดแท็กกับร่างกายเพื่อให้สามารถใช้งานได้ (ลองใช้ใน Chrome ตอนนี้)
เกินรหัส

52

ฉันแค่อยากจะขยายคำตอบที่ได้รับการยอมรับด้วยการสนับสนุนสำหรับ Internet Explorer (รุ่นที่ทันสมัยที่สุด, anyways) และเพื่อจัดระเบียบโค้ดโดยใช้ 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();
}

นี่คือตัวอย่างซอ โชคดี


ทำงานได้อย่างสมบูรณ์แบบ
N8allan

1
ฉันใช้โซลูชันที่ยอมรับแล้ว แต่ใช้งานไม่ได้กับ firefox! ฉันยังไม่รู้ว่าทำไม โซลูชันของคุณทำงานใน Firefox ขอบคุณ
elahehab

@elahehab โซลูชันของฉันใช้ได้เสมอ;)
Alexandru

27

หลักการเดียวกับการแก้ปัญหาข้างต้น แต่ฉันมีปัญหากับ Firefox 52.0 (32 บิต) ที่ไฟล์ขนาดใหญ่ (> 40 MBytes) ถูกตัดทอนที่ตำแหน่งสุ่ม การตั้งเวลาการโทรของ revokeObjectUrl () อีกครั้งช่วยแก้ไขปัญหานี้ได้

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)
  }
}

ตัวอย่าง jsfiddle


1
ฉันพบว่าการแฮ็ก setTimeout () นี้แก้ไข MS Edge ซึ่งไฟล์จะไม่ดาวน์โหลดเลย อย่างไรก็ตามเฉพาะการเรียก revokeObjectURL () เท่านั้นที่จะต้องมีความล่าช้า
รัสเซลฟิลลิปส์

ฉันพบว่า "if (window.navigator.msSaveOrOpenBlob)" เป็นสิ่งที่หลอกลวงสำหรับฉัน
Jacques Olivier

23

ล่าช้า แต่เนื่องจากฉันมีปัญหาเดียวกันฉันจึงเพิ่มวิธีแก้ไข:

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);
    }
}

5
ขอบคุณ @ben มันใช้งานได้ดี ไม่มีองค์ประกอบ dom ไม่มีอะไรที่จะทริกเกอร์เหมือนคลิกกิจกรรม มันใช้งานได้ยอดเยี่ยมด้วยส่วนขยายที่เหมาะสม แต่ชื่อไฟล์ที่ระบุไม่ได้รับการพิจารณาให้ดาวน์โหลด "<object_url_id> .csv" แทนที่จะเป็น "<myfileName> .csv"
Ram Babu S

3
การโทรrevokeObjectURLหลังจากlocation.assignทำงานได้ดีใน Firefox แต่หยุดการดาวน์โหลดลงบน Chrome
Fred

โปรดทราบว่า "Edge ไม่รองรับตัวสร้างไฟล์" อ้าง caniuse.com/#feat=fileapi
user1477388

นี่ควรเป็นคำตอบที่ถูกต้อง ไม่มีจุดในการสร้างวัตถุที่ไร้ประโยชน์ในต้นไม้ DOM
Luiz Felipe

ตอนนี้ตั้งแต่มกราคม '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);
        }
    }

มีวิธีใดบ้างในการเปิดหน้าต่างใหม่?
Enrique Altuna

ฉันคิดว่าคุณสามารถโทรหาlink.click()แทนที่จะส่งเหตุการณ์เมาส์
Fred

2

ตัวอย่างการทำงานของปุ่มดาวน์โหลดเพื่อบันทึกภาพแมวจาก url เป็น "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();
}

1

window.location.assign ไม่ได้ผลสำหรับฉัน มันดาวน์โหลดได้ดี แต่การดาวน์โหลดที่ไม่มีส่วนเสริมสำหรับไฟล์ CSV บนแพลตฟอร์ม Windows ต่อไปนี้ใช้งานได้สำหรับฉัน

    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);

0

นี่คือทางออกของฉัน <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>

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.