vue3点击按钮下载文件功能的代码实现

 更新时间:2024年01月02日 09:40:09   作者:栀椩  
在写vue项目时,有个需求是点击表格中某一行的下载按钮,然后开始下载这一行对应的文件,所以本文小编给大家介绍了使用vue3实现点击按钮下载文件功能,文中有详细的代码示例供大家参考,需要的朋友可以参考下

VUE3实现点击按钮下载文件功能

在写vue项目时,有个需求是点击表格中某一行的下载按钮,然后开始下载这一行对应的文件,效果如下:

表格每行的最右侧的蓝色按钮就是点击下载,这里涉及到原生的JavaScript写法,长期在写vue项目,原生的写法都很陌生了,记录一下

先上组件的原始代码:

<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: '下载次数' },
    { prop: 'upload_time', label: '上传时间' },
    // { prop: 'message_content', label: '消息内容' },
]

const fileList = ref([])
// 上传成功之后的回调函数
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('上传失败,请检查是否重名')
    }

}
// 超出文件个数限制的钩子
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()
}

// 分页
const paginationData = ref({
    // 总页数
    pageCount: 1,
    // 当前页
    currentPage: 1,
})
// 获取数据总数
const filesLength = ref(0)
const getFilesLength = async () => {
    const res = await getFilesLengthAPI()
    filesLength.value = res.filesCount
}
// 获取首页数据
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
}
// 页码切换
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
}
// 增删数据后,需要刷新当前页数据
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语法糖写法,代码比较长,关注一下与下载相关的代码:

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>

其实就是表格最后一列,添加两个按钮,然后为这个按钮传入本行的所有数据,下载文件按钮添加点击函数downloadFile,并传入行数据作为参数

JavaScript部分

js部分是实现点击下载的核心,看downloadFile方法

// 下载文件
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')				// 创建链接标签,即a标签,并将dom命名为link
    link.href = url											// 为dom为link的元素添加链接
    link.setAttribute('download', '')						// 为link设置下载属性
    document.body.appendChild(link)							// 把创建并配置好的link dom添加到页面文档中
    link.click()											// 模拟dom的点击事件
    document.body.removeChild(link)							// 从文档中移出link节点
    getCurrentPageData()									// 调用写好的方法刷新数据
}

相关的解释我都写在了上面的代码中,其中下面两个步骤不是必须的:

  • await updateDownloadTimesAPI({ download_number, id }) ,点击下载后,要在数据库中标记,增加点击量
  • getCurrentPageData(),因为操作了数据库,数据要更新,所以这是为了更新数据

以上就是vue3实现点击按钮下载文件功能的详细内容,更多关于vue3下载文件功能的资料请关注脚本之家其它相关文章!

相关文章

  • vue使用svg文件补充-svg放大缩小操作(使用d3.js)

    vue使用svg文件补充-svg放大缩小操作(使用d3.js)

    这篇文章主要介绍了vue使用svg文件补充-svg放大缩小操作(使用d3.js),具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-09-09
  • vue基础之v-bind属性、class和style用法分析

    vue基础之v-bind属性、class和style用法分析

    这篇文章主要介绍了vue基础之v-bind属性、class和style用法,结合实例形式分析了vue.js中v-bind绑定及class、style样式控制相关操作技巧,需要的朋友可以参考下
    2019-03-03
  • vue.js动态修改background-image问题

    vue.js动态修改background-image问题

    这篇文章主要介绍了vue.js动态修改background-image问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-08-08
  • Vue2.0 组件传值通讯的示例代码

    Vue2.0 组件传值通讯的示例代码

    本篇文章主要介绍了Vue2.0 组件传值通讯的示例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-08-08
  • 解决Vue3报错:Property “xxx“ was accessed during render but is not defined on instance.

    解决Vue3报错:Property “xxx“ was accessed during render but

    这篇文章主要给大家介绍了关于解决Vue3报错:Property “xxx“ was accessed during render but is not defined on instance.的相关资料,文中通过图文介绍的非常详细,需要的朋友可以参考下
    2023-01-01
  • 基于Vue3的全屏拖拽上传组件

    基于Vue3的全屏拖拽上传组件

    本文主要介绍了基于Vue3的全屏拖拽上传组件,其实思路上与其他拖拽上传组件基本一样,都是指定一个区域可拖拽,然后读取文件在上传,需要的朋友们下面随着小编来一起学习学习吧
    2021-09-09
  • vue项目中使用rem,在入口文件添加内容操作

    vue项目中使用rem,在入口文件添加内容操作

    这篇文章主要介绍了vue项目中使用rem,在入口文件添加内容操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-11-11
  • 老生常谈vue3组件通信方式

    老生常谈vue3组件通信方式

    这篇文章主要介绍了vue3组件通信方式,面试题经常会问到vue3组件间的通信方式,今天就通过实例代码给大家详细介绍下,对vue3组件通信相关知识感兴趣的朋友一起看看吧
    2022-08-08
  • Vue3中操作ref的四种使用方式示例代码(建议收藏)

    Vue3中操作ref的四种使用方式示例代码(建议收藏)

    这篇文章主要介绍了Vue3中操作ref的四种使用方式示例代码(建议收藏),本文通过示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-04-04
  • vue实现弹幕功能

    vue实现弹幕功能

    这篇文章主要介绍了vue实现弹幕功能,本文通过实例代码给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-10-10

最新评论