未古其人

目录

【代码片段】文件处理


/**
 * 导出Excel
*/
import XLS from 'xlsx-style'

export const exportExcel = (workbook, filename) => {
  // 导出文件
  const saveAs = (obj) => {
    const a = document.createElement('a')
    a.download = filename
    a.href = URL.createObjectURL(obj)
    a.click()
    setTimeout(() => {
      URL.revokeObjectURL(obj)
    }, 100)
  }
  // 格式转化
  const s2ab = s => {
    let buf = new ArrayBuffer(s.length)
    let view = new Uint8Array(buf)
    for (let i = 0; i !== s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF
    return buf
  }

  saveAs(
    new Blob([s2ab(
      XLS.write(workbook, {
        bookType: 'xlsx',
        bookSST: false,
        type: 'binary'
      })
    )], {
      type: 'application/octet-stream'
    })
  )
}


/**
 * 创建一个文件上传组件,并返回用户选择的文件
 * @param { string|array } exts - 允许上传的文件后缀格式,可以是字符串以逗号分隔或数组对象;忽略请留空;务必填写文件后缀名 例如 jpg,不包括点;默认忽略
 * @param { boolean } multiple - 是否允许多选, 默认 false
 * @param { boolean } toBase64 - 是否将文件转为 base64 格式,用于图片处理,默认 false
 */
export const createUpload = ({ exts, multiple, toBase64, fileSize }) => {
  exts = exts || ''
  multiple = multiple || false
  toBase64 = toBase64 || false
  fileSize = fileSize || 5 // 单位:M
  let lock = false

  // 生成文件 accept
  const mimeTypes = getMIMETypes()
  let accept = '*'
  if (exts && typeof exts === 'string') exts = exts.split(',')
  if (Array.isArray(exts) && exts.length) {
    accept = exts.map(ext => mimeTypes[ext] ? mimeTypes[ext] : `.${ext}`).join(',')
  }

  return new Promise((resolve, reject) => {
    // 创建文件上传框
    const el = document.createElement('input')
    el.id = +new Date()
    el.style.display = 'none'
    el.setAttribute('accept', accept)
    el.setAttribute('type', 'file')
    document.body.appendChild(el)

    el.addEventListener('change', () => {
      lock = true
      const file = el.files[0]
      if (accept.indexOf(file.type) === -1) {
        Message({
          showClose: true,
          message: `请选择 ${exts.join('、')} 格式的文件`,
          type: 'error'
        })
        reject(new Error('onblur'))
        return
      }
      if (file.size > fileSize * 1024 * 1024) {
        Message({
          showClose: true,
          message: `文件大小不能超过 ${fileSize} MB`,
          type: 'error'
        })
        reject(new Error('onblur'))
        return
      }
      if (toBase64) {
        const reader = new FileReader()
        reader.readAsDataURL(el.files[0])
        reader.onload = () => {
          file.base64 = reader.result
          resolve(file)
          // remove dom
          document.body.removeChild(document.getElementById(el.id))
        }
      } else {
        resolve(file)
        // remove dom
        document.body.removeChild(document.getElementById(el.id))
      }
    }, { once: true })

    // file blur
    window.addEventListener('focus', () => {
      setTimeout(() => {
        if (!lock && document.getElementById(el.id)) {
          reject(new Error('onblur'))
          // remove dom
          document.body.removeChild(document.getElementById(el.id))
        }
      }, 300)
    }, { once: true })

    // open file select box
    el.click()
  })
}


/**
 * 校验文件类型
 * @param { string } file - 文件实例,由浏览器创建
 * @param { array } exts - 允许上传的文件后缀格式,以逗号分隔或数组对象;例如 jpg,不包括点
 */
export const checkFile = ({ file, exts }) => {
  exts = exts || ''

  // 生成文件 accept
  const mimeTypes = getMIMETypes()
  let accept = '*'
  if (exts && typeof exts === 'string') exts = exts.split(',')
  if (Array.isArray(exts) && exts.length) {
    accept = exts.map(ext => mimeTypes[ext] ? mimeTypes[ext] : `.${ext}`).join(',')
  }

  if (accept.indexOf(file.type) === -1) {
    return `请选择 ${exts.join('、')} 格式的文件`
  }

  return null
}


export const downloadFile = ({ file, fileName }) => {
  let a = document.createElement('a')
  let ext = fileName.split('.')[1]
  let mime = getMIMETypes()[ext]

  a.download = fileName
  a.href = `data:${mime};base64,${file}`
  
  a.click()
}

export const fileToBase64 = (file) => {
  return new Promise((resolve, reject) => {
    const reader = new FileReader()
    reader.readAsDataURL(file)
    reader.onload = () => {
      resolve(reader.result)
    }
  })
}