vue3點(diǎn)擊按鈕下載文件功能的代碼實(shí)現(xiàn)
VUE3實(shí)現(xiàn)點(diǎn)擊按鈕下載文件功能
在寫(xiě)vue項(xiàng)目時(shí),有個(gè)需求是點(diǎn)擊表格中某一行的下載按鈕,然后開(kāi)始下載這一行對(duì)應(yīng)的文件,效果如下:

表格每行的最右側(cè)的藍(lán)色按鈕就是點(diǎn)擊下載,這里涉及到原生的JavaScript寫(xiě)法,長(zhǎng)期在寫(xiě)vue項(xiàng)目,原生的寫(xiě)法都很陌生了,記錄一下
先上組件的原始代碼:
<template>
<BreadCrumb ref="breadCrumb" :item="item"></BreadCrumb>
<div class="pane-content">
<div class="pane-top">
<div class="module-common-header">
<div class="button-wrapped">
<el-upload v-model:file-list="fileList" class="upload-demo" multiple :on-exceed="handleExceed"
action="http://127.0.0.1:3088/api/files/uploadFile" :on-success="handleSuccess"
:show-file-list="false">
<el-button type="primary">上傳文件</el-button>
</el-upload>
</div>
</div>
<div class="module-common-table">
<el-table :data="tableData" border style="width: 100%">
<el-table-column type="index" width="50"></el-table-column>
<el-table-column show-overflow-tooltip v-for="(item, index) in tableLabel" :key="index"
:prop="item.prop" :label="item.label" />
<el-table-column fixed="right" label="操作">
<template #default="scope">
<el-button type="primary" size="small" @click="downloadFile(scope.row)">下載文件</el-button>
<el-popconfirm title="確定刪除該文件嗎?" confirm-button-text="是" cancel-button-text="否"
@confirm="deleteFile(scope.row)">
<template #reference>
<el-button type="danger" size="small">刪除文件</el-button>
</template>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
</div>
</div>
<div class="table-footer">
<el-pagination :page-size="10" :pager-count="5" layout="prev, pager, next" :total="filesLength"
:current-page="paginationData.currentPage" @current-change="currentPageChange" />
</div>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import {
getFilesLengthAPI,
returnFileListDataAPI,
bindFileAndUserAPI,
deleteFileAPI,
updateDownloadTimesAPI,
} from '@/apis/files'
const item = ref({
first: '合同管理',
})
const tableData = ref([])
const tableLabel = [
{ prop: 'file_name', label: '合同名' },
{ prop: 'file_size', label: '合同文件大小' },
{ prop: 'upload_person', label: '上傳人' },
{ prop: 'download_number', label: '下載次數(shù)' },
{ prop: 'upload_time', label: '上傳時(shí)間' },
// { prop: 'message_content', label: '消息內(nèi)容' },
]
const fileList = ref([])
// 上傳成功之后的回調(diào)函數(shù)
const handleSuccess = async (response, uploadFile, uploadFiles) => {
if (response.status == 0) {
const name = JSON.parse(localStorage.user).userInfo.name
const url = response.url
const res = await bindFileAndUserAPI({ name, url })
if (res.status == 0) {
ElMessage.success('上傳成功')
getCurrentPageData()
getFilesLength()
}
else ElMessage.error('上傳失敗')
} else {
ElMessage.error('上傳失敗,請(qǐng)檢查是否重名')
}
}
// 超出文件個(gè)數(shù)限制的鉤子
const handleExceed = (uploadFile, uploadFiles) => { }
// 下載文件
const downloadFile = async (row) => {
// console.log(row)
const { download_number, id } = row
await updateDownloadTimesAPI({ download_number, id })
const url = row.file_url
const link = document.createElement('a')
link.href = url
link.setAttribute('download', '')
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
getCurrentPageData()
}
// 刪除文件
const deleteFile = async row => {
const res = await deleteFileAPI({ id: row.id })
if (res.status == 0) ElMessage.success('刪除成功')
else ElMessage.error('刪除失敗')
getCurrentPageData()
getFilesLength()
}
// 分頁(yè)
const paginationData = ref({
// 總頁(yè)數(shù)
pageCount: 1,
// 當(dāng)前頁(yè)
currentPage: 1,
})
// 獲取數(shù)據(jù)總數(shù)
const filesLength = ref(0)
const getFilesLength = async () => {
const res = await getFilesLengthAPI()
filesLength.value = res.filesCount
}
// 獲取首頁(yè)數(shù)據(jù)
const getFirstPageList = async () => {
const res = await returnFileListDataAPI({ page: 1 - 1 })
res.forEach(item => {
item.upload_time = item.upload_time?.slice(0, 19)
item.file_size = Math.floor(item.file_size) + 'kb'
})
tableData.value = res
}
// 頁(yè)碼切換
const currentPageChange = async (val) => {
paginationData.value.currentPage = val
const res = await returnFileListDataAPI({ page: val - 1 })
res.forEach(item => {
item.upload_time = item.upload_time?.slice(0, 19)
item.file_size = Math.floor(item.file_size) + 'kb'
})
tableData.value = res
}
// 增刪數(shù)據(jù)后,需要刷新當(dāng)前頁(yè)數(shù)據(jù)
const getCurrentPageData = async () => {
const res = await returnFileListDataAPI({ page: paginationData.value.currentPage - 1 })
res.forEach(item => {
item.upload_time = item.upload_time?.slice(0, 19)
item.file_size = Math.floor(item.file_size) + 'kb'
})
tableData.value = res
}
onMounted(() => {
getFilesLength()
getFirstPageList()
})
</script>
<style lang="scss" scoped>
.pane-content {
margin-top: 8px;
display: flex;
flex-direction: column;
justify-content: space-between;
height: calc(100vh - 118px);
background: #fff;
.pane-top {
padding: 8px;
background: #fff;
.module-common-header {
padding: 0 20px;
display: flex;
align-items: center;
justify-content: flex-end;
}
.module-common-table {
min-height: 10px;
padding: 10px 20px 20px;
margin-bottom: 8px;
background: #fff;
}
}
.table-footer {
display: flex;
justify-content: flex-end;
margin-bottom: 8px;
}
}
</style>
我用的是vue3+setup語(yǔ)法糖寫(xiě)法,代碼比較長(zhǎng),關(guān)注一下與下載相關(guān)的代碼:
html部分
<el-table-column fixed="right" label="操作">
<template #default="scope">
<el-button type="primary" size="small" @click="downloadFile(scope.row)">下載文件</el-button>
<el-popconfirm title="確定刪除該文件嗎?" confirm-button-text="是" cancel-button-text="否"
@confirm="deleteFile(scope.row)">
<template #reference>
<el-button type="danger" size="small">刪除文件</el-button>
</template>
</el-popconfirm>
</template>
</el-table-column>
其實(shí)就是表格最后一列,添加兩個(gè)按鈕,然后為這個(gè)按鈕傳入本行的所有數(shù)據(jù),下載文件按鈕添加點(diǎn)擊函數(shù)downloadFile,并傳入行數(shù)據(jù)作為參數(shù)
JavaScript部分
js部分是實(shí)現(xiàn)點(diǎn)擊下載的核心,看downloadFile方法
// 下載文件
const downloadFile = async (row) => {
// console.log(row)
const { download_number, id } = row // 從行中獲取下載文件接口的傳入?yún)?shù)
await updateDownloadTimesAPI({ download_number, id }) // 調(diào)用下載文件的接口
const url = row.file_url // 從行數(shù)據(jù)中獲取下載鏈接
const link = document.createElement('a') // 創(chuàng)建鏈接標(biāo)簽,即a標(biāo)簽,并將dom命名為link
link.href = url // 為dom為link的元素添加鏈接
link.setAttribute('download', '') // 為link設(shè)置下載屬性
document.body.appendChild(link) // 把創(chuàng)建并配置好的link dom添加到頁(yè)面文檔中
link.click() // 模擬dom的點(diǎn)擊事件
document.body.removeChild(link) // 從文檔中移出link節(jié)點(diǎn)
getCurrentPageData() // 調(diào)用寫(xiě)好的方法刷新數(shù)據(jù)
}
相關(guān)的解釋我都寫(xiě)在了上面的代碼中,其中下面兩個(gè)步驟不是必須的:
- await updateDownloadTimesAPI({ download_number, id }) ,點(diǎn)擊下載后,要在數(shù)據(jù)庫(kù)中標(biāo)記,增加點(diǎn)擊量
- getCurrentPageData(),因?yàn)椴僮髁藬?shù)據(jù)庫(kù),數(shù)據(jù)要更新,所以這是為了更新數(shù)據(jù)
以上就是vue3實(shí)現(xiàn)點(diǎn)擊按鈕下載文件功能的詳細(xì)內(nèi)容,更多關(guān)于vue3下載文件功能的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Vue中mintui的field實(shí)現(xiàn)blur和focus事件的方法
今天小編就為大家分享一篇Vue中mintui的field實(shí)現(xiàn)blur和focus事件的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-08-08
vue中使用echarts實(shí)現(xiàn)動(dòng)態(tài)數(shù)據(jù)綁定以及獲取后端接口數(shù)據(jù)
總結(jié)一下自己最近項(xiàng)目中用echarts動(dòng)態(tài)獲取接口數(shù)據(jù)并畫(huà)圖的方法,下面這篇文章主要給大家介紹了關(guān)于vue中使用echarts實(shí)現(xiàn)動(dòng)態(tài)數(shù)據(jù)綁定以及獲取后端接口數(shù)據(jù)的相關(guān)資料,需要的朋友可以參考下2022-07-07
解決vue-cli 打包后自定義動(dòng)畫(huà)未執(zhí)行的問(wèn)題
今天小編就為大家分享一篇解決vue-cli 打包后自定義動(dòng)畫(huà)未執(zhí)行的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-11-11
基于vue.js實(shí)現(xiàn)分頁(yè)查詢功能
這篇文章主要為大家詳細(xì)介紹了基于vue.js實(shí)現(xiàn)分頁(yè)查詢功能,vue.js實(shí)現(xiàn)數(shù)據(jù)庫(kù)分頁(yè),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-12-12
Vue3 + Element Plus 實(shí)現(xiàn)表格全選/反選/禁用功能(示例詳解)
本文詳細(xì)介紹了如何使用Vue3組合式API和ElementPlus實(shí)現(xiàn)表格的全選/反選/禁用功能,并分享了分頁(yè)保持、視覺(jué)提示優(yōu)化、性能優(yōu)化等技巧,同時(shí),還提供了常見(jiàn)問(wèn)題的解決方案和擴(kuò)展思考,幫助開(kāi)發(fā)者構(gòu)建功能豐富且用戶體驗(yàn)良好的表格組件,感興趣的朋友一起看看吧2025-03-03
Vue3+Vite多項(xiàng)目多dist打包操作實(shí)現(xiàn)方式
本文介紹了如何使用Vue3和Vite搭建多項(xiàng)目環(huán)境,并在打包時(shí)生成多個(gè)dist包,通過(guò)創(chuàng)建主項(xiàng)目環(huán)境、配置多個(gè)dist包、以及執(zhí)行打包操作,可以實(shí)現(xiàn)多個(gè)子項(xiàng)目的獨(dú)立管理2025-12-12
vue3中g(shù)etCurrentInstance示例講解
這篇文章主要給大家介紹了關(guān)于vue3中g(shù)etCurrentInstance的相關(guān)資料,文中還介紹了Vue3中關(guān)于getCurrentInstance的大坑,需要的朋友可以參考下2023-03-03
Vue手寫(xiě)dialog組件模態(tài)框過(guò)程詳解
這篇文章主要介紹了Vue手寫(xiě)dialog組件模態(tài)框過(guò)程,dialog組件為模態(tài)框,因此應(yīng)該是固定定位到頁(yè)面上面的,并且需要留一定的插槽來(lái)讓使用者自定義顯示內(nèi)容2023-02-02
詳解Vue微信授權(quán)登錄前后端分離較為優(yōu)雅的解決方案
這篇文章主要介紹了詳解Vue微信授權(quán)登錄前后端分離較為優(yōu)雅的解決方案,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-06-06

