在开发中,有这样一个需求,点击上传logo,点击上传封面,点击上传头像等等,每次都上传很浪费存储资源,故要实现一个图片库的功能,点击先在图片库选择,如果图片库没有在执行上传。废话少说:上图
image.pngimage.png
image.png
image.png
1. 图片库页面代码
<template>
<div class="fileDialog">
<el-dialog :append-to-body='appendToBody' title="选择图片" :visible.sync="imgFileDialogFlag.show" width="60%" destroy-on-close @open="openDialog"
@close="closeDialog" :close-on-click-modal="false" :close-on-press-escape="false" :modal-append-to-body="false">
<!-- 上传图片按钮区域 -->
<div class="header_top">
<span>
<el-button size="mini" type="success" @click="vExampleAdd">上传图片</el-button>
<form ref="vExample">
<input type="file" style="display:none;" :accept="accept" ref="vExampleFile" @change="vExampleUpload" />
</form>
</span>
<span>
<el-input size="mini" placeholder="请输入图片名称" v-model="searchKey" @change="search" clearable>
<i slot="prefix" class="el-input__icon el-icon-search"></i>
</el-input>
</span>
</div>
<!-- 表格 -->
<div class="table">
<el-table element-loading-text="正在为您拼命加载中..." :data="tableData" ref="multipleTable" style="width: 100%" @row-click="clickRow"
v-loading='loading' :header-cell-style="{background:'#eef1f6',color:'#38a4bd'}">
<el-table-column label="" width="65">
<template slot-scope="scope">
<el-radio class="radio" v-model="templateSelection" :label="scope.$index"><br></el-radio>
</template>
</el-table-column>
<!-- 图片 -->
<el-table-column prop="videoUrl" label="图片" align="left">
<template slot-scope="scope">
<div class="imgBox">
<div class="l">
<!-- <img :src="scope.row.videoUrl" alt="" width="100%"> -->
<el-image :src="scope.row.videoUrl" :preview-src-list="[scope.row.videoUrl]" fit="cover" lazy class="el-avatar">
<div slot="error" class="image-slot">
<i class="el-icon-picture-outline"></i>
</div>
</el-image>
</div>
<div class="r">
<span>{{scope.row.videoName}}</span>
<span>{{scope.row.width}}*{{scope.row.height}}</span>
</div>
</div>
</template>
</el-table-column>
<!-- 大小 -->
<el-table-column prop="material_size" label="大小" align="center">
<template slot-scope="scope">
<span>{{scope.row.videoSize}}KB</span>
</template>
</el-table-column>
<!-- 上传时间 -->
<el-table-column prop="createTime" show-overflow-tooltip label="上传时间" align="right">
</el-table-column>
</el-table>
</div>
<!-- 分页 -->
<Pagination :page="page" :total="total" :page_size="page_size" :background="true" @handleCurrentChange="handleCurrentChange"
@handleSizeChange="handleSizeChange" />
<span slot="footer" class="dialog-footer">
<el-button size="mini" @click="imgFileDialogFlag.show = false">取 消</el-button>
<el-button size="mini" type="primary" @click="selectImage">确 定</el-button>
</span>
<el-dialog width="30%" title="上传进度" :visible.sync="innerVisible" append-to-body :show-close='false'>
<div class="loading">
<el-progress :text-inside="true" :stroke-width="20" :percentage="uploadPercent" status="exception"></el-progress>
</div>
</el-dialog>
</el-dialog>
</div>
</template>
<script>
import * as qiniu from 'qiniu-js'
import { getFileAuth, getFileList, addFile } from "@/api/common";
export default {
props: {
imgFileDialogFlag: Object,
appendToBody: {
type: Boolean,
default: false
}
},
data() {
return {
uploadPercent: 0,//上传进度
innerVisible: false,
tableHeight: document.documentElement.clientHeight - 300 || document.body.clientHeight - 300,
searchKey: "",
baseUrl: "",
accept: 'image/*',
loading: false,
templateSelection: "",//选中的图片数据索引
templateRadioUrl: "",//选中的图片url
tableData: [],
upToken: "",//上传token
page: 1,
page_size: 5,
total: 0,
imgSize: "",//图片大小
imgWidth: "",//图片宽度
imgHeight: "",//图片高度
imgName: "",//图片名称
imgType: "",//图片类型
}
},
methods: {
// 实现点击整行选中复选框
clickRow(row) {
this.templateSelection = this.tableData.indexOf(row);
this.templateRadioUrl = row.videoUrl;
},
// 上传按钮触发
vExampleAdd() {
this.$refs.vExampleFile.click()
},
// input change 事件 上传图片
vExampleUpload() {
let _this = this
let file = _this.$refs.vExampleFile.files[0]
_this.imgName = file.name
_this.imgSize = (file.size / 1024).toFixed(2)
_this.imgType = file.type
let config = {
useCdnDomain: true,
region: qiniu.region.z0
};
let putExtra = {
fname: file,
params: {},
mimeType: null
};
let observe = {
next(res) {
// // console.log('已上传大小,单位为字节:' + res.total.loaded)
// // console.log('本次上传的总量控制信息,单位为字节:' + res.total.size)
// // console.log('当前上传进度,范围:0~100:' + res.total.percent);
// _this.$emit("uploadPercent", res.total.percent)
_this.uploadPercent = res.total.percent
_this.innerVisible = true
},
error(err) {
// console.log(err.code)
console.log(err.message)
// console.log(err.isRequestError)
// console.log(err.reqId)
// _this.$emit('uploaderr')
_this.$message.error('上传失败!请勿重复上传')
_this.innerVisible = false
},
complete(res) {
//完成后的操作
//上传成功以后会返回key 和 hash key就是文件名了!
let imageUrl = (_this.baseUrl + '/' + res.key)
let img = new Image()
img.src = imageUrl
img.onload = function() {
_this.imgWidth = img.width
_this.imgHeight = img.height
addFile({ width: _this.imgWidth, height: _this.imgHeight, categoryId: 3, videoName: _this.imgName, videoUrl: imageUrl, videoSize: _this.imgSize, mimeTypeName: _this.imgType }).then(res => {
console.log(res);
_this.innerVisible = false
_this.$message.success('上传成功!')
_this.templateSelection = ''
_this.templateRadioUrl = ''
_this.getFileList()
})
}
}
};
//开始上传 token 需要找后端获取(单独的方法)
getFileAuth().then(res => {
this.upToken = res.data.auth
this.baseUrl = res.data.bucket
let key = res.data.uuid; // 文件资源名
let headers = qiniu.getHeadersForMkFile(this.upToken)
let observable = qiniu.upload(file, key, this.upToken, headers, putExtra, config)
let subscription = observable.subscribe(observe)
})
},
// 确认选择按钮触发
selectImage() {
this.$emit('selectImage', this.templateRadioUrl)
this.templateSelection = ''
this.templateRadioUrl = ""
},
// 获取图片列表
getFileList() {
this.loading = true
getFileList({ pageSize: this.page_size, pageNum: this.page, mimeType: 3, videoName: this.searchKey }).then(res => {
this.tableData = res.data.records
this.total = res.data.total
this.loading = false
})
},
// 分页所需
handleCurrentChange(val) {
this.page = val;
this.getFileList(this.searchKey);
this.templateSelection = ''
this.templateRadioUrl = ""
},
// 分页所需
handleSizeChange(val) {
this.page_size = val;
// this.page = 1;
this.getFileList(this.searchKey);
this.templateSelection = ''
this.templateRadioUrl = ""
},
// 打开弹窗触发
openDialog() {
this.getFileList()
},
closeDialog() { },
// 搜索触发
search() {
this.getFileList()
}
}
}
</script>
<style lang="scss" scoped>
.header_top {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15px 0;
}
.table {
.imgBox {
display: flex;
.l {
img {
width: 68px;
height: 48px;
object-fit: scale-down;
background: #fafafa;
}
}
.r {
display: flex;
flex-direction: column;
margin-left: 10px;
overflow: hidden;
justify-content: space-between;
span {
text-align: left;
&:first-child {
font-weight: bold;
display: block;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
color: #333;
}
}
}
}
}
::v-deep .el-dialog__header {
background: #fafbfc;
border-radius: 2px 2px 0 0;
border-bottom: 1px solid #f2f2f2;
}
::v-deep .el-dialog__body {
padding: 0px 20px;
}
.loading {
padding-bottom: 20px;
}
</style>
2. 组件内用到了封装的分页组件,代码如下
<template>
<div class="pagination">
<el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :page-sizes="[1,5, 10, 20, 30, 40, 50]" :layout="layout"
:current-page.sync="page" :page-size="page_size" :total="total" :background="background" small>
</el-pagination>
</div>
</template>
<script>
export default {
name: "pagination",
data() {
return {
page: 1
}
},
props: {
// 避免直接改变prop属性
// 'currentPage': {
// required: false,
// default: 1
// },
'layout': {
required: false,
default: 'total, prev, pager, next, sizes'
},
'total': {
required: false,
default: 0
},
'page_size': {
required: false,
default: 10
},
'background': {
required: false,
type: Boolean,
default: false
}
},
watch: {
currentPage(val) {
// 改变这个值并不会触发 handleCurrentChange
if (typeof val === "number") {
// console.log('prop currentPage!!!');
this.currentPage = val;
}
},
},
methods: {
// 当前页变化
handleCurrentChange(val) {
this.$emit("handleCurrentChange", val);
},
// size变化
handleSizeChange(val) {
this.currentPage = 1;
this.$emit('handleSizeChange', val);
},
}
}
</script>
<style lang="scss" scoped>
.pagination {
margin: 10px 0 0 0;
text-align: right;
}
::v-deep .el-pagination .el-select .el-input {
margin-top: -3px;
}
::v-deep .el-pagination.is-background .el-pager li {
border-radius: 50%;
}
::v-deep .el-pagination.is-background .el-pager li:not(.disabled).active {
background-color: #38a4bd;
}
::v-deep .el-pagination.is-background.el-pagination--small .btn-prev {
border-radius: 50%;
}
::v-deep .el-pagination.is-background.el-pagination--small .btn-next {
border-radius: 50%;
}
</style>
3. 写个容器调用组件
<el-form-item label="LOGO">
<div class="flex">
<el-image :src="formDataHandle.orgLogo" :preview-src-list="[formDataHandle.orgLogo]" fit="cover" lazy class="el-avatar">
<div slot="error" class="image-slot" @click="showImgFileDialog">
<i class="el-icon-picture-outline"></i>
</div>
</el-image>
<div class="dot" v-if="formDataHandle.orgLogo != ''">
<el-button class="closeicon" type="danger" circle icon="el-icon-delete" @click="delLogo"></el-button>
</div>
</div>
</el-form-item>
<ImgFileDialog :appendToBody='true' @selectImage='selectImage' :imgFileDialogFlag='imgFileDialogFlag'></ImgFileDialog>
data(){
return{
imgFileDialogFlag: {
show: false
},
}
}
methods(){
//打开图片库
showImgFileDialog() {
this.imgFileDialogFlag = {
show: true
}
},
selectImage(url) {
this.formDataHandle.orgLogo = url //赋值
this.imgFileDialogFlag = {
show: false
}
},
//删除图片重新选择
delLogo() {
this.formDataHandle.orgLogo = ''
}
}
网友评论