Vue封装文件上传组件(支持图片、PDF、Excel、word预览下载)

一、准备工作

安装预览依赖包:exceljs、mammoth、vue-pdf

二、封装组件

文件上传组件

fileUploadPro.vue。默认预览、下载是true,可通过isPreView、isDownLoad控制

<template>
    <div style="display: flex">
        <el-upload
                multiple
                action=""
                ref="uploadF"
                :show-file-list="false"
                :file-list="fileList"
                :http-request="fileUpLoad"
        >
            <el-button v-if="!readOnly" size="mini" type="primary">点击上传</el-button>
        </el-upload>
        <div style="flex-grow: 1;flex-wrap: wrap">
            <el-tag
                    @close="removeFile(index)"
                    v-for="(tag, index) in fileList"
                    :key="tag.fileId"
                    :closable="true"
                    type="info">
                    <div style="float: left">
                        {{tag.name}}
                    </div>
                    <div v-if="isPreView" class="iconStyle" @click="preView(tag)">
                        <i  class="el-icon-view"></i>
                    </div>
                    <div v-if="isDownLoad" class="iconStyle" @click="downLoad(tag)">
                        <i  class="el-icon-download"></i>
                    </div>
            </el-tag>
        </div>
    </div>
</template>
<script>
    export default {
        name: "fileUploadPro",
        props: {
            fileList: {
                type: Array,
                default: []
            },
            isPreView: {
                type: Boolean,
                default: true
            },
            isDownLoad: {
                type: Boolean,
                default: true
            },
            readOnly:{
                type: Boolean,
                default: false
            }
        },
        data() {
            return {

            }
        },
        methods:{
            fileUpLoad(e) {
                let file = e.file
                let formData = new FormData();
                formData.append("file", file); // 'file' 可变 相当于 input 表单的name 属性
                formData.append("name", file.name);
                formData.append("type", file.type);
                formData.append("size", file.size);
                formData.append("lastModifiedDate", file.lastModifiedDate);
                this.$http({
                    method: 'post',
                    url: "/base/ctBaseFile/saveFile50",
                    data: formData
                }).then((response) => {
                    if (response.data.code === 200) {
                        this.$message.success('上传成功')
                        this.fileList.push({
                            fileId: response.data.data.ctBaseFile.id,
                            name: file.name
                        })
                    }
                })
            },
            removeFile(index) {
                this.fileList.splice(index, 1)
            },
            preView(file) {
                let fileUrl = '';
                let fileType = '';
                if (file) {
                    fileUrl = this.$fileUrl + '/common/getFileRes/' + file.fileId
                    const addTypeArray = file.name.split(".");
                    const addType = addTypeArray[addTypeArray.length - 1];
                    if (addType === "pdf") {
                        fileType = 'pdf'
                    }else if(addType === 'xls' || addType === 'xlsx'){
                        fileType = 'excel'
                    }else if (addType === "doc" || addType === "docx") {
                        fileType = 'word'
                    } else if (["png", "jpg", "jpeg"].includes(addType)) {
                        fileType = 'image'
                    } else {
                        fileType = addType
                    }
                }
                this.$emit("preView",fileType,fileUrl);
                //that.showModal = true
            },
            downLoad(file){
                let a = document.createElement("a");//创建a标签
                a.setAttribute("href", this.$fileUrl + '/common/getFileRes/' + file.fileId);//设置文件下载地址
                a.setAttribute('target', '_blank');//在当前页面创建下载
                document.body.appendChild(a);//添加到body
                a.click();//触发事件
                document.body.removeChild(a);//移除标签
            },
        }
    }
</script>
<style scope>
    .iconStyle{
        float: left;
        width: 16px;
        height: 16px;
        line-height: 16px;
        text-align: center;
        position: relative;
        top:7px;
        margin-left: 6px;
        border-radius: 50%;
        cursor: pointer;
    }
    .iconStyle:hover{
        background-color: #909399;
        color: #fff;
    }
</style>

预览组件

preViewDialog.vue

<template>
    <div>
        <!-- Modal -->
        <el-dialog
                :title="'预览' + fileType"
                :visible.sync="showModal"
                width="70%"
                top="5vh"
                :before-close="handleClose"
                :close-on-click-modal="false"
        >
            <!-- Conditional rendering based on fileType -->
            <div v-if="fileType === 'image'" style="text-align:center">
                <img v-loading="loading" style="height: 400px" :src="fileUrl" alt="预览图片">
            </div>
            <div v-else-if="fileType === 'excel'">
                <el-table v-loading="loading" size="mini" :data="excelData" height="400" width="100%" :show-header="false">
                        <el-table-column width="150" v-for="(cell, key) in excelData[0]" :key="key" :prop="key" :label="key">
                        </el-table-column>
                </el-table>
            </div>
            <div v-else-if="fileType === 'pdf'">
                <!-- Render PDF preview here -->
                <VuePdf v-loading="loading" :src="pdfUrl"></VuePdf>
            </div>
            <div v-else-if="fileType === 'word'">
                <!-- Render Word preview here -->
                <div v-loading="loading" v-html="wordContent"></div>
            </div>
            <div v-else>
                <p>不支持的文件类型或未提供URL。</p>
            </div>

            <!-- Close Button -->
            <span slot="footer" class="dialog-footer">
                <el-button type="primary" @click="downLoad(fileUrl)">下 载</el-button>
                <el-button type="info" @click="closeModal">关 闭</el-button>
            </span>
        </el-dialog>
    </div>
</template>

<script>
    import ExcelJS from 'exceljs';
    import mammoth from 'mammoth';
    import VuePdf from 'vue-pdf';

    export default {
        props: {
            fileType: {
                type: String,
                required: true,
            },
            fileUrl: {
                type: String,
                required: true
            }
        },
        components: {
            VuePdf,
        },
        data() {
            return {
                pdfUrl:'',
                loading: true,
                excelContent: '',
                wordContent: '',
                showModal: false,
                excelData: [],
            };
        },
        mounted() {
            this.showModal = true
            this.loadFile();
        },
        methods: {
            async loadFile() {
                switch (this.fileType) {
                    case 'excel':
                        await this.loadExcel();
                        break;
                    case 'word':
                        await this.loadWord();
                        break;
                    case 'pdf':
                        // 加载 PDF 的逻辑
                        await this.loadPdf();
                        break;
                    default:
                        this.loading = false;
                        break;
                }
            },
            closeModal() {
                this.loading = true;
                this.$emit('close-modal');
            },
            async loadExcel() {
                try {
                    const response = await fetch(this.fileUrl);
                    if (!response.ok) {
                        throw new Error(`HTTP error! Status: ${response.status}`);
                    }
                    const arrayBuffer = await response.arrayBuffer();
                    const workbook = new ExcelJS.Workbook();
                    await workbook.xlsx.load(arrayBuffer);
                    const worksheet = workbook.worksheets[0]; // Assuming you want the first worksheet
                    if (worksheet) {
                        let data = [];
                        worksheet.eachRow((row, rowIndex) => {
                            let rowData = {};
                            row.eachCell((cell, colIndex) => {
                                rowData[`col${colIndex}`] = cell.value;
                            });
                            data.push(rowData);
                        });
                        this.excelData = data;
                    } else {
                        this.excelData = [];
                    }
                } catch (error) {
                    console.error('Error loading Excel:', error);
                    this.excelData = [];
                } finally {
                    this.loading = false;
                }
            },
            async loadWord() {
                try {
                    const response = await fetch(this.fileUrl);
                    const arrayBuffer = await response.arrayBuffer();
                    const result = await mammoth.extractRawText({ arrayBuffer });
                    this.wordContent = result.value;
                } catch (error) {
                    this.wordContent = '加载Word文件失败。';
                } finally {
                    this.loading = false;
                }
            },
            async loadPdf() {
                try {
                    this.pdfUrl = VuePdf.createLoadingTask({
                        url:this.fileUrl,
                        cMapUrl: 'https://cdn.jsdelivr.net/npm/pdfjs-dist@2.6.347/cmaps/',
                        cMapPacked: true
                    })
                    const response = await fetch(this.pdfUrl);
                    if (!response.ok) {
                        throw new Error(`HTTP error! Status: ${response.status}`);
                    }
                } catch (error) {
                    console.error('Error fetching data:', error);
                }finally {
                    this.loading = false
                }
            },
            handleClose() {
                this.closeModal()
            },
            downLoad(file){
                let a = document.createElement("a");//创建a标签
                a.setAttribute("href", file);//设置文件下载地址
                a.setAttribute('target', '_blank');//在当前页面创建下载
                document.body.appendChild(a);//添加到body
                a.click();//触发事件
                document.body.removeChild(a);//移除标签
            },
        },
    };
</script>

<style scoped>
</style>

三、组件调用

<template>
    <div>
        <fileUploadPro
                :file-list.sync="fileList"
                :isPreView="true"
                :isDownLoad="false"
                @preView="preView"/>
        
        <previewDialog
                v-if="showModal"
                :file-type="fileType"
                :file-url="fileUrl"
                @close-modal="showModal = false"/>
    </div>
</template>
<script>
    import previewDialog from '../components/previewDialog';
    import fileUploadPro from "../components/fileUploadPro";
    export default {
        name: "parentXXX",
        components:{previewDialog,fileUploadPro},
        data() {
            return{
              fileList:[],
              fileType: '',
              fileUrl:'',
              showModal: false,
            }
        },
        methods:{
            preView(type,url){
                this.fileUrl = url;
                this.fileType = type;
                this.showModal = true
            },

        }
    }
</script>

四、效果

 

 

 

相关推荐

  1. SperingBoot+vue文件&下载&

    2024-07-18 11:52:04       59 阅读
  2. vue2自定义封装图片组件

    2024-07-18 11:52:04       48 阅读
  3. Vue【七】实现图片

    2024-07-18 11:52:04       34 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-18 11:52:04       52 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-18 11:52:04       54 阅读
  3. 在Django里面运行非项目文件

    2024-07-18 11:52:04       45 阅读
  4. Python语言-面向对象

    2024-07-18 11:52:04       55 阅读

热门阅读

  1. Docker 容器中的 Docker Compose 简介

    2024-07-18 11:52:04       20 阅读
  2. Spring boot 2.0 升级到 3.3.1 的相关问题 (三)

    2024-07-18 11:52:04       19 阅读
  3. NLP篇10 NLP总结

    2024-07-18 11:52:04       16 阅读
  4. 自然语言处理NLP--文本相似度面试题

    2024-07-18 11:52:04       15 阅读
  5. vue中获取剪切板中的内容

    2024-07-18 11:52:04       20 阅读
  6. 面向过程编程和面向对象编程

    2024-07-18 11:52:04       16 阅读
  7. 【Vue】 @/ 和 ./ 区别

    2024-07-18 11:52:04       18 阅读
  8. 特朗普主题meme币受消息面和选情影响大幅波动

    2024-07-18 11:52:04       16 阅读
  9. Git【撤销远程提交记录】

    2024-07-18 11:52:04       20 阅读
  10. android的跨进程通讯方式

    2024-07-18 11:52:04       14 阅读