Skip to content

download 封装的一些下载函数

ts
let isChrome = false
let isSafari = false
const isIOS = /(iP)/g.test(window.navigator.userAgent)

// 这些变量可以放在文件级别,因为浏览器类型不会在运行时改变
// 这里为了保持示例的完整性,将它们放在函数外部,但在实际应用中应移至文件顶部
;(function detectBrowser() {
  isChrome = window.navigator.userAgent.toLowerCase().indexOf('chrome') > -1
  isSafari = window.navigator.userAgent.toLowerCase().indexOf('safari') > -1
  if (isSafari && isChrome) {
    // Safari的userAgent也包含"Chrome",需要额外判断
    isChrome = !isIOS
  }
})()

export function downloadByUrl({ url, name }: { url: string; name?: string }) {
  if (isIOS) {
    console.error('您的浏览器不支持下载!')
    return
  }
  if (isChrome || isSafari) {
    const link = document.createElement('a')
    link.href = url
    link.download = name || url.substring(url.lastIndexOf('/') + 1)

    // 更现代的触发点击事件的方式
    const clickEvent = new MouseEvent('click', {
      bubbles: true,
      cancelable: true,
      view: window
    })

    link.dispatchEvent(clickEvent)
    return
  }
  const newUrl = url.includes('?') ? `${url}&download` : `${url}?download`
  window.open(newUrl, '_blank')
}

function isBase64(base64: string) {
  return base64 && typeof base64 === 'string' && btoa(atob(base64)) === base64
}

function isBlob(data: any) {
  return Object.prototype.toString.call(data) === '[object Blob]'
}

function isUint8Array(val: any) {
  return Object.prototype.toString.call(val) === '[object Uint8Array]'
}

/**
 * 下载文件
 *
 * @param data 要下载的数据,可以为ArrayBuffer、Blob或字符串类型
 * @param option 下载选项,包括文件名、文件MIME类型以及数据类型
 * @returns 无返回值
 */
export function downloadFile(
  data: ArrayBuffer | Blob | string,
  option: { name: string; mimeType?: string; dataType: 'base64' | 'blob' | 'arraybuffer' | 'text' }
) {
  const { name, mimeType = 'application/octet-stream' } = option
  let { dataType } = option

  if (!dataType) {
    if (isBlob(data)) {
      dataType = 'blob'
    } else if (isUint8Array(data)) {
      dataType = 'arraybuffer'
    } else if (isBase64(data as string)) {
      dataType = 'base64'
    } else {
      dataType = 'text'
    }
  }

  if (dataType === 'base64') {
    return downloadByUrl({
      url: `data:${mimeType};base64,${data}`,
      name
    })
  }

  const blob = dataType === 'blob' ? (data as Blob) : new Blob([data], { type: mimeType })

  if ('msSaveOrOpenBlob' in navigator) {
    // @ts-ignore ie使用的下载方式
    window.navigator.msSaveOrOpenBlob(blob, name)
    return
  }
  const url = URL.createObjectURL(blob)
  downloadByUrl({ url, name })
  URL.revokeObjectURL(url)
}