Element-ui之upload封装

二次封装el-upload组件,以便使用。

包含两个部分:创建、引用。

说明:
1. 包含:组件本身有的各种属性控制、是否拖拽、扩展按钮、上传前的各种校验(图片的话需要压缩,压缩方法在之前的文章有,这里不再重复写)、预览附件(这里支持pdf和图片预览,支持Excel下载,word没写,原理应该和Excel一样,其余的暂不支持)等。
2. 各个属性灵活运用,也可自己添加、更改相关属性配置。
3. 这里设置从父组件中传输过来的对象和数组都用JSON串接收,目的是为了方便监听数值变化。
4. 代码为手写,已检查,但不保证没有单词写错,如报错,请检查一下单词的拼写。

一、创建封装文件 - comUpload.vue:
<template>
	<div>
		<el-upload
			ref="comUpload"
			:class="{ 'is-drag': drag }"
			:drag="drag"
			:accept="accept"
			:action="action"
			:multiple="multiple"
			:disabled="disabled"
			:limit="limit"
			:file-list="fileList"
			:on-preview="onPreview"
			:on-remove="onRemove"
			:on-success="onSuccess"
			:before-upload="beforeUpload"
			:before-remove="beforeRemove"
			:on-exceed="onExceed"
			:on-progress="onProgress"
			:on-error="onError"
			:data="data"
		>
			<i v-if="drag" class="el-icon-upload"></i>
			<div v-if="drag" class="el-upload_text">
				将文件拖到此处,或<em>点击上传</em>
			</div>
			<el-button v-if="!drag" slot="trigger" size="small" type="primary">点击上传</el-button>
			
			<!-- 扩展按钮 -->
			<template v-if="buttonList">
				<el-button
					v-for="itemB in buttonList"
					:key="itemB.id"
					style="margin-left: 10px;"
					size="small"
					:type="itemB.type"
					@click="buttonClick(itemB)"
				>{{ itemB.label }}</el-button>
			</template>

			<!-- 提示语 -->
			<div slot="tip" class="el-upload_tip">
				<span v-if="acceptText">只能上传{{ acceptText }}文件</span>
				<span v-if="acceptText && limit"></span>
				<span v-if="limit">最多上传{{ limit }}</span>
				<span v-if="(limit && size) || (acceptText && size)"></span>
				<span v-if="size">每个文件不超过{{ size }}MB</span>
				<p v-if="tips" class="el-upload__tip_tips">{{ tips }}</p>
			</div>
		</el-upload>

		<!-- pdf预览组件,前篇文章已有介绍 -->
		<com-pdf-show ref="comPdfShowRef"></com-pdf-show>

		<!-- 图片预览组件,由el-dialog全屏展示,img标签展示,没什么技术含量,这里就不写了 -->
		<com-img-show ref="comImgShowRef"></com-img-show>
	</div>
</template>
<script>
	import comImgShow from './comImgShow';
	import comPdfShow from './comPdfShow';

	export default {
		name: 'ComUpload',
		components: { comImgShow, comPdfShow },
		props: {
			multiple: { // 是否可以上传多个,默认true,非必传
				type: Boolean,
				default: true,
			},
			drag: { // 是否可拖拽,默认false,非必传
				type: Boolean,
				default: false,
			},
			accept: { // 上传文件的格式限制,默认不限制,非必传
				type: String,
				default: '',
			},
			accepts: { // 当drag为true时,accept设置的话拖拽无效,故加此属性限制文件格式,在上传前校验;默认不限制,非必传
				type: String,
				default: '',
			},
			acceptText: String, // 上传文件格式限制文字说明,放入提示语中用来展示;默认空,非必传。
			action: { // 上传文件地址,默认'/upload';非必传
				type: String,
				default: '/upload',
			},
			disabled: { // 是否禁用,默认false;非必传
				type: Boolean,
				default: false,
			},
			limit: Number, // 最大允许上传个数,默认不限制,非必传
			size: Number, // 最大允许上传文件大小,单位为MB,默认不限制,非必传
			initFiles: String, // 初始化附件数据数组JSON串,默认空,非必传
			paramsData: String, // 上传文件时附带的额外参数对象JSON串,默认空,非必传
			buttons: String, // 额外按钮数组JSON串,默认空,非必传
			tips: String, // 额外需添加的提示语,默认空,非必传
		},
		data() {
			return {
				fileList: [],
				data: {},
				buttonList: [],
			};
		},
		watch: {
			initFiles() {
				if (this.initFiles) this.fileList = JSON.parse(this.initFiles)
			},
			buttons() {
				this.buttonList = this.buttons ? JSON.parse(this.buttons) : [];
			},
			paramsData() {
				this.data = this.paramsData ? JSON.parse(this.paramsData) : {}
			},
		},
		created() {
			this.data = this.paramsData ? JSON.parse(this.paramsData) : {}

			if (this.initFiles) this.fileList = JSON.parse(this.initFiles);

			this.buttonList = this.buttons ? JSON.parse(this.buttons) : [];
		},
		methods: {
			/**
			* 点击额外按钮触发
			* @buttonInfo {Object} 按钮信息
			**/
			buttonClick(buttonInfo) {
				this.$emit('buttonClick', buttonInfo);
			},
			/**
			* 预览文件,暂时只支持预览图片和pdf,预览Excel是以下载的方式,word没有写,应该和Excel原理一样,其他不支持
			* @file {File} 附件信息
			**/
			onPreview(file) {
				let acceptType = this.accepts || this.accept;
				let isImg = acceptType.match('image/');
				let isPdf = acceptType.match('application/pdf');
				
				let excelAccept = 'application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
				let isExcel = excelAccept.match(acceptType)
				if (isImg) {
					// 预览图片,调用图片预览组件展示图片;如果有本地文件,则直接展示本地文件,否则,根据fileId获取服务器上的文件后进行展示
					if (file.raw) {
						this.$refs.comImgShowRef.getmgUrl(file.raw, file.name)
					} else {
						this.axios.post('/getFile', { fileId: file.fileId }).then(res => {
							this.$refs.comImgShowRef.previewPDF(res, file.name)
						})
					}
				} else if (isPdf) {
					// 预览pdf,如果有本地文件,则直接展示本地文件,否则,根据fileId获取服务器上的文件后进行展示
					if (file.raw) {
						this.$refs.comPdfShowRef.previewPDF(file.raw, '02')
					} else {
						this.axios.post('/getFile', { fileId: file.fileId }).then(res => {
							this.$refs.comPdfShowRef.previewPDF(res)
						})
						
					}
				} else if (isExcel) {
					// 预览Excel,仅支持查看非当前上传行为的Excel预览(因预览是以下载的模式预览的,这里认为当前上传的文件再次下载没有意义)。
					if (file.fileId) {
						this.downloadExcel(file.fileId, file.name)
					}
				}
			},
			/**
			* 下载Excel表
			* @fileId {String} 文件id
			* @name {String} 文件名
			**/
			downloadExcel(fileId, name) {
				// 根据fileId请求服务获取Excel流,将流进行整理后下载下来
				this.axios.post('/getxcel', { fileId }).then( res => {
					// 调用公共方法,下载文件;【此公共方法是写在全局的,通用的,现将公共方法写在下面】
					this.downloadFile(res, name)
				})
			},
			/**
			* 通过文件流下载文件
			* @file 文件流,必输
			* @name 下载的文件名,必输
			* @type 下载的文件类型,默认xls,非必输
			**/
			downloadFile(file, name, type) {
				if (!file) {
					return
				}
				const url = window.URL.createObjectURL(
					new Blob([file], { 
						type: type || 'application/vnd.ms-excel' 
					})
				);
				const link = document.createElement('a');
				link.style.display = 'none';
				link.href = url;
				// 设置文件名;download属性定义了下载链接的地址而不是跳转路径
				link.setAttribute('download', name);
				document.body.appendChild(link);
				link.click();
				document.body.removeChild(link); // 下载完成后移除元素
				window.URL.revokeObjectURL(url); // 释放掉blob对象
			},
			/**
			* 删除文件的钩子
			* @file {File} 删除的文件信息
			* @fileList {Array} 删除后的文件列表
			**/
			onRemove(file, fileList) {
				this.fileList = fileList;
				this.$emit('fileChange', fileList)
				this.$emit('fileRemove', file)
			},
			/**
			* 上传成功的钩子
			* @response {Object} 上传成功后服务返回的数据
			* @file {File} 上传的文件信息
			* @fileList {Array} 上传后的文件列表
			**/
			onSuccess(response, file, fileList) {
				if (response.code != 'SUCCESS') {
					console.log(response.message || '文件上传报错')
					// 删除报错文件
					this.$refs.comUpload.abort(file.raw);
					fileList.splice(fileList.indexOf(file), 1);
					this.onRemove(file, fileList);
					return;
				}

				this.fileList = fileList
				this.$emit('fileChange', fileList)
				this.$emit('fileAdd', file);
			},
			/**
			* 上传文件之前的钩子,用于做校验文件等一系列操作,压缩图片操作在以前的文章中讲过了,这里就略过不写了
			* @file {File} 文件本身
			**/
			beforeUpload(file) {
				let _this = this
				return new Promise((resolve, reject) => {
					if (file.size === 0) { // 如果检测不到文件大小,报错
						console.log('文件错误,请上传正确的文件')
						reject()
					}
					// 判断文件是否超过限制大小
					let isLtSize = _this.size 
						? file.size / 1024 / 1024 < _this.size 
							? true 
							: false 
						:true 
					if (!isLtSize) {
						console.log(`文件大小超过限制,最大不超过${_this.size}MB`)
						reject()
					}
					
					// 判断文件是否符合要求的格式
					let acceptType = _this.accepts || _this.accept;
					let extension = acceptType 
						? acceptType.match(file.type)
							? true
							: false
						: true
					if (!extension) {
						console.log(`文件格式错误,仅限${_this.acceptText}格式`)
						reject();
					}
					// 判断是否是图片,如果是图片文件,则进行压缩
					if (acceptType.match('image') || (!acceptType && file.type.match('image'))) {
						// 此处做压缩图片操作,方法已在之前的文章中写过(https://blog.csdn.net/weixin_44134899/article/details/95046994),这里不做赘述
					} else {
						resolve(file)
					}
				});
			},
			/**
			* 删除文件之前的钩子
			* @file {File} 删除的文件
			* @fileList {Array} 文件列表
			**/
			beforeRemove(file, fileList) {
				this.$emit('fileBeforeRemove', file, fileList)
			},
			/**
			* 文件超出个数限制时的钩子
			* @files {File} 当前上传的文件
			* @fileList {Array} 当前的文件列表
			**/
			onExceed(files, fileList) {
				console.log(`文件${files[0].name}上传失败,最多只能上传${this.limit}个文件`)
			},
			/**
			* 文件上传失败时的钩子
			**/
			onError(err, file, fileList) {
				console.log(`文件【${file.name}】上传失败,请刷新重试或联系系统管理员!`)
			},
		},
	};
	
</script>
<style lang="less">
	.com-upload {
		.el-upload {
			display: inline-block;
			text-align: left;
		}
		&.is-drag {
			.el-upload {
				width: 100%;
			}
		}
		.el-upload__tip {
			line-height: 20px;
			.el-upload__tip_tips {
				margin: 0;
				color: #777;
			}
		}
	}
</style>
二、引用:

html部分(这里只列举少数属性的配置例子):

<com-upload
	v-model="model"
	accept="application/pdf"
	:drag="false"
	accept-text="pdf"
	:buttons="JSON.stringify([{label: '额外按钮1', type: '', id: '01'},{label: '额外按钮2', type: 'primary', id: '02'}])"
	:init-files="JSON.stringify([{name: '01.pdf', url: 'https://www.baidu.com', fileId: '01'},{name: '02.pdf', url: 'https://www.baidu.com', fileId: '02'}])"
	:size="5"
	:limit="3"
	tips="这是额外提:请在上传前检查附件是否正确!"
	@fileChange="fileChange"
	@fileAdd="fileAdd"
></com-upload>

js部分:

fileChange(fileList) {
	console.log("fileList=>",fileList)
},
fileAdd(file) {
	console.log("file=>",file)
},

效果图:
Element-ui之upload封装_第1张图片
完。

你可能感兴趣的:(Vue)