— Pixels Commander

[ In English, На русском ]

Лучший способ загрузки файлов в JavaScript

Скачивание файла — что может быть проще? Однако как и везде — в этом вопросе есть подводные камни и нет предела совершенству. В статье описывается лучший способ скачать файл в JavaScript.

Если вам не нужна теория о загрузке файлов в JavaScript и вы просто хотите подключить функцию downloadFile к проекту — вам на GitHub.

Как правило в HTML среде используются два пути вызова загрузки: window.open и клик по ссылке на файл. Каждый из способов по своему ущербный. В поиске универсальной техники было найдено несколько интересных решений, все вместе они составляют лучший метод для скачивания файлов из JS.

Начнем с простого метода загрузки файла через window.open:

window.downloadFile = function(sUrl) {
    window.open(sUrl);
}

Эта функция будет работать везде, но с рядом недостатков:

  • В Chrome и Safari после срабатывания останется пустое окно;
  • Если content-type файла предполагает открытие то файл не скачается, а отобразится в открывшемся окне.

Что же мы можем предпринять?

Аргумент «_self» для window.open

Убрать назойливое окно в Chrome и Safari можно добавив аргумент «_self» к window.open:

window.downloadFile = function(sUrl) {
    window.open(sUrl, '_self');
}

 

Виртуальный клик

Клик по ссылке так же не вызывает упомянутой выше проблемы с пустым окном и хоть клик — операция пользователя, нам никто не мешает создать виртуальную ссылку и виртуально по ней кликнуть сгенерировав событие мыши.

Добавим код виртуального щелчка для хрома и сафари, оставляя за кадром банальное определение браузера:

if (window.downloadFile.isChrome || window.downloadFile.isSafari) {
    //Creating new link node.
    var link = document.createElement('a');
    link.href = sUrl;

    //Dispatching click event.
    if (document.createEvent) {
        var e = document.createEvent('MouseEvents');
        e.initEvent('click' ,true ,true);
        link.dispatchEvent(e);
        return true;
    }
}

HTML5 аттрибут download и игнорирование content-type Что еще может вызвать раздражение пользователя? Например ситуация, когда при загрузке HTML или PNG файла он открывается в браузере. Этого можно избежать добавивши к нашему виртуальному линку аттрибут download, который появился в HTML5 и служит для указания браузеру на «скачивающий» характер ссылки. Значение аттрибута — это итоговое имя скачиваемого файла, а href — исходный URL.   Итоговый код модуля download.js:

window.downloadFile = function(sUrl) {

    //If in Chrome or Safari - download via virtual link click
    if (window.downloadFile.isChrome || window.downloadFile.isSafari) {
        //Creating new link node.
        var link = document.createElement('a');
        link.href = sUrl;

        if (link.download !== undefined){
            //Set HTML5 download attribute. This will prevent file from opening if supported.
            var fileName = sUrl.substring(sUrl.lastIndexOf('/') + 1, sUrl.length);
            link.download = fileName;
        }

        //Dispatching click event.
        if (document.createEvent) {
            var e = document.createEvent('MouseEvents');
            e.initEvent('click' ,true ,true);
            link.dispatchEvent(e);
            return true;
        }
    }

    // Force file download (whether supported by server).
    var query = '?download';

    window.open(sUrl + query, '_self');
}

window.downloadFile.isChrome = navigator.userAgent.toLowerCase().indexOf('chrome') > -1;
window.downloadFile.isSafari = navigator.userAgent.toLowerCase().indexOf('safari') > -1;

 

Пример использования

Проект на GitHub