基于element-ui,编写上穿组件
技术:vue
概述
因在公司,项目有需要,我就写了个上传组件供大家参考,可以上穿,视频,文档,图片,音频,的上传组件
详细
1,项目目录结构
2,新建uploadImgDesc,代码如下
<template> <div class="sl_eda_pageCSS" :class="{ "components": mode === "components" }"> <div v-for="(item,index) in dataList" :key="index" class="group" :class="{ "componentsGroup": mode === "components" }"> <!-- 图片 --> <el-card v-if="item.img || item.img === ''" class="photoCard" :body-style="{ padding: '0px' }" :class="{ "componentsCard": mode === "components" }"> <div slot="header" class="title"> {{ item.name ? item.name : item.text ? '文本'+ (index+1) : item.video ? '视频' + (index+1) : item.audio ? '音频' + (index + 1) : '图片' + (index+1) }} </div> <el-upload class="avatar-uploader" multiple action="" :auto-upload="false" :show-file-list="false" :on-change="(file, fileList) => {photoChange(file, fileList, item)}"> <el-image v-if="!item.isLoading" fit="cover" :src="item.img" class="avatar" /> <el-image v-else class="avatar"> <div slot="error" class="image-slot"> <i class="el-icon-loading" /> </div> </el-image> </el-upload> <div class="bottom clearfix"> <div class="item"> <el-button v-if="index!==0" type="text" class="button" @click="upItem(index)">上移</el-button> </div> <div class="item"> <el-button v-if="index!==dataList.length - 1" type="text" class="button" @click="downItem(index)">下移 </el-button> </div> <div class="item"> <el-button type="text" class="button" style="color: red;" @click="delItem(index)">删除</el-button> </div> </div> </el-card> <!-- 文本 --> <el-card v-if="item.text || item.text === ''" class="photoCard" :body-style="{ padding: '0px' }" :class="{ "componentsCard": mode === "components" }"> <div slot="header" class="title"> {{ item.name ? item.name : item.text ? '文本'+ (index+1) : item.video ? '视频' + (index+1) : item.audio ? '音频' + (index + 1) : '图片' + (index+1) }} </div> <el-input v-model="item.text" type="textarea" :rows="3" placeholder="请输入内容" /> <div class="bottom clearfix"> <div class="item"> <el-button v-if="index!==0" type="text" class="button" @click="upItem(index)">上移</el-button> </div> <div class="item"> <el-button v-if="index!==dataList.length - 1" type="text" class="button" @click="downItem(index)">下移 </el-button> </div> <div class="item"> <el-button type="text" class="button" style="color: red;" @click="delItem(index)">删除</el-button> </div> </div> </el-card> <!-- 视频 --> <el-card v-if="item.video || item.video === ''" class="photoCard" :body-style="{ padding: '0px' }" :class="{ "componentsCard": mode === "components" }"> <div slot="header" class="title"> {{ item.name ? item.name : item.text ? '文本'+ (index+1) : item.video ? '视频' + (index+1) : item.audio ? '音频' + (index + 1) : '图片' + (index+1) }} </div> <el-upload class="avatar-uploader" action="" :auto-upload="false" :show-file-list="false" :on-change="(file, fileList) => {videoChange(file, fileList, item)}"> <video v-if="item.video" :src="item.video" class="avatar" controls="controls" /> <el-image v-else class="avatar"> <div slot="error" class="image-slot"> <i class="el-icon-video-play" /> </div> </el-image> </el-upload> <div class="bottom clearfix"> <div class="item"> <el-button v-if="index!==0" type="text" class="button" @click="upItem(index)">上移</el-button> </div> <div class="item"> <el-button v-if="index!==dataList.length - 1" type="text" class="button" @click="downItem(index)">下移 </el-button> </div> <div class="item"> <el-button type="text" class="button" style="color: red;" @click="delItem(index)">删除</el-button> </div> </div> </el-card> <!-- 音频 --> <el-card v-if="item.audio || item.audio === ''" class="photoCard" :body-style="{ padding: '0px' }" :class="{ "componentsCard": mode === "components" }"> <div slot="header" class="title"> {{ item.name ? item.name : item.text ? '文本'+ (index+1) : item.video ? '视频' + (index+1) : item.audio ? '音频' + (index + 1) : '图片' + (index+1) }} </div> <el-upload class="avatar-uploader" action="" :auto-upload="false" :show-file-list="false" :on-change="(file, fileList) => {audioChange(file, fileList, item)}"> <audio v-if="item.audio" :src="item.audio" controls="controls" /> <el-image v-else class="avatar"> <div slot="error" class="image-slot"> <i class="el-icon-video-play" /> </div> </el-image> </el-upload> <div class="bottom clearfix"> <div class="item"> <el-button v-if="index!==0" type="text" class="button" @click="upItem(index)">上移</el-button> </div> <div class="item"> <el-button v-if="index!==dataList.length - 1" type="text" class="button" @click="downItem(index)">下移 </el-button> </div> <div class="item"> <el-button type="text" class="button" style="color: red;" @click="delItem(index)">删除</el-button> </div> </div> </el-card> </div> <div class="group"> <el-button v-if="type !== 'image' && type !== 'noText'" class="btns" @click="addItemDetail(1)">添加文本</el-button> <el-upload class="avatar-uploader" multiple action="" :auto-upload="false" :show-file-list="false" :on-change="(file, fileList) => { uploadImages(file, fileList) }"> <el-button class="btns">添加图片</el-button> </el-upload> <el-upload v-if="type !== 'noVideo' && mode !== 'shop' && type !== 'image'" class="avatar-uploader" multiple action="" :auto-upload="false" :show-file-list="false" :on-change="(file, fileList) => { uploadvideos(file, fileList) }"> <el-button class="btns">添加视频</el-button> </el-upload> </div> <div v-if="mode === "page"" class="footer"> <el-button :disabled="dataList.length <= 0" type="primary" @click="saveDetail">保存</el-button> <el-button @click="back">返回</el-button> </div> </div> </template> <script> // import config from '@/config/config' //配置oso,在这里配置你公司项目oso // import { // getFileType // } from '@/utils' export default { name: 'UploadImgDesc', props: { id: { type: String, default: '' }, type: { type: String, default: '' }, dataList: { type: Array, default () { return [] } }, mode: { type: String, default: 'page' } }, data() { return { title: null, oss: null } }, watch: { dataList: { handler(newValue, oldValue) { this.$emit('update:dataList', newValue) }, deep: true } }, created() { // const Oss = require('ali-oss') // this.oss = new Oss({ // region: config.bucket.region, // accessKeyId: config.bucket.accessKeyId, // accessKeySecret: config.bucket.accessKeySecret, // bucket: config.bucket.bucket // }) }, methods: { upItem(index) { if (this.dataList.length > 1 && index !== 0) { this.dataList = this.swapItems(this.dataList, index, index - 1) } }, downItem(index) { if (this.dataList.length > 1 && index !== (this.dataList.length - 1)) { this.dataList = this.swapItems(this.dataList, index, index + 1) } }, delItem(index) { this.dataList.splice(index, 1) }, addItemDetail(type) { var name = null if (!this.dataList) { this.dataList = [] } switch (type) { case 1: name = '文本' this.dataList.push({ text: '', isEdit: false, isText: true, isVideo: false, isImg: false, isLoading: false, isAudio: false, name: name + (this.dataList.length + 1), type: type }) break case 2: name = '图片' this.dataList.push({ img: '', isEdit: false, isLoading: false, isImg: true, isText: false, isVideo: false, isAudio: false, name: name + (this.dataList.length + 1), type: type }) break case 3: name = '视频' this.dataList.push({ video: '', isEdit: false, isVideo: true, isImg: false, isText: false, isLoading: false, isAudio: false, name: name + (this.dataList.length + 1), type: type }) break case 4: name = '音频' this.dataList.push({ audio: '', isEdit: false, isVideo: false, isImg: false, isText: false, isLoading: false, isAudio: true, name: name + (this.dataList.length + 1), type: type }) break } }, swapItems(arr, index1, index2) { arr[index1] = arr.splice(index2, 1, arr[index1])[0] return arr }, // 已有容器 点击替换图片 photoChange(file, fileList, item) { // debugger const isJPGPNG = (file.raw.type === 'image/jpeg' || file.raw.type === 'image/png' || file.raw.type === 'image/gif') const isLt2M = file.size / 1024 / 1024 < 10 if (!isJPGPNG) { this.$message.error('上传图片只能是 JPG、PNG、GIF 格式!') return } if (!isLt2M) { this.$message.error('上传图片大小不能超过 10MB!') return } this.uploadFile(file, item) }, // 添加图片按钮 uploadImages(file, fileList) { const isJPGPNG = (file.raw.type === 'image/jpeg' || file.raw.type === 'image/png' || file.raw.type === 'image/gif') const isLt2M = file.size / 1024 / 1024 < 10 if (!isJPGPNG) { this.$message.error('上传图片只能是 JPG、PNG、GIF 格式!') return } if (!isLt2M) { this.$message.error('上传图片大小不能超过 10MB!') return } if (this.dataList === null) { this.dataList = [] } const name = '图片' const itemData = { img: '', isEdit: false, isLoading: true, isImg: true, isText: false, isVideo: false, isAudio: false, name: name + (this.dataList.length + 1), type: 2 } console.log('上传之前的dataList', this.dataList) this.dataList.push(itemData) this.uploadFile(file, itemData, this.dataList.length - 1) }, // 添加视频按钮 uploadvideos(file, fileList) { const isLt50M = file.size / 1024 / 1024 < 50 if (['video/mp4', 'video/ogg', 'video/flv', 'video/avi', 'video/wmv', 'video/rmvb', 'video/quicktime'].indexOf( file.raw.type) === -1) { this.$message.error('上传视频只能是 mp4,ogg,flv,avi,wmv,rmvb,mp3,wav,mov 格式!') return } if (!isLt50M) { this.$message.error('上传视频大小不能超过 50MB!') return } if (this.dataList === null) { this.dataList = [] } const name = '视频' const itemData = { video: '', isEdit: false, isLoading: false, isImg: false, isText: false, isVideo: true, isAudio: false, name: name + (this.dataList.length + 1), type: 3 } this.dataList.push(itemData) console.log('加入你:', itemData) this.uploadFile(file, itemData, this.dataList.length - 1) }, audioChange(file, fileList, item) { const isLt50M = file.size / 1024 / 1024 < 50 if (['audio/mpeg', 'audio/ogg', 'audio/mp3', 'audio/x-wav'].indexOf(file.raw.type) === -1) { this.$message.error('上传音频只能是 wmv,rmvb,mp3,wav 格式!') return } if (!isLt50M) { this.$message.error('上传音频大小不能超过 50MB!') return } if (this.dataList === null) { this.dataList = [] } // 判断多图还是单图 this.uploadFile(file, item) }, audioMoreChange(file, fileList) { const isLt50M = file.size / 1024 / 1024 < 50 if (['audio/mpeg', 'audio/ogg', 'audio/mp3', 'audio/x-wav'].indexOf(file.raw.type) === -1) { this.$message.error('上传音频只能是 wmv,rmvb,mp3,wav 格式!') return } if (!isLt50M) { this.$message.error('上传音频大小不能超过 50MB!') return } if (this.dataList === null) { this.dataList = [] } // 判断多图还是单图 const name = '音频' const itemData = { audio: '', isEdit: false, isVideo: false, isImg: false, isText: false, isLoading: false, isAudio: true, name: name + (this.dataList.length + 1), type: 4 } this.dataList.push({ itemData }) this.uploadFile(file, itemData, this.dataList.length - 1) }, videoChange(file, fileList, item) { const isLt50M = file.size / 1024 / 1024 < 50 if (['video/mp4', 'video/ogg', 'video/flv', 'video/avi', 'video/wmv', 'video/rmvb', 'video/quicktime'].indexOf( file.raw.type) === -1) { this.$message.error('上传视频只能是 mp4,ogg,flv,avi,wmv,rmvb,mp3,wav,mov 格式!') return } if (!isLt50M) { this.$message.error('上传视频大小不能超过 50MB!') return } if (this.dataList === null) { this.dataList = [] } // item.url = URL.createObjectURL(file.raw) this.uploadFile(file, item) }, back() { this.$emit('on-back') }, uploadFile(file, item, index) { const stuff = getFileType(file.name) const fileName = new Date().getTime() +'_'+ Math.ceil(Math.random()*1000) + '.' + stuff console.log('上传文件file, item:', file, item) // TODO 上传文件的进度条 this.oss.put(fileName, file.raw).then(result => { console.log('oss上传结果:', item.type, index, result) console.log('this.dataList:', this.dataList) if (item.type === 2) { if (!index && ((index + '') !== '0')) { item.img = result.url } else { this.dataList[index].img = result.url this.dataList[index].isLoading = false } } else if (item.type === 3) { if (!index && ((index + '') !== '0')) { item.video = result.url } else { this.dataList[index].video = result.url this.dataList[index].isLoading = false } } else if (item.type === 4) { if (!index && ((index + '') !== '0')) { item.audio = result.url } else { this.dataList[index].audio = result.url this.dataList[index].isLoading = false } } item.hasCon = true console.log(this.dataList) }).catch(err => { this.$message.error(err) }) }, saveDetail() { let flag = false this.dataList.forEach((item) => { if (item.type === 1) { if (item.text === '' || item.text === null) { this.$message.error(item.name + '未填写内容!') flag = true return } } else if (item.type === 2) { if (item.img === '' || item.img === null) { this.$message.error(item.name + '未上传内容!') flag = true return } } else if (item.type === 3) { if (item.video === '' || item.video === null) { this.$message.error(item.name + '未上传内容!') flag = true return } } }) if (flag) { return } console.log('this.dataList:', this.dataList) this.$emit('on-save', this.dataList) } } } </script> <style scoped> .titles { font-weight: bold; font-size: 18px; margin: 15px 0; margin-bottom: 30px; color: #666; } .table-tools { padding: 20px 0; display: flex; } .block { width: 100%; display: flex; } .right-con { display: flex; flex: 1; justify-content: flex-end; align-items: center; } .left-con { display: flex; flex: 1; justify-content: flex-start; align-items: center; } .batch-del-box { padding: 20px 0; display: flex; } .el-pagination { display: flex; margin-top: 20px; justify-content: flex-end; } .box-card { width: 100%; margin: 12px; } .sl_eda_pageCSS { width: 100%; padding: 10px; position: relative; background-color: white; } .pageHeader { height: 46px; background: #fff; display: flex; } .left { flex: 1; } .components { width: 100%; display: flex; justify-content: center; align-items: center; flex-flow: column; } .componentsGroup { display: flex; justify-content: center; align-items: center; width: 100%; } .group { margin: 15px; display: flex; flex-flow: wrap; } .btns { margin: 0 10px; } .componentsCard { width: 60% !important; } .photoCard { width: 30%; position: relative; } .title { color: #666; } .bottom { border-top: 1px solid #ebeef5; padding: 10px 15px; display: flex; flex-flow: wrap; } .item { flex: 1; display: flex; justify-content: center; align-items: center; } .footer { margin-top: 25px; margin-left: 15px; } .avatar-uploader .el-upload { border: 1px dashed #d9d9d9; border-radius: 6px; cursor: pointer; position: relative; overflow: hidden; width: 100%; } .avatar-uploader { display: flex; justify-content: center; align-items: center; } .avatar-uploader .el-upload:hover { border-color: #409EFF; } .avatar-uploader-icon { font-size: 28px; color: #8c939d; width: 100%; height: 178px; line-height: 178px; text-align: center; } .avatar { width: 100%; height: 100%; min-height: 178px; display: block; } </style> <style> .photoCard .image-slot { display: flex; justify-content: center; align-items: center; font-size: 50px; color: #666; width: 100%; height: 100%; min-height: 178px; background: #f5f7fa; } .photoCard .el-upload--text { width: 100%; } .photoCard .el-textarea__inner { border: 0px !important; border-radius: 0px !important; } </style>
3,新建goodsMainImg组件代码如下
<template> <el-dialog class="schedule" center :title="title" :visible="show" :model="false" width="40%" :modal="false" @close="handleClose"> <span> <div class="block"> <div class="groupItem"> <!-- <uploadImgDesc :id="id" mode="components" :data-list.sync="editList" @on-back="back" /> --> <uploadImgDesc :id="id" mode="components" type="noText" :data-list.sync="editList" @on-back="back" /> </div> </div> </span> <span slot="footer" class="dialog-footer"> <el-button size="mini" style="margin-right:8%;" @click="handleClose">取 消</el-button> <el-button size="mini" type="primary" @click="handleItemSave">保 存</el-button> </span> </el-dialog> </template> <script> import uploadImgDesc from '@/components/uploadImgDesc' export default { name: 'Specs', components: { uploadImgDesc }, props: { show: { type: Boolean, default: false }, id: { type: String, default: '' }, title: { type: String, default: '' }, list: { type: Array, default() { return [] } } }, data() { return { reason: '', specsName: null, specsData: [], specsCoulumData: [], specsResultArray: [], oldSpecsData: [], oldSpecsCoulumData: [], foreverFlag: true, editList: [] } }, watch: { list(newValue, oldValue) { this.editList = JSON.parse(JSON.stringify(newValue)) console.log(this.editList) } }, // 初始化页面 created() {}, mounted() { this.editList = JSON.parse(JSON.stringify(this.list)) }, methods: { back() { }, handleItemSave(item) { let flag = false this.editList.forEach((item) => { if (item.type === 1) { if (item.text === '' || item.text === null) { this.$message.error(item.name + '未填写内容!') flag = true return } } else if (item.type === 2) { if (item.img === '' || item.img === null) { this.$message.error(item.name + '未上传内容!') flag = true return } } else if (item.type === 3) { if (item.video === '' || item.video === null) { this.$message.error(item.name + '未上传内容!') flag = true return } } }) if (flag) { return } this.$emit('on-save', this.editList) }, // 新增事件 handleSave() { this.$emit('on-save', this.editList) }, handleClose() { this.list = [] this.$emit('on-close') } } } </script> <style scoped> .el-dialog__header { padding: 15px; background-color: #304155; } .el-dialog__title { color: #fff; } .dialog-footer { display: flex; justify-content: center; margin-top: 0; } .block { padding: 0; padding-top: 20px; font-size: 12px; display: flex; justify-content: flex-start; align-items: center; flex-flow: column; } .warning { font-weight: 400; color: red; margin-bottom: 5px; } .groupItem { width: 100%; padding: 10px 25px; display: flex; flex-flow: wrap; align-items: center; } .label { font-weight: bold; color: #666; flex: 0.4; } .groupItems { flex-flow: column; display: flex; flex: 1.6; } .items { display: flex; margin: 5px 0; } .item { flex: 1; margin: 0 10px; } .item2 { display: flex; flex: 0.8; margin: 0 10px; } input { padding-left: 5px; border: 1px solid #e1e1e1; } </style>
4,调用组件
<template> <div> <el-button size="small" @click="showGoodsImgMask = true">编辑商品主图</el-button> <goodsMainImg :id="itemData.id" title="编辑商品主图" :list.sync="mainImgList" :show="showGoodsImgMask" @on-close="showGoodsImgMask = false" @on-save="saveGoodsImg" /> </div> </template> <script> import goodsMainImg from "./components/goodsMainImg.vue"; export default { name: "Tailoring", components: {goodsMainImg}, data () { return { showGoodsImgMask: false, itemData: { cover: [], detailPic: [], vipVals: [ { value: '', key: Date.now() } ] }, } }, methods: { saveItemDetail(item) { console.log(item, '获取图文描述') this.itemData.detailPic = item this.showItem = false }, } } </script> <style scoped> </style>
5,运行项目
npm run dev
本实例支付的费用只是购买源码的费用,如有疑问欢迎在文末留言交流,如需作者在线代码指导、定制等,在作者开启付费服务后,可以点击“购买服务”进行实时联系,请知悉,谢谢
手机上随时阅读、收藏该文章 ?请扫下方二维码