这里的情景是:给定一个链接,如 http://localhost:8000/1.jpg , 需要实现的效果是将文件/图片下载下来,保存到本地。
但是在使用vue实现文件下载功能的时候,遇到了一个很大的问题,就是,文件只能在浏览器中预览,而不是下载到本地。在这个过程中,尝试了 el-link 、a 标签、window.open 、window.location.href 等方案来进行文件下载,但是都没有实现想要的效果。
最终采用了以下的一种方案实现了,这里记录的方法,重点不在于 a 标签,而是 blob ,通过将url地址转换为blob 地址,然后再下载。此外,需要说明的一点是,这种方案是需要后端设置跨域的,否则,下载下来的文件是损坏的,不能使用。
这里以下载一张图片为例,图片存放在后端服务器上,图片地址: http://localhost:8000/1.jpg 。这里在进行前端测试时,后端服务器一致保持开启状态。此外,这种方案,下载 pdf、xlsx 等文件都可以成功。
下面记录了三种方案来实现文件下载的功能,但这三种方案实现下载的核心是一样的,不同的只是使用不同的方式来组织代码。
1. 自定义指令
vue上自定义指令介绍
代码复用和抽象的主要形式是组件。然而,有的情况下,你仍然需要对普通 DOM 元素进行底层操作,这时候就会用到自定义指令。通过自定义指令实现代码复用和抽象。
这里使用的自定义指令是 v-download 。下面分别记录了使用局部自定义指令和全局自定义指令两种方法实现。
1.1 局部自定义指令
Step1 定义自定义指令
在当前组件或页面上, 通过 directive 设置自定义指令。
export default {
name: 'DownloadFile',
data() {
return {
fileUrl: 'http://localhost:8000/1.jpg'
}
},
directives: {
download: {
bind: function (el, binding) {
el.addEventListener('click', () => {
const url = binding.value;
let urlArray = url.split('/');
let filename = urlArray[urlArray.length-1];
const a = document.createElement('a');
fetch(url).then(res => res.blob())
.then(blob => {
a.href = URL.createObjectURL(blob)
a.download = filename
document.body.appendChild(a)
a.click()
})
})
}
},
},
}
Step2 使用
使用自定义指令 v-download 绑定数据,点击按钮后下载图片,保存到本地。
<el-button v-download="fileUrl">点击下载图片</el-button>
1.2 全局自定义指令
Step1 定义自定义指令
新建路径 src/directive ,在该路径下存放自定义指令的文件。 在该路径下创建文件 download.js 。内容如下:
export default {
bind: function (el, binding) {
el.addEventListener('click', () => {
const url = binding.value;
let urlArray = url.split('/');
let filename = urlArray[urlArray.length-1];
const a = document.createElement('a');
fetch(url).then(res => res.blob())
.then(blob => {
a.href = URL.createObjectURL(blob)
a.download = filename
document.body.appendChild(a)
a.click()
})
})
}
}
Step2 注册自定义组件
在 main.js 种注册刚才写的自定义指令,添加以下内容:
import download from "./directive/download";
Vue.directive('download', download);
Step3 使用
使用自定义指令 v-download 绑定数据,点击按钮后下载图片,保存到本地。
<el-button v-download="fileUrl">点击下载图片</el-button>
2. 使用方法下载文件
这里也测试了使用方法来实现文件下载的功能,没有将文件下载抽象为一个指令。如果需要在不同页面或组件中多处使用文件下载的功能,则使用自定义指令比较方便。
Step1 定义按钮点击事件
定义一个按钮,给按钮绑定数据 fileUrl ,绑定点击事件 handleDownload 。实现的效果是:点击按钮后下载图片,保存到本地。
<el-button v-model="fileUrl" @click="handleDownload">点击下载图片</el-button>
Step2 在点击事件中实现下载文件
按钮点击事件处理文件下载的方法的具体实现如下:
export default {
name: 'DownloadFile',
data() {
return {
fileUrl: 'http://localhost:8000/1.jpg'
}
},
methods: {
handleDownload(event) {
let url = event.target.value;
let urlArray = url.split('/');
let filename = urlArray[urlArray.length - 1];
const a = document.createElement('a');
fetch(url).then(res => res.blob())
.then(blob => {
a.href = URL.createObjectURL(blob)
a.download = filename
document.body.appendChild(a)
a.click()
})
},
}
}
3. 后端设置跨域
这里使用的springboot实现后端,后端需要进行的跨域设置如下:
【springboot】设置跨域
|