VUE3 implements the function of clicking a button to download a file

VUE3 implements the function of clicking a button to download a file

When writing a vue project, there is a requirement to click the download button of a certain row in the table, and then start downloading the file corresponding to this row. The effect is as follows:

image-20231229083122632

The blue button on the far right of each row of the table is to click to download. This involves the native JavaScript writing method. I have been writing Vue projects for a long time, and the native writing method is very unfamiliar. Please record it.

First, the original code of the component:

<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>

I use the vue3+setup syntactic sugar writing method. The code is relatively long. Pay attention to the code related to downloading:

html part

<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>

In fact, it is the last column of the table. Add two buttons, and then pass in all the data of this row for this button. Add the click function downloadFile to the download file button, and pass in the row data as a parameter.

JavaScript part

The js part is the core of realizing click download, see downloadFile method

// 下载文件
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()									// 调用写好的方法刷新数据
}

I have written the relevant explanations in the above code, but the following two steps are not necessary:

  1. await updateDownloadTimesAPI({ download_number, id }) , after clicking to download, mark it in the database to increase the number of clicks
  2. getCurrentPageData(), because the database is operated and the data needs to be updated, so this is to update the data

Guess you like

Origin blog.csdn.net/u012848304/article/details/135282481