文件导出方法的思路

这里主要讲解blob导出的思路

1. 首先设置一个方法名,接受payload={method='get', url, param, fileName}和options={header},返回promise

function downBlob(payload: payloadType, options?: optionsType) {
  return new Promise(((resolve, reject) => {
   
  }));
}

2. 然后,创建一个请求XMLHttpRequest,设置返回blob类型为文件流等配置参数    const { method = 'GET', url = '', param, fileName = '' } = payload;

    const requrstUrl = method === 'GET' ? `${url}?${param}` : url;
    let name = fileName;
    // 获取 XMLHttpRequest
    const xmlResquest = new XMLHttpRequest();
    // 发起请求
    xmlResquest.open(method, requrstUrl, true);
    // 返回类型为文件流
    xmlResquest.responseType = 'blob';
    // 设置请求头类型
    xmlResquest.setRequestHeader('Content-type', 'application/json');
// 设置header, options.headers 看情况需要,可支持 Object.entries(options.headers || {}).forEach(item => { const [k, v] = item; xmlResquest.setRequestHeader(k, v); });

3. 设置返回方法 onload,然后发送请求

  xmlResquest.onload = (oEvent) => {
      // 处理下载的文件
      const content = xmlResquest.response;
      const blob = new Blob([content]);

      // 请求失败
      if (xmlResquest.status != 200) {
        message.error('请求失败');
        return;
      }
      // 从这个字段获取 filename
      const contentDisposition = xmlResquest.getResponseHeader('content-disposition');
      if (!name && contentDisposition) {
        const matched = contentDisposition.match(/filename*=(.*)/) || contentDisposition.match(/filename=(.*)/); 
        // 获取filename的值
        const filename = matched && matched[1];
        name = filename ? decodeURIComponent(filename) : '';
      }
      // 如果是IE10及以上,不支持download属性,采用msSaveOrOpenBlob方法,但是IE10以下也不支持msSaveOrOpenBlob
      if ('msSaveOrOpenBlob' in navigator) {
        navigator.msSaveOrOpenBlob(blob, name);
        return;
      }
    };
  if (method === 'GET')  xmlResquest.send(); 
  if (method === 'POST')  xmlResquest.send(JSON.stringify(param));

4. 还需要兼容下ie10以下浏览器

     const reader = new FileReader();
     reader.onload = (event) => {
        // json成功表示服务器报错,将错误信息提示出来
        try {
			const res = JSON.parse(reader.result);
			message.error(res.errorMsg);
			reject(res);
        } catch (e) {
          // json化失败,表示是一个文件流,将文件流下载下来
          // 组装a标签
          const elink = document.createElement('a');
          // 设置下载文件名
          elink.download = name || `${timestamp}.xlsx`;
          elink.style.display = 'none';
      const blobUrl = URL.createObjectURL(blob);
      elink.href = blobUrl; document.body.appendChild(elink); elink.click(); document.body.removeChild(elink); URL.revokeObjectURL(blobUrl); resolve(true); } }; reader.readAsText(content); };

5. 总代码合并起来

function fileDownBlob(payload, options) {
  return new Promise(((resolve, reject) => {
   const { method = 'GET', url = '', param, fileName = '' } = payload;
    const requrstUrl = method === 'GET' ? `${url}?${param}` : url;
    let name = fileName;
    // 获取 XMLHttpRequest
    const xmlResquest = new XMLHttpRequest();
    // 发起请求
    xmlResquest.open(method, requrstUrl, true);
    // 返回类型为文件流
    xmlResquest.responseType = 'blob';
    // 设置请求头类型
    xmlResquest.setRequestHeader('Content-type', 'application/json');
    // 设置header, options.headers 看情况需要,可支持
    Object.entries(options.headers || {}).forEach(item => {
        const [k, v] = item;
        xmlResquest.setRequestHeader(k, v);
    })
  // 设置返回方法
    xmlResquest.onload = (oEvent) => {
      // 处理下载的文件
      const content = xmlResquest.response;
      const blob = new Blob([content]);

      // 请求失败
      if (xmlResquest.status != 200) {
        message.error('请求失败');
        return;
      }
      // 从这个字段获取 filename
      const contentDisposition = xmlResquest.getResponseHeader('content-disposition');
      if (!name && contentDisposition) {
        const matched = contentDisposition.match(/filename*=(.*)/) || contentDisposition.match(/filename=(.*)/); 
        // 获取filename的值
        const filename = matched && matched[1];
        name = filename ? decodeURIComponent(filename) : '';
      }
      // 如果是IE10及以上,不支持download属性,采用msSaveOrOpenBlob方法,但是IE10以下也不支持msSaveOrOpenBlob
      if ('msSaveOrOpenBlob' in navigator) {
        navigator.msSaveOrOpenBlob(blob, name);
        return;
      }
   // 下面是支持ie10以下版本
   const reader = new FileReader();
     reader.onload = (event) => {
        // json成功表示服务器报错,将错误信息提示出来
        try {
		  const res = JSON.parse(reader.result);
	    message.error(res.errorMsg);
		  reject(res);
        } catch (e) {
          // json化失败,表示是一个文件流,将文件流下载下来
          // 组装a标签
          const elink = document.createElement('a');
          // 设置下载文件名
          elink.download = name || `${timestamp}.xlsx`;
          elink.style.display = 'none';
      const blobUrl = URL.createObjectURL(blob);
      elink.href = blobUrl; document.body.appendChild(elink); elink.click(); document.body.removeChild(elink); URL.revokeObjectURL(blobUrl); resolve(true); } }; reader.readAsText(content); };
  // 发送请求
  if (method === 'POST')  xmlResquest.send(JSON.stringify(param));
  if (method === 'GET') xmlResquest.send();
  })); 
} 

写到这里整个导出的方法就结束了。

这里在讲解下URL.createObjectURL和URL.revokeObjectURL

URL.createObjectURL:静态方法会创建一个DOMString、,其中包含一个表示参数中给出的对象的URL。这个 URL 的生命周期和创建它的窗口中的document、 绑定。这个新的URL 对象表示指定的File、 对象或Blob、 对象。

URL.revokeObjectURL: 在每次调用 createObjectURL方法时,都会创建一个新的 URL 对象,即使你已经用相同的对象作为参数创建过。当不再需要这些 URL 对象时,每个对象必须通过调用 URL.revokeObjectURL() 方法来释放。

若有不对的地方,欢迎大家一起探讨深入了解~

 

posted @ 2024-01-02 16:43  君临天下之徐少  阅读(69)  评论(0)    收藏  举报