我写了一个基于Scott's answer的指令。您将像这样使用它:

<button class="btn btn-success"
        download-response="getData()"
        download-success="getDataSuccess()"
        download-error="getDataError()"
        download-name="{{name}}.pdf"
        download-backup-url="/Backup/File.pdf">
    Save
</button>

问题:,以下代码在第一种方法中在TypeError: Invalid calling object中引发错误IE11(行:saveBlob(blob, filename);)。即使可以使用其他下载方法,但据我了解,saveMethod1应该可以在IE11中工作。

这是代码:
'use strict';

// directive allows to provide a function to be executed to get data to be downloaded
// attributes:
// download-response - Required. Function to get data. It must return a promise. It must be declared on the $scope.
// download-success - Optional. Function to be executed if download-response function was successfully resolved. It must be declared on the $scope.
// download-error - Optional. Function to be executed if download-response function return a promise rejection. It must be declared on the $scope.
// download-mime - Optional. provide a mime type of data being downloaded. Defaulted to "application/octet-stream"
// download-name - Optional. name of the file to download. Defaulted to "download.bin"
// download-backup-url - in case browser does not support dynamic download, this url will be called to get the file
angular.module('app.directives')
    .directive('downloadResponse', [ '$parse', '$timeout',
        function ($parse, $timeout) {

            function saveMethod1(data, filename, contentType) {
                // Support for saveBlob method (Currently only implemented in Internet Explorer as msSaveBlob, other extension in case of future adoption)
                var saveBlob = navigator.msSaveBlob || navigator.webkitSaveBlob || navigator.mozSaveBlob || navigator.saveBlob;

                if (saveBlob) {
                    // Save blob is supported, so get the blob as it's contentType and call save.
                    var blob = new Blob([data], { type: contentType });
                    saveBlob(blob, filename);
                    //console.log("SaveBlob Success");
                } else {
                    throw 'saveBlob is not supported. Falling back to the next method';
                }
            }

            function saveMethod2(data, filename, contentType, octetStreamMime) {
                // Get the blob url creator
                var urlCreator = window.URL || window.webkitURL || window.mozURL || window.msURL;
                if (urlCreator) {
                    // Try to use a download link
                    var link = document.createElement("a");
                    var url;
                    if ("download" in link) {
                        // Prepare a blob URL
                        var blob = new Blob([data], { type: contentType });
                        url = urlCreator.createObjectURL(blob);
                        link.setAttribute("href", url);

                        // Set the download attribute (Supported in Chrome 14+ / Firefox 20+)
                        link.setAttribute("download", filename);

                        // Simulate clicking the download link
                        var event = document.createEvent('MouseEvents');
                        event.initMouseEvent('click', true, true, window, 1, 0, 0, 0, 0, false, false, false, false, 0, null);
                        link.dispatchEvent(event);

                        //console.log("Download link Success");
                    } else {
                        // Prepare a blob URL
                        // Use application/octet-stream when using window.location to force download
                        var blob = new Blob([data], { type: octetStreamMime });
                        url = urlCreator.createObjectURL(blob);
                        window.location = url;

                        //console.log("window.location Success");
                    }
                } else {
                    throw 'UrlCreator not supported. Falling back to the next method';
                }
            }

            function saveMethod3(attrs) {
                if (attrs.downloadBackupUrl && attrs.downloadBackupUrl != '') {
                    console.log('opening ' + attrs.downloadBackupUrl);
                    window.open('http://' + document.domain + attrs.downloadBackupUrl, '_blank');
                } else {
                    throw 'Could not download a file using any of the available methods. Also you did not provide a backup download link. No more bullets left...';
                }
            }

            return {
                restrict: 'A',
                scope: false,
                link:function (scope, elm, attrs) {
                    var getDataHandler = $parse(attrs.downloadResponse);

                    elm.on('click', function() {
                        var promise = getDataHandler(scope);
                        promise.then(
                            function (data) {
                                if (attrs.downloadSuccess && attrs.downloadSuccess != '') {
                                    var successHandler = $parse(attrs.downloadSuccess);
                                    successHandler(scope);
                                }

                                var octetStreamMime = "application/octet-stream";

                                var filename = attrs.downloadName || "download.bin";
                                var contentType = attrs.downloadMime || octetStreamMime;


                                try {
                                    saveMethod1(data, filename, contentType);
                                    return;
                                } catch (e) {
                                    console.log(e);
                                    try {
                                        saveMethod2(data, filename, contentType, octetStreamMime);
                                        return;
                                    } catch (e) {
                                        console.log(e);
                                        try {
                                            saveMethod3(attrs);
                                            return;
                                        } catch (e) {
                                            throw e;
                                        }
                                        throw e;
                                    }
                                    throw e;
                                }
                            },
                            function(data) {
                                if (attrs.downloadError && attrs.downloadError != '') {
                                    var errorHandler = $parse(attrs.downloadError);
                                    errorHandler(scope);
                                }
                            }
                        );
                    });

                }
            };
        }
    ]);

任何帮助是极大的赞赏!

最佳答案

问题:

我已经解决了这个问题。最简单的示例说明了Internet Explorer 11似乎不喜欢msSaveBlob函数的别名的情况:

// Succeeds
navigator.msSaveBlob(new Blob(["Hello World"]), "test.txt");

// Fails with "Invalid calling object"
var saveBlob = navigator.msSaveBlob;
saveBlob(new Blob(["Hello World"]), "test.txt");

因此,从本质上讲,为封装saveBlob功能而创建的通用别名应该可以防止msSaveBlob正常工作:

var saveBlob = navigator.msSaveBlob || navigator.webkitSaveBlob || navigator.mozSaveBlob || navigator.saveBlob;

解决方法:

因此,解决方法是分别测试msSaveBlob

if(navigator.msSaveBlob)
    navigator.msSaveBlob(blob, filename);
else {
    // Try using other saveBlob implementations, if available
    var saveBlob = navigator.webkitSaveBlob || navigator.mozSaveBlob || navigator.saveBlob;
    if(saveBlob === undefined) throw "Not supported";
    saveBlob(blob, filename);
}

tl; dr

因此,只要您不为函数命名,msSaveBlob方法就可以使用。也许这是一种安全预防措施-但是考虑到源头,我认为这很可能是一个缺陷,但是那样的话也许更合适。 :)

09-28 05:39