js下载/上传文件

350 阅读2分钟

我们经常会遇到读写文件的需求,这里稍微总结一下。

前端下载文件

一、下载json文件

function downloadJson(){
    const data = await download();
    const content = JSON.stringify(data);
    const element = document.createElement('a');
    const blob = new Blob([content], { type: 'text/plain;charset=utf-8' });
    const objectUrl = URL.createObjectURL(blob);
    element.href = objectUrl;
    element.download = `aggregate_${Date.now()}.json`;
    document.body.appendChild(element);
    element.click();
    document.body.removeChild(element);
    URL.revokeObjectURL(objectUrl);
}

二、下载excel文件

1、接口返回excel文件内容

1-1、通过get请求拿到文件内容,api请求响应类型responseType设置为blob

function download() {
   return axios({
      url: `your_api_url`,
      method: 'get',
      responseType: 'blob'
   });
}

1-2、写文件

function downloadExcel(){
    const result = await download();
    const element = document.createElement('a');
    const resType = result.headers && result.headers['content-type'] ? result.headers['content-type'] : '';
    const blob = new Blob([result.data], { type: resType || 'application/vnd.ms-excel;charset=utf-8' });
    const objectUrl = URL.createObjectURL(blob);
    element.href = objectUrl
    element.download = `download_${Date.now()}.xlsx`;
    document.body.appendChild(element);
    element.click();
    document.body.removeChild(element);
    URL.revokeObjectURL(objectUrl);
}

2、接口返回数组

安装xlsx依赖包

npm install xlsx

// 字符串转字符流
function s2ab(s) {
  const buf = new ArrayBuffer(s.length);
  const view = new Uint8Array(buf);
  for (let i = 0; i !== s.length; ++i) view[i] = s.charCodeAt(i) & 0xff;
  return buf;
}

/**
 * 将 js 对象的数组转换为工作表。
 * @param {string[]} header - 表头
 * @param {Object} headerDisplay - 表头名称
 * @param {object[]} sheetData - 表数据
 * @param {Boolean} skipHeader - 是否隐藏表头
 * @returns 工作表
 */
function jsonToSheet(header, headerDisplay, sheetData, skipHeader) {
  const newSheetData = skipHeader ? [headerDisplay, ...sheetData] : sheetData;
  const ws = window.XLSX.utils.json_to_sheet(newSheetData, {
    header,
    skipHeader,
  });

  return ws;
}

/**
 * 自定义将js数据导出下载excel
 * 
 * sheetHeaderDisplay(表头名称) 不存在时,默认使用 sheetHeader(表头key) 当做表头名称
 * @param {Object[]} data - 所有表信息
 * @param {string} data[].sheetName - 表名称
 * @param {string[]} data[].sheetHeader - 表头key
 * @param {Object} data[].sheetHeaderDisplay - 表头名称
 * @param {Object[]} data[].sheet - 表数据
 * @param {string} excelName - 导出的excel名称
 * @example 
  [
    {
      sheetName: 'Tom and Jerry',
      sheetHeader: ['name', 'age', 'sex'],
      sheetHeaderDisplay: {name: '名字', age: '年龄', sex: '性别'},
      sheet: [
        { name: 'Tom', age: 3, sex: '男' },
        { name: 'Jerry', age: 2, sex: '女' },
        { name: 'Spike', age: 4, sex: '男' },
      ],
    },
  ];
 */
function Xlsx(data, excelName) {
  const tmpWB = {
    SheetNames: [], // 保存的表标题
    Sheets: {}, // 表数据
  };

  // 生成excel的配置项
  data.forEach(item => {
    const skipHeader =
      Object.prototype.toString.call(item.sheetHeaderDisplay) === '[object Object]' && Object.keys(item.sheetHeaderDisplay).length > 0;
    tmpWB.SheetNames.push(item.sheetName);
    tmpWB.Sheets[item.sheetName] = Object.assign({}, jsonToSheet(item.sheetHeader, item.sheetHeaderDisplay, item.sheet, skipHeader), {});
  });

  // 创建二进制对象写入转换好的字节流
  const tmpDown = new Blob(
    [
      s2ab(
        // write 用来把数据写入并生成 xlsx 文件的 API
        window.XLSX.write(
          tmpWB,
          {
            // 要生成的文件类型: 'xlsx'|'xlsm'|'xlsb'
            bookType: 'xlsx',
            bookSST: false, // 是否生成Shared String Table,官方解释是,如果开启生成速度会下降,但在低版本IOS设备上有更好的兼容性
            type: 'binary',
          }, // 这里的数据是用来定义导出的格式类型
        ),
      ),
    ],
    {
      type: '',
    },
  );

  const outFile = document.createElement('a');
  const href = URL.createObjectURL(tmpDown); // 创建对象超链接
  outFile.download = `${excelName || 'export'}.xlsx`; // 下载名称
  outFile.style.display = 'none';
  outFile.href = href; // 绑定a标签
  document.body.appendChild(outFile);
  outFile.click(); // 模拟点击实现下载
  setTimeout(() => {
    // 延时释放
    URL.revokeObjectURL(tmpDown); // 用URL.revokeObjectURL()来释放这个object URL
    document.body.removeChild(outFile);
  }, 100);
}

export default Xlsx;

前端上传文件

一、原生js读文件

<div>
 <input type="file" id="files"/>
</div>
 
 <script>
     var inputElement = document.getElementById("files");
     inputElement.addEventListener("change", handleFiles, false);
     function handleFiles() {
        var selectedFile = document.getElementById("files").files[0];
        var name = selectedFile.name;
        var size = selectedFile.size;
        console.log("文件名:"+name+"大小:"+size);
        var reader = new FileReader();
        reader.onload = function(result){
             console.log("读取结果:", result);
        };
        reader.readAsText(selectedFile);
     }
 </script>

二、vue+elementui读文件

<el-upload
     action="icon"
     class="batch-import-area"
     :show-file-list="false"
     :http-request="batchImport"
     :accept="'.xlsx'"
     >
     <el-button size="small" type="primary" @click="downloadExcel">批量导入</el-button>
</el-upload>

三、上传文件内容

使用axios上传

import axios from 'axios';

export const service = axios.create({
  baseURL: process.env.BASE_API, // api 的 base_url
  withCredentials: true,
  timeout: 5000
})

export default service;

服务层

import request from '@/request'

const batchImportFile = (data, config) => {
  const options = Object.assign({
    url: 'your url path',
    method: 'post',
    data,
    headers: {
      'Content-Type': 'multipart/form-data'
    }
  }, config || {})
  return request(options)
}

页面导入文件方法

import {batchImportFile} from '@/service'

async batchImport (file) {
      const form = new FormData()
      // 上传到指定文件夹
      // form.append('folder', '/upload')
      form.append('file', file.file, file.file.name);
      const result = await batchImportFile(form);
      if (result.data.code === 200 && result.data.data) {
        return toast(`批量导入成功`)
      }
      return toast('批量导入失败');
}

参考:

前端JS自定义导出excel表格

使用 JavaScript 和 Axios 下载 Excel 文件