前几天,一个关于下载的问题,把我困在原地蛮久,记录一下。
说到标题,后台返回一个url,前端浏览器打开实现下载功能,直接想到的就是window.open(url) 来实现下载,但是这种方法 我个人认为一闪而过的白色页面导致用户体验不是很好, so,就随手写写。
- 1 window.location.href = url;
- 2 a标签下载,栗子
可以使用download属性指定下载下来的文件名
我在vue中,因为是导出,url参数根据页面的选择项而变化,点击button,生成一个url,a标签的href属性绑定url,之后
<a :href="downloadUrl" style="display: none" ref="download"></a> // a标签隐藏
this.$nextTick(() => {
this.$refs.download.click()
}) 这种的写法代替了jquery的trigger事件
- 3 form下载
/**
* 兼容性的下载方式,调用浏览器的下载功能
* 使用该方法需要跟后台协商好传递token的字段名为access_token
* @param url 文件下载请求的url
* @param token 传递的token
* @param input 传递的其他参数 [{name: 'reportPath', value: '/conc/report/201710300735080796.doc'}, {name: 'isOnline', value: false}]
*/
const downloadFile = (url, token, input = []) => {
var $form = document.createElement('form')
var $input = document.createElement('input')
if (token) {
$input.setAttribute('type', 'hidden')
$input.setAttribute('name', 'access_token')
$input.setAttribute('value', token)
}
$form.setAttribute('method', 'get') // or post
$form.setAttribute('action', url)
$form.appendChild($input)
for (var i = 0; i < input.length; i++) {
var _input = document.createElement('input')
_input.setAttribute('type', 'hidden')
_input.setAttribute('name', input[i].name)
_input.setAttribute('value', input[i].value)
$form.appendChild(_input)
}
document.body.appendChild($form)
$form.submit()
$form.addEventListener('submit', function (e) {
e.preventDefault()
})
document.body.removeChild($form)
}
但是这种方法的体验我感觉最好,但是是有限制的,如果你以get请求形式下载,url后面的?参数会全部被截取,我之前就是采用这种方式进行导出,结果才发现了这个问题。采取以上方式最好的url参数不是?携带,而是 以http://XXXX/${参数}的形式最好
- 当为get请求时,请求所需的参数用input标签来传递,直接写在url后面是无效的。
- 当为post类型时,queryString参数直接写在URL?后面,formData参数则用input标签传递
个人认为参数过多,就很麻烦了,因为要传多少数据就得用多少input标签。post请求的时候,如何后台需要指定content-type,form做不到
- 4 iframe下载
这种方式,就是如果给了多个url,他都可以给你下载下来,还能指定下载下来的文件名,栗子
for (let i = 0; i < this.dataList.length; i++) {
let url = this.dataList[i].contractSignUrl
let token = cache.get('TOKEN').Authorization
let ifr = document.createElement('iframe')
ifr.style.display = 'none'
ifr.src = url + '?access_token=' + token
document.body.appendChild(ifr)
// 保存页面 -> 保存文件
ifr.contentWindow.document.execCommand('SaveAs', false, this.dataList[i].contractName)
}
如果有什么不对之处,希望大家能指出来,谢谢。