vue使用elementUI的upload上传文件封装

这篇文章的目的

将文件上传的方法封装一下,供大家统一调用,

话不多说,直接上代码

upload 核心参数说明

  1. action 上传的地址
  2. accept 接受上传的文件类型
  3. multiple 是否开启多文件上传模式
  4. limit 限制上传个数
  5. fileList 文件列表
  6. disabled 是否禁用

upload 核心方法说明

  • before-upload 上传文件之前的钩子.
  • on-success 上传成功的钩子函数
  • on-error 文件上传失败时的钩子
  • on-exceed 文件超出个数限制时的钩子
  • on-remove 文件列表移除文件时的钩子
  • on-preview 点击文件列表中已上传的文件时的钩子.
  • on-progress 文件上传时的钩子 进度条展示的基础

核心局部代码说明

html中

插槽的使用

子组件

html 复制代码
   <slot name="uploadBtn"></slot>

调用上传组件的父组件

html 复制代码
    <uploadBtn>
        <template v-slot="uploadBtn">
            <img src='http://test/upload.img'></img>
        </template>
    </uploadBtn>

说明

使用了具名插槽 将上传的按钮放在父组件调用子组件标签的容器中,这样的好处是:随意定制按钮不需要写一堆的条件判断,且可定制上传按钮


js中

office 自动预览的使用

data定义office基础路径

javascript 复制代码
    officeOnlineAddress:'https://view.officeapps.live.com/op/view.aspx?src=',

office基础路径拼接文件路径并预览

javascript 复制代码
   const preveiewURL = this.officeOnlineAddress + target
   window.open(preveiewURL)

说明

office基础路径拼接文件路径并用window.open即可实现文件的预览

beforeUpload 上传文件之前的拦截处理

代码

javascript 复制代码
    beforeUpload(file) {
        const { name = '', size } = file
        if (size > this.maxSize * 1024 * 1000) {
            this.$Message.warning(`文件最大仅支持${this.maxSize}M`)
            return false
        }

        if (!this.acceptTypeList.includes(name.split('.').pop())) {
            this.$Message.warning(
                `文件格式仅支持${this.acceptTypeList.join(',')}`
            )
            return false
        }
    },

说明

  • 文件大小大于父组件传入的maxSize则拦截并提示
  • 文件格式不正确则拦截并提示
  • beforeUpload函数体中,如果函数的返回值是false,则终止上传

文件预览的操作

代码

javascript 复制代码
    preview (data) {
        const { url, response = {} } = data || {}
        let name = data.name
        const downLoadTypeList = this.downLoadTypeList
        const preveiwTypeList = this.preveiwTypeList
        if (!name) {
            name = ''
        }
        const suffixFileType = name.split('.').pop()
        if (downLoadTypeList.includes(suffixFileType)) {
            //下载 'doc', 'docx', 'xlsx', 'xls', 'txt' 文件
            name = name.replace(/&/g, '') // & 不兼容
            const target = encodeURIComponent(
                Base64.encode(
                    `${
                        location.origin
                    }/api/abk/web/v1/resource/file?fileId=${
                        url || response.data
                    }&fullfilename=${name}&sid=4AC67ADB4E264AB0A8B899A671072875`
                )
            )
            if (
                this.officePreviewFlag &&
                this.officeType.includes(suffixFileType)
            ) {
                // office预览的
                const preveiewURL = this.officeOnlineAddress + target
                window.open(preveiewURL)
            } else {
                // 非office预览
                window.open(
                    `https://test/preview/onlinePreview?url=${target}`,
                    '_blank'
                )
            }
        } else if (preveiwTypeList.includes(suffixFileType)) {
            //新窗口打开 预览图片文件
            window.open(
                '/api/abk/web/v1/resource/file?fileId=' +
                    (url || response.data),
                '_blank'
            )
        }
    },

说明

  • 使用 name.split('.').pop() 拿到文件的后缀名
  • 根据传入的 downLoadTypeList(需要下载的文件类型)、preveiwTypeList(可以直接预览的文件类型)、officePreviewFlag(office文件类型)以及officePreviewFlag(是否启用office预览)和文件后缀名匹配
  • 需要下载的文件类型 根据后端的下载基础路径拼接得到下载地址,并结合windwo.open下载
  • 可以直接预览的文件类型 根据后端的预览基础路径拼接得到下载地址,并结合windwo.open 预览
  • office文件类并且启用了office预览直接调用office预览路径(https://view.officeapps.live.com/op/view.aspx?src=)

进度条处理

html

html 复制代码
<el-progress v-if="showProcessFlag&&processFlag" :percentage="loadProcess"></el-progress>

js

JavaScript 复制代码
   onProgressFn(event, file, fileList){
    this.processFlag = true
    this.loadProcess =  event.percent.toFixed(2)
    if(this.loadProcess>=100){
        this.loadProcess= 100
        this.$nextTick(()=>{
            this.processFlag = false
        })
    }
    }

说明

  • 用户启用了进度条(showProcessFlag为true) 并且 processFlag的值为true(当进度条的值存在并且小于100时)
  • 当进度大于等于100时需要隐藏进度条,为了保险起见,此处加了 $nextTick,当然了setTimeout(()=>{},0)也可以
javascript 复制代码
<template>
    <div>
        <!--action="/api/abk/web/v1/resource/file" -->
        <el-upload
            :action="actionUrl"
            style="width: 100%"
            :on-success="(response, file) => successUpload(response, file)"
            :on-error="errorUpload"
            :accept="acceptTypeList.join('|')"
            :before-upload="beforeUpload"
            :multiple="multiple"
            :limit="maxLimit"
            :on-exceed="handleExceed"
            :file-list="fileList"
            :disabled="disabledFlag"
            :on-remove="(file, fileList) => removeFile(file, fileList)"
            :on-preview="(file) => preview(file)"
            :on-progress="(event, file, fileList)=>onProgressFn(event, file, fileList)"
        >
        <!-- 上传的按钮 或者 icon 通过具名插槽的方式 -->
          <slot name="uploadBtn"></slot>
        </el-upload>
        <el-progress v-if="showProcessFlag&&processFlag" :percentage="loadProcess"></el-progress>
    </div>
</template>

<script>
export default {
    name: 'UploadFile',
    props: {
        actionUrl: {
            //上传的地址
            type: String,
            default: '',
        },
        acceptTypeList: {
            //接受的文件类型
            type: Array,
            default: () => {
                return []
                //  ['doc', 'docx', 'xlsx', 'xls', 'txt', 'pdf','jpg','jpeg','png','zip,'rar']
            },
        },
        multiple: {//是否开启多图上传
            type: Boolean,
            default: false,
        },
        maxLimit: {
            // 最大上传个数限制
            type: Number | String,
            default: 1,
        },
        maxSize:{
            // 文件上传的最大体积 M
            type: Number | String,
            default: 4,

        },
        disabledFlag: {
            //是否禁用
            type: Boolean,
            default: false,
        },
        fileList: {//文件列表
            type: Array,
            default: () => {
                return []
            },
        },
        extraData: {}, //上传时的额外参数 如 name等
        /* 
        {
            name:'12321'
        }
        */
        dragFlag: {
            type: Boolean,
            default: true, //是否启用拖拽上传 此处默认启用  element 官方默认是 不启用的
        },
        downLoadTypeList: {
            //需要下载的文件类型
            type: Array,
            default: () => {
                return ['doc', 'docx', 'xlsx', 'xls', 'txt']
            },
        },
        preveiwTypeList: {
            //需要预览的文件类型
            type: Array,
            default: () => {
                return ['pdf', 'jpg', 'jpeg', 'png']
            },
        },
        officePreviewFlag: {
            //是否启用office在线预览
            type: Boolean,
            default: false,
        },
        showProcessFlag:{
            //是否显示进度条
            type: Boolean,
            default: false,
        },
    },
    // office预览
    // https://view.officeapps.live.com/op/view.aspx?src=
    // https://view.officeapps.live.com/op/view.aspx?src=文档地址
    //
    data() {
        return {
            officeOnlineAddress:
                'https://view.officeapps.live.com/op/view.aspx?src=',
            officeType: ['doc', 'docx', 'xlsx', 'xls'],
            processFlag:false,//是否显示进度条
            loadProcess:0//进度条的刻度值
        }
    },

    mounted() {},

    methods: {
        // 上传图片 成功
        successUpload(response, file) {
            if (response.rt.status === 200) {
                this.fileList.push({
                    url: response.data,
                    name: file.name,
                })
            } else {
                this.$Message.info(response.data)
            }
        },
        errorUpload(res) {
            this.$Message.info('上传失败请重试!')
        },
        beforeUpload(file) {
            const { name = '', size } = file
            if (size > this.maxSize * 1024 * 1000) {
                this.$Message.warning(`文件最大仅支持${this.maxSize}M`)
                return false
            }

            if (!this.acceptTypeList.includes(name.split('.').pop())) {
                this.$Message.warning(
                    `文件格式仅支持${this.acceptTypeList.join(',')}`
                )
                return false
            }
        },
        handleExceed(files, fileList) {
            this.$Message.warning(
                `当前限制选择 10 个文件,本次选择了 ${
                    files.length
                } 个文件,共选择了 ${files.length + fileList.length} 个文件`
            )
        },
        // 移除文件
        removeFile(file, data) {
            console.log(file, data)
            this.fileList = data
        },
        // 预览
        preview (data) {
            const { url, response = {} } = data || {}
            let name = data.name
            const downLoadTypeList = this.downLoadTypeList
            const preveiwTypeList = this.preveiwTypeList
            if (!name) {
                name = ''
            }
            const suffixFileType = name.split('.').pop()
            if (downLoadTypeList.includes(suffixFileType)) {
                //预览 'doc', 'docx', 'xlsx', 'xls', 'txt' 文件
                name = name.replace(/&/g, '') // & 不兼容
                const target = encodeURIComponent(
                    Base64.encode(
                        `${
                            location.origin
                        }/api/abk/web/v1/resource/file?fileId=${
                            url || response.data
                        }&fullfilename=${name}&sid=4AC67ADB4E264AB0A8B899A671072875`
                    )
                )
                if (
                    this.officePreviewFlag &&
                    this.officeType.includes(suffixFileType)
                ) {
                    // office预览的
                    const preveiewURL = this.officeOnlineAddress + target
                    window.open(preveiewURL)
                } else {
                    // 非office预览
                    window.open(
                        `https://test/preview/onlinePreview?url=${target}`,
                        '_blank'
                    )
                }
            } else if (preveiwTypeList.includes(suffixFileType)) {
                //新窗口打开 预览图片文件
                window.open(
                    '/api/abk/web/v1/resource/file?fileId=' +
                        (url || response.data),
                    '_blank'
                )
            }
        },
        onProgressFn(event, file, fileList){
            this.processFlag = true
            this.loadProcess =  event.percent.toFixed(2)
            if(this.loadProcess>=100){
                this.loadProcess= 100
                this.$nextTick(()=>{
                    this.processFlag = false
                })
            }
        }
    },
}
</script>

<style lang="scss" scoped>
</style>

List){
            this.processFlag = true
            this.loadProcess =  event.percent.toFixed(2)
            if(this.loadProcess>=100){
                this.loadProcess= 100
                this.$nextTick(()=>{
                    this.processFlag = false
                })
            }
        }
    },
}
</script>

<style lang="scss" scoped>
</style>
相关推荐
Pedantic1 小时前
SwiftUI 手势层级(Gesture Hierarchy)详解
前端
飘尘1 小时前
前端转型全栈(Java后端)的快速上手指引
前端·后端·全栈
一颗烂土豆2 小时前
Meshopt 压缩深度解析,为什么它比 Draco 更快
前端·javascript·webgl
浏览器工程师3 小时前
AI Agent 接浏览器任务,先别让它一路点到底
前端·后端
雨季mo浅忆3 小时前
VSCode自动格式化三要素
前端
爱勇宝3 小时前
深扒 Anthropic 1680 位工程师简历:应届生几乎没机会,AI 公司最缺的不是博士
前端·后端·程序员
kyriewen4 小时前
同事每天催我 Code Review,我写了个脚本让 AI 替我 review PR——现在他反过来催 AI 了
前端·javascript·ai编程
user20585561518136 小时前
Windows 项目安装时报 `node-sass` 错误,如何快速处理
前端
LiaCode6 小时前
Redis 在生产项目的使用
前端·后端