基于element-ui,编写上穿组件

发布时间:2022-03-14

概述

因在公司,项目有需要,我就写了个上传组件供大家参考,可以上穿,视频,文档,图片,音频,的上传组件

详细

1,项目目录结构

image.png

image.png


2,新建uploadImgDesc,代码如下

<template>
  <div class="sl_eda_pageCSS" :class="{ &quot;components&quot;: mode === &quot;components&quot; }">
    <div v-for="(item,index) in dataList" :key="index" class="group"
      :class="{ &quot;componentsGroup&quot;: mode === &quot;components&quot; }">
      <!-- 图片 -->
      <el-card v-if="item.img || item.img === ''" class="photoCard" :body-style="{ padding: '0px' }"
        :class="{ &quot;componentsCard&quot;: mode === &quot;components&quot; }">
        <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="{ &quot;componentsCard&quot;: mode === &quot;components&quot; }">
        <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="{ &quot;componentsCard&quot;: mode === &quot;components&quot; }">
        <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="{ &quot;componentsCard&quot;: mode === &quot;components&quot; }">
        <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 === &quot;page&quot;" 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




本实例支付的费用只是购买源码的费用,如有疑问欢迎在文末留言交流,如需作者在线代码指导、定制等,在作者开启付费服务后,可以点击“购买服务”进行实时联系,请知悉,谢谢
手机上随时阅读、收藏该文章 ?请扫下方二维码