效果
优点
- 组件UI美化并支持宽度自适应
- 预览图片按自身比例缩放展示
- 解决与背景同色图片无法清楚预览
- 配置支持修改、预览、删除等操作
需求
- 实现交互效果,并支持宽度自适应
- 预览图片宽高小于或大于容器,图片按照自身比例缩放展示
- 预览图片实现 PS 透明背景色的效果
- 支持修改、预览、删除操作
解析思路
- 由于时间紧张并且需要 el-upload 原本的一些功能,直接在此基础上封装
- 思路
- 交互效果并支持宽度自适应
- 中间内容以及边框默认移入效果(不再介绍)
- 自适应宽通过样式覆盖 el-upload 宽高 100%
- 四角可以使用八个元素绘制,为了省事让UI出了四个角的图
- 预览图片自适应缩放
- 由于不需要兼容IE浏览器,直接一个样式解决(object-fit: contain)
- 个人有个兼容性强的思路会在下面分享
- PS 透明背景色效果
- 采用多层背景叠加实现
- 支持修改、预览、删除操作
- 基于 el-upload 实现相应功能,取决于配置项展示
- 交互效果并支持宽度自适应
实现
交互效果、宽度自适应
-
最初 UI 出的是整个方框的图,后期支持自适应,会产生变形,最后采用点九切图
- 只切不能拉伸的地方(如下图)
- 采用绝对定位实现(使用 svg 需要注意 dom 宽高设置与其一致,并保证 svg 图无边缘空隙)
- 只切不能拉伸的地方(如下图)
-
中间区域可自定义,也可使用默认布局替换中间区域图片
js<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>
-
图片存在鼠标移入的遮罩使用伪元素实现
css&::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,说明是纵向图片(同理如上)
- ratio > 1,说明是横向图片
PS 透明背景色效果
- 采用 background-image 实现多个背景叠加(见下图)
- 图一采用 linear-gradient 实现上下有颜色,中间透明
- 图二通过偏移 45 度角,实现三角
- 图三通过设置背景大小,并让其背景沿水平轴,垂直轴重复展示
- 图四依次两个同样背景,偏移第二个背景,让三角拼接成方块
- 图五由于UI指定了颜色,白色方块是不行滴🤐,那就在最底层增加一个UI指定颜色的背景,上面两次的透明区域就是指定颜色了
css
.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'] 相应关键字支持展示
- 视图
js<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,点击修改按钮主动触发
jscomputed: { // 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() }, }
-
预览、删除(正常操作即可,不再介绍)
-
自定义上传
jsmethods:{ 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 支配的恐惧(话说大家有过这种体验嘛👾)
体验
最后
如果对你开发某些功能有所帮助,麻烦多点赞评论收藏😊
如果对你实现某类业务有所启发,麻烦多点赞评论收藏😊
如果...,麻烦多点赞评论收藏😊
如果大家有其他的方案,欢迎留言交流哦!