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>
相关推荐
发呆的薇薇°8 分钟前
react里使用Day.js显示时间
前端·javascript·react.js
跑跑快跑12 分钟前
React vite + less
前端·react.js·less
web1368856587121 分钟前
ctfshow_web入门_命令执行_web29-web39
前端
GISer_Jing29 分钟前
前端面试题合集(一)——HTML/CSS/Javascript/ES6
前端·javascript·html
清岚_lxn30 分钟前
es6 字符串每隔几个中间插入一个逗号
前端·javascript·算法
胡西风_foxww33 分钟前
【ES6复习笔记】Map(14)
前端·笔记·es6·map
星就前端叭34 分钟前
【开源】一款基于SpringBoot的智慧小区物业管理系统
java·前端·spring boot·后端·开源
缘友一世35 分钟前
将现有Web 网页封装为macOS应用
前端·macos·策略模式
刺客-Andy1 小时前
React 第十九节 useLayoutEffect 用途使用技巧注意事项详解
前端·javascript·react.js·typescript·前端框架
谢道韫6661 小时前
今日总结 2024-12-27
开发语言·前端·javascript