vue中上传组件封装及使用
2023-12-13 05:42:11
1.from中引用
<el-form-item label="打卡照片" prop="checkInPhoto">
<myFile :uploadPm="uploadPm" ref="file1Ref" @notice="_getFileIds"/><br>
</el-form-item>
2.在data中定义 uploadPm
uploadPm: {
fieldCode: "dkzp",//打卡照片
attachmentType: "PICTURE",//只有为"PICTURE"才使用照片墙这个会被存入附件表所以必须传
fileType: ['png', 'jpg','mp4'],//允许上传的格式
limit: 5,//上传图片的最大个数
isRead: false,//是否只读(编辑时候传true)
fileSize: 100 //单个图片的最大大小限制
},
3.在methods中定方法
_getFileIds: function (data) {
this.form.fileIds = data;
},
4.在新增方法中
this.$nextTick(() => {
_that.$refs.file1Ref.cleanFiles();
_that.$refs.file1Ref.setIsRead(false);
});
5.修改方法中
this.$nextTick(() => {
_that.$refs.file1Ref.showFiles(response.data.id);
_that.$refs.file1Ref.setIsRead(false);
});
6.查看方法中
this.$nextTick(() => {
_that.$refs.file1Ref.showFiles(response.data.id);
_that.$refs.file1Ref.setIsRead(true);
});
下面代码为上传组件封装
<template>
<div class="upload-file">
<el-upload
:class="{hide:uploadPm.isRead}"
v-if="isPic"
:disabled="isRead"
list-type="picture-card"
:action="uploadFileUrl"
:before-upload="handleBeforeUpload"
:file-list="fileList"
:limit="limit"
:on-error="handleUploadError"
:on-exceed="handleExceed"
:on-success="handleUploadSuccess"
:on-preview="handlePictureCardPreview"
:on-remove="handleRemove"
:before-remove="beforeRemove"
:headers="headers"
>
<i class="el-icon-plus"></i>
</el-upload>
<el-dialog id="imgView" style="left: 100px" :visible.sync="dialogVisible" :width="dialogWidth?dialogWidth+'px':''" :height="dialogHeight?dialogHeight+'px':''" :modal="false" >
<img :width="imgWidth?imgWidth:'50%'" :height="imageHeight?imageHeight:''" :src="dialogImageUrl" alt="" style="display: block; margin: 0 auto;">
<div slot="footer" class="dialog-footer">
<el-button icon="el-icon-close" class="qzlbg" size="small" @click="dialogVisible = false" style="margin: 30px 45%;">取 消</el-button>
</div>
</el-dialog>
<el-upload
v-if="!isPic"
:disabled="isRead"
:action="uploadFileUrl"
:before-upload="handleBeforeUpload"
:file-list="fileList"
:limit="limit"
:on-error="handleUploadError"
:on-exceed="handleExceed"
:on-success="handleUploadSuccess"
:show-file-list="false"
:headers="headers"
class="upload-file-uploader"
ref="upload"
>
<!-- 上传按钮 -->
<el-button size="mini" type="primary" class="blueLinearbg">选取文件</el-button>
<!-- 上传提示 -->
<div class="el-upload__tip" slot="tip" v-if="showTip">
请上传
<template v-if="fileSize"> 大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b></template>
<template v-if="fileType"> 格式为 <b style="color: #f56c6c">{{ fileType.join("/") }}</b></template>
的文件
</div>
</el-upload>
<!-- 文件列表 -->
<transition-group v-if="!isPic" class="upload-file-list el-upload-list el-upload-list--text"
name="el-fade-in-linear" tag="ul">
<div class="el-upload-list__item ele-upload-list__item-content" v-for="(file, index) in fileList"
v-bind:key="file.name">
<el-link :href="file.url" :underline="false" target="_blank">
<span class="el-icon-document"> {{ file.fileName }} </span>
</el-link>
<div class="ele-upload-list__item-content-action" v-if="!uploadPm.isRead">
<el-link :underline="false" @click="handleDelete(index)" type="danger">删除</el-link>
</div>
</div>
</transition-group>
<!--視頻查看-->
<el-dialog
z-index="99999"
title="视频预览"
:visible.sync="dialogPlay"
width="30%"
:modal="false"
@close="closeDialog"
>
<video
:src="videoUrl"
controls
autoplay
class="video"
ref="dialogVideo"
width="100%"
/>
</el-dialog>
</div>
</template>
<script>
import {getToken} from "@/utils/auth";
import request from '@/utils/request'
export default {
name: "lengFileUploadPlus",
props: {
//父页面传过来的附件上传相关参数
uploadPm: {
type: [Object]
},
value: [String, Object, Array],
// 是否显示提示
isShowTip: {
type: Boolean,
default: true
}
},
data() {
return {
loading:null,
waitRemove:false,//等待删除忽略删除提示
clientWidth:null,
clientHeight:null,
imgWidth:null,
imageHeight:null,
dialogWidth:null,
dialogHeight:null,
videoUrl:"",
dialogPlay:false,
//放大图片的路径
dialogImageUrl: '',
//放大器展示开关
dialogVisible: false,
// disabled: false,
//展示照片墙还是列表true展示照片墙
isPic: true,
//是否允许编辑
isRead: {
type: Boolean,
default: false
},
// 数量限制
limit: {
type: Number,
default: 5
},
//单个文件最大值单位MB
fileSize: {
type: Number,
default: 20
},
//允许上传的文件类型
fileType: {
type: Array,
default: () => ["doc", "xls", "ppt", "txt", "pdf", 'png', 'jpg', 'mp4', 'zip'],
},
uploadFileUrl: process.env.VUE_APP_BASE_API + "/file/upload", // 上传的图片服务器地址
headers: {
Authorization: "Bearer " + getToken(),
FieldCode:this.uploadPm.fieldCode,
},
fileList: [],//存放附件的列表
ids: [],//附件的id用来修改entityId
};
},
watch: {
value: {
handler(val) {
if (val) {
let temp = 1;
// 首先将值转为数组
const list = Array.isArray(val) ? val : this.value.split(',');
// 然后将数组转为对象数组
this.fileList = list.map(item => {
if (typeof item === "string") {
item = {name: item, url: item};
}
item.uid = item.uid || new Date().getTime() + temp++;
return item;
});
} else {
this.fileList = [];
return [];
}
},
deep: true,
immediate: true
}
},
created() {
//初始化父页面传来的上传参数
this.init();
},
computed: {
// 是否显示提示
showTip() {
return this.isShowTip && (this.fileType || this.fileSize);
},
},
methods: {
beforeRemove(){
if(this.waitRemove){
this.waitRemove = false;
return true;
}
const p = new Promise((resolve, reject) => {
this.$confirm('此操作将删除该文件, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
.then(() => {
console.log("beforeRemove-then")
this.rmVModel();
resolve(true)
})
.catch(() => {
console.log("beforeRemove-catch")
this.rmVModel();
reject(false)
})
})
return p;
/*return this.$confirm('此操作将删除该文件, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
.then(() => {
console.log("beforeRemove-then")
$(".v-modal").remove();
this.Promise.resolve(true)
})
.catch(() => {
console.log("beforeRemove-catch")
$(".v-modal").remove();
this.Promise.resolve(false)
});*/
},
rmVModel(){
// $(".v-modal").remove();
var elements = document.querySelectorAll('.v-modal');
elements.forEach(function(element) {
if (element.parentNode) {
element.parentNode.removeChild(element);
}
});
},
closeDialog() {
this.videoUrl = ""; //清空数据 关闭视频播放
this.dialogPlay = false; //清空数据 关闭视频播放
},
handleRemove(file) {
const findex = this.fileList.map(f => f.uid).indexOf(file.uid);
if (findex > -1) {
this.handleDelete(findex);
}
},
handlePictureCardPreview(file) {
console.log(file)
//这里判断照片展示照片 视频展示视频
if(this.getFileType(file.name) === "PICTURE"){
this.showImg(file);
}else if(this.getFileType(file.name) === "VIDEO"){
this.showVideo(file);
}
},
getFileType(fileName){
// 定义图片格式的扩展名数组
const pictureExtensions = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'tif', 'tiff', 'svg'];
// 定义视频格式的扩展名数组
const videoExtensions = ['mp4', 'avi', 'mov', 'wmv', 'flv', 'mkv'];
// 获取文件扩展名
const extension = fileName.split('.').pop().toLowerCase();
// 判断扩展名是否在图片格式数组中
if (pictureExtensions.includes(extension)) {
return 'PICTURE';
}
// 判断扩展名是否在视频格式数组中
else if (videoExtensions.includes(extension)) {
return 'VIDEO';
}
// 如果都不是,则返回'FILE'
else {
return 'FILE';
}
},
showImg(file){
this.clientWidth = document.body.clientWidth;
this.clientHeight = document.body.clientHeight;
this.dialogHeight = this.clientHeight*0.8;
this.dialogWidth = this.clientWidth*0.8;
let img = document.createElement('img');
img.src=file.url;
const self = this;
img.onload = function(){
self.imgWidth = img.width;
self.imageHeight = img.height;
self.setWH();
self.dialogImageUrl = file.url;
self.dialogVisible = true;
}
},
//设置弹窗宽高和图片宽高
setWH(){
let bl = (this.imgWidth/this.dialogWidth >this.imageHeight/this.dialogHeight)?(this.dialogWidth*0.8/this.imgWidth):(this.dialogHeight*0.8/this.imageHeight);//放大或缩小比例
this.imgWidth = this.imgWidth*bl;
this.imageHeight = this.imageHeight*bl;
/*
if(this.imgWidth&&this.imageHeight&&(this.imgWidth>=this.dialogWidth*0.8||this.imageHeight>=this.dialogHeight*0.8)){
this.imgWidth = this.imgWidth*0.95;
this.imageHeight = this.imageHeight*0.95;
this.setWH();
}else if(this.imgWidth&&this.imageHeight&&(this.imgWidth<=this.dialogWidth*0.3||this.imageHeight<=this.dialogHeight*0.3)){
this.imgWidth = this.imgWidth*1.1;
this.imageHeight = this.imageHeight*1.1;
this.setWH();
}
*/
},
showVideo(o){
this.dialogPlay = true;
this.videoUrl = o.url;
},
//根据视频地址获取封面
async getVideoBase64(url, second) {
const video = document.createElement('video');
video.setAttribute('crossOrigin', 'anonymous'); // 处理跨域
video.setAttribute('src', url);
// 静音操作,防止播放失败
video.setAttribute('muted', 'muted');
video.addEventListener('loadeddata', async () => {
const canvas = document.createElement('canvas');
const { width, height } = video; // canvas的尺寸和图片一样
canvas.width = width;
canvas.height = height;
if (second) {
video.currentTime = second;
// 播放到当前时间的帧,才能截取到当前的画面
await video.play();
await video.pause();
}
canvas.getContext('2d')?.drawImage(video, 0, 0, width, height);
return canvas.toDataURL('image/jpeg');
});
},
handleDownload(file) {
// console.log(file);
},
/*修改entityId*/
upEntityId: function (entityId,callback) {
//修改entityId
let fileIds = this.getFileIds();
// let attachmentType = this.uploadPm.attachmentType;
updateEntityId(fileIds, entityId, this.uploadPm.attachmentType,function(){
if(callback)
callback();
});
},
/*图片回显*/
showFiles(entityId) {
// console.log("showFiles "+entityId)
getFileList(entityId).then(res => {
this.fileList = [];
//填充fileList
if (res) {
for (let i in res) {
this.fileList.push({
name: res[i].url,
url: res[i].url,
attachmentType:res[i].attachmentType,
attachmentId: res[i].id,
fileName: res[i].fileName
});
console.log(this.fileList)
}
}
})
},
/*图片回显*/
showFilesByPm(entityId,entityName,fieldCode) {
let parm = {};
parm.entityId = entityId;
parm.entityName = entityName;
parm.fieldCode = fieldCode;
getFileListByPm(parm).then(res => {
this.fileList = [];
//填充fileList
if (res) {
for (let i in res) {
this.fileList.push({
name: res[i].url,
url: res[i].url,
attachmentType:res[i].attachmentType,
attachmentId: res[i].attachmentId,
fileName: res[i].fileName
});
console.log(this.fileList)
}
}
})
},
/*追加图片回显*/
appendFiles(entityId) {
// console.log("appendFiles "+entityId)
getFileList(entityId).then(res => {
//填充fileList
if (res) {
for (let i in res) {
if(res[i].url.indexOf('http://39.107.66.190:9300/files')>=0){
const arr = res[i].url.split('http://39.107.66.190:9300/files');
arr [0]=attachmentURL;
res[i].url =arr.join('');
}
this.fileList.push({
name: res[i].url,
url: res[i].url,
attachmentId: res[i].attachmentId,
fileName: res[i].fileName
});
}
}
})
},
cleanFiles(){
this.fileList=[];
},
/*获取附件列表*/
getFiles() {
return this.fileList;
},
// 上传前校检格式和大小
handleBeforeUpload(file) {
console.log("!23213123")
// 校检文件类型
if (this.fileType) {
let fileExtension = "";
if (file.name.lastIndexOf(".") > -1) {
fileExtension = file.name.slice(file.name.lastIndexOf(".") + 1);
}
const isTypeOk = this.fileType.some((type) => {
if (file.type.indexOf(type) > -1) return true;
if (fileExtension && fileExtension.indexOf(type) > -1) return true;
return false;
});
if (!isTypeOk) {
this.$message.error(`文件格式不正确, 请上传${this.fileType.join("/")}格式文件!`);
this.waitRemove = true;
return false;
}
}
// 校检文件大小
if (this.fileSize) {
const isLt = file.size / 1024 / 1024 < this.fileSize;
if (!isLt) {
this.$message.error(`上传文件大小不能超过 ${this.fileSize} MB!`);
return false;
}
}
this.loading = this.$loading({
lock: true,
text: '文件上传中',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)'
});
return true;
},
// 文件个数超出
handleExceed() {
this.$message.error(`上传文件数量不能超过 ${this.limit} 个!`);
},
// 上传失败
handleUploadError(err) {
console.log("上传失败",err)
if(this.loading){
this.loading.close();
}
this.$message.error("上传失败, 请重试");
},
// 上传成功回调
handleUploadSuccess(res, file) {
console.log("上传成功",res)
this.$message.success("上传成功");
this.fileList.push({
name: res.data.url,
url: res.data.url,
attachmentId: res.data.id,
fileName: res.data.fileName,
});
// updateAttachmentType(res.data.attachmentId,this.uploadPm.attachmentType,this.uploadPm.fieldCode);
//告诉父页面更新fileIds
this.$emit("notice", this.getFileIds());
this.loading.close();
this.loading = null;
},
// 删除文件
handleDelete: function (index) {
console.log("删除附件")
//#todo 这里要先从服务器删除,在删除列表
//删除前先拿到id
let fileListElement = this.fileList[index];
//去服务器删除附件表和附件
delFile(fileListElement.attachmentId).then(res => {
if (res) {
//#todo 判断服务器的删除状态 成功则把前端列表清除
this.fileList.splice(index, 1);
//通知父页面更新fileIds
this.$emit("notice", this.getFileIds());
// this.$emit("callback", true,fileListElement);
}
})
},
//初始化父页面传来的相关配置
init: function () {
this.isPic = this.uploadPm.attachmentType === "PICTURE"||this.uploadPm.attachmentType === "VIDEO";//判断组件应该使用照片墙还是使用列表(图片使用照片墙,其他使用列表)
this.isRead = this.uploadPm.isRead;
this.limit = this.uploadPm.limit;
this.fileSize = this.uploadPm.fileSize;
this.fileType = this.uploadPm.fileType;
const arr = this.fileType;
this.$nextTick(function(){
if(this.$refs.upload){
const inputEl = $(this.$refs.upload.$el).find('input')[0];
let str = '';
for(let i=0,len=arr.length;i<len;i++){
str += (i==0?('.'+arr[i]):(',.'+arr[i]));
if(i==len-1)
inputEl.accept = str;
}
}
});
},
changeIsRead: function () {
this.isRead = !this.isRead;
},
setIsRead: function (flag) {
this.uploadPm.isRead = flag;
this.isRead = flag;
},
changeModel: function () {
this.isPic = !this.isPic;
},
// 获取文件名称
getFileName(name) {
if (name.lastIndexOf("/") > -1) {
return name.slice(name.lastIndexOf("/") + 1).toLowerCase();
} else {
return "";
}
},
// 对象转成指定字符串分隔
listToString(list, separator) {
let strs = "";
separator = separator || ",";
for (let i in list) {
strs += list[i].url + separator;
}
return strs !== '' ? strs.substr(0, strs.length - 1) : '';
},
getFileIds: function () {
this.ids = [];
let files = this.fileList;
for (let i in files) {
this.ids.push(files[i].attachmentId);
}
return this.ids;
}
}
};
// 删除字典类型
export function delFile(attachmentId) {
return request({
url: '/file/delFile',
method: 'post',
data: {id: attachmentId}
})
}
//修改entityId
export function updateEntityId(ids, entityId, attachmentType,callback) {
return request({
url: '/file/updateEntityId',
method: 'post',
data: {ids: ids, entityId: entityId, attachmentType: attachmentType}
}).then(res=>{
if(callback)
callback();
})
}
// export function updateAttachmentType(attachmentId,attachmentType,fieldCode) {
// return request({
// url: '/system/attachment/updateAttachmentType',
// method: 'post',
// data: { attachmentId: attachmentId, attachmentType: attachmentType,fieldCode:fieldCode?fieldCode:""}
// })
// }
export function getFileList(entityId) {
return request({
url: '/file/getListByEntityId',
method: 'post',
data: {entityId: entityId}
})
}
export function getFileListByPm(pm) {
return request({
url: '/file/getFileListByPm',
method: 'post',
data: {entityId: pm.entityId,entityName: pm.entityName,fieldCode:pm.fieldCode}
})
}
</script>
<style scoped lang="scss">
.upload-file-uploader {
margin-bottom: 5px;
}
.upload-file-list .el-upload-list__item {
border: 1px solid #e4e7ed;
line-height: 2;
margin-bottom: 10px;
position: relative;
}
.upload-file-list .ele-upload-list__item-content {
display: flex;
justify-content: space-between;
align-items: center;
color: inherit;
}
.ele-upload-list__item-content-action .el-link {
margin-right: 10px;
}
::v-deep{
.el-upload-list__item-thumbnail{
position: absolute;
left: 0px !important;
}
.el-icon-check{
margin-left: -19px;
margin-top: 12px;
}
#imgView{
left:0px !important;
.el-dialog{
right:0px;
margin:0px;
left:unset !important;
width: calc(100% - 290px) !important;
border-top-left-radius: 20px;
border-top-right-radius: 20px;
bottom: 0px;
overflow: hidden;
height: 94%;
position: absolute;
.el-dialog__header{
height: 100px;
.el-dialog__headerbtn {
background: red;
width: 30px;
height: 30px;
border-radius: 20px;
.el-dialog__close{
color: white;
}
}
}
.el-dialog__body{
background:transparent;
}
}
}
}
</style>
<style>
.hide .el-upload--picture-card{
display: none !important;
}
</style>
文章来源:https://blog.csdn.net/qq_24441205/article/details/134927846
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!