likes
comments
collection
share

UI大大:element图片上传不太行,按照我设计的实现一下

作者站长头像
站长
· 阅读数 46

效果

UI大大:element图片上传不太行,按照我设计的实现一下

优点

  1. 组件UI美化并支持宽度自适应
  2. 预览图片按自身比例缩放展示
  3. 解决与背景同色图片无法清楚预览
  4. 配置支持修改、预览、删除等操作

需求

  1. 实现交互效果,并支持宽度自适应
  2. 预览图片宽高小于或大于容器,图片按照自身比例缩放展示
  3. 预览图片实现 PS 透明背景色的效果
  4. 支持修改、预览、删除操作

解析思路

  • 由于时间紧张并且需要 el-upload 原本的一些功能,直接在此基础上封装
  • 思路
    1. 交互效果并支持宽度自适应
      • 中间内容以及边框默认移入效果(不再介绍)
      • 自适应宽通过样式覆盖 el-upload 宽高 100%
      • 四角可以使用八个元素绘制,为了省事让UI出了四个角的图
    2. 预览图片自适应缩放
      • 由于不需要兼容IE浏览器,直接一个样式解决(object-fit: contain)
      • 个人有个兼容性强的思路会在下面分享
    3. PS 透明背景色效果
      • 采用多层背景叠加实现
    4. 支持修改、预览、删除操作
      • 基于 el-upload 实现相应功能,取决于配置项展示

实现

交互效果、宽度自适应

  • 最初 UI 出的是整个方框的图,后期支持自适应,会产生变形,最后采用点九切图
    • 只切不能拉伸的地方(如下图) UI大大:element图片上传不太行,按照我设计的实现一下
    • 采用绝对定位实现(使用 svg 需要注意 dom 宽高设置与其一致,并保证 svg 图无边缘空隙)
  • 中间区域可自定义,也可使用默认布局替换中间区域图片
    <slot v-else>
       <div class="upload-area" :style="uploadAreaStyle">
         <div class="upload-icon">
           <div class="icon-wrap">
             <i class="el-icon-plus"></i>
           </div>
         </div>
       </div>
     </slot>
    
  • 图片存在鼠标移入的遮罩使用伪元素实现
    &::before {
      content: '';
      display: block;
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      background: #000000;
      opacity: 0.5;
      z-index: 1;
    }
    

预览图片自适应缩放

  • 在 img 元素加上 object-fit: contain 样式
  • 兼容性比较强的思路(不需要跳过即可,大家有其他思路欢迎评论分享😁)
    • 图片、容器都获取到宽高
    • 计算图片宽高比 ratio
      • ratio > 1,说明是横向图片
        • 图片宽 > 容器宽(需要按比例缩小)
          • 使用容器宽、图片宽高比,计算出图片新的高度
            • 图片新高度 > 容器高
              • 使用容器高、图片宽高比,计算出图片新的宽度
                • 结果图片使用容器高、计算出来的宽度
            • 图片新高度 < 容器高
              • 结果图片使用容器宽、计算出来的高度
        • 图片宽 < 容器宽
          • 图片高 > 容器高
            • 使用容器高、图片宽高比,计算出图片新的宽度
              • 结果图片使用容器高、计算出来的宽度
          • 图片高 < 容器高(需要按比例放大)
            • 继续使用容器宽、图片宽高比计算图片新高度;若大于容器高度,再使用容器高、图片比计算图片新宽度
      • ratio < 1,说明是纵向图片(同理如上)

PS 透明背景色效果

  • 采用 background-image 实现多个背景叠加(见下图)
    • 图一采用 linear-gradient 实现上下有颜色,中间透明
    • 图二通过偏移 45 度角,实现三角
    • 图三通过设置背景大小,并让其背景沿水平轴,垂直轴重复展示
    • 图四依次两个同样背景,偏移第二个背景,让三角拼接成方块
    • 图五由于UI指定了颜色,白色方块是不行滴🤐,那就在最底层增加一个UI指定颜色的背景,上面两次的透明区域就是指定颜色了

UI大大:element图片上传不太行,按照我设计的实现一下

.bk {
  width: 300px;
  height: 300px;
  margin-left: 20px;
  &.test1 {
    background-image: linear-gradient(#666666 25%, transparent 25%, transparent 75%, #666666 75%);
  }
  &.test2 {
    background-image: linear-gradient(45deg, #666666 25%, transparent 25%, transparent 75%, #666666 75%);
  }
  &.test3 {
    background-image: linear-gradient(45deg, #666666 25%, transparent 25%, transparent 75%, #666666 75%);
    background-size: 20px 20px;
    background-repeat: repeat;
  }
  &.test4 {
    background-image: linear-gradient(45deg, #666666 25%, transparent 25%, transparent 75%, #666666 75%),
      linear-gradient(45deg, #666666 25%, transparent 25%, transparent 75%, #666666 75%, #666666 100%);
    background-size: 20px 20px;
    background-position: 0 0, 10px 10px;
    background-repeat: repeat;
  }
  &.test5 {
    background-image: linear-gradient(45deg, #666666 25%, transparent 25%, transparent 75%, #666666 75%),
      linear-gradient(45deg, #666666 25%, transparent 25%, transparent 75%, #666666 75%, #666666 100%), linear-gradient(#7f7f7f, #7f7f7f);
    background-size: 20px 20px;
    background-position: 0 0, 10px 10px;
    background-repeat: repeat;
  }
}

操作支持

  • 默认支持修改、预览、删除操作,通过 prop 传入 ['edit', 'preview', 'delete'] 相应关键字支持展示
    • 视图
    <div v-for="item in operateList" :key="item.key" :class="['show-area-common', 'icon-' + item.key]">
      <div class="icon-wrap" @click.stop="handleFuc(item)">
        <i :class="[item.icon]"></i>
      </div>
      <span class="show-area-text">{{ item.text }}</span>
    </div>
    props: {
        startOperate: {
          type: Array,
          default() {
            return ['edit', 'preview', 'delete']
          },
        },
    },
    data() {
      return {
        operateObj: {
            edit: {
              key: 'edit',
              icon: 'el-icon-plus',
              text: '修改',
            },
            preview: {
              ....
            },
            delete: {
              ...
            },
          },
        }
      }
    computed: {
        operateList() {
          return this.startOperate.map((key) => this.operateObj[key])
        }
    },
    methods: {
        handleFuc(item) {
          this[`${item.key}Fuc`]()
        },
    }
    
    • 修改
      • el-upload 点击则可触发资源框,现在需要缩小触发区域;图片预览状态并鼠标移入需要禁用 el-upload,点击修改按钮主动触发
      computed: {
          // el-upload :disabled="areaEditFlag"
          areaEditFlag() {
            if (this.uploadDisable) {
              return true
            }
            if (this.mouseOver && this.file) {
              return true
            }
            return false
          }
      },
      methods: {
         // 点击修改触发资源框
        editFuc() {
            const inputEl = this.$el.querySelector('.el-upload__input')
            inputEl.value = null
            inputEl.click()
          },
      }
      
    • 预览、删除(正常操作即可,不再介绍)
    • 自定义上传
    methods:{
        uploadSuccess(val, KeyName) {
            const windowURL = window.URL || window.webkitURL
            this.file = windowURL.createObjectURL(val.file)
            this.$emit('update:picUrl', KeyName)
         },
        httpRequest(val) {
            // props 传入自定义上传
            if (typeof this.customeUpload === 'function') {
              this.customeUpload(val, (KeyName) => {
                this.uploadSuccess(val, KeyName)
              })
            } else {
            const form = new FormData()
              // 默认上传
              form.append('file', val.file)
              ...
            }
         },
    }
    

UI大大的支配

记录一下我最近被 UI 支配的恐惧(话说大家有过这种体验嘛👾)

体验

最后

如果对你开发某些功能有所帮助,麻烦多点赞评论收藏😊

如果对你实现某类业务有所启发,麻烦多点赞评论收藏😊

如果...,麻烦多点赞评论收藏😊

如果大家有其他的方案,欢迎留言交流哦!

UI大大:element图片上传不太行,按照我设计的实现一下