因为需要做了一个相册的业务组件,我感觉还挺难看的,分享给大家看一下,能够本人提取,6 点几了,上班先!
<template>
<div class="img-wrapper">
<el-button
icon="h-icon-angle_left"
plain
class="left to"
:disabled="disabledPrev"
@click="toRight"
></el-button>
<div ref="imagesWrapper" class="images">
<div v-if="noData" class="empty-text">
<slot name="empty"> 暂无数据 </slot>
</div>
<div v-show="!noData" class="items" :style="itemsStyle">
<div
v-for="(item, index) in data"
:key="index"
class="item-img"
:style="imgSize"
:class="{'is-active': index === currentIndex}"@click="selected(index)"
>
<img :title="item[props.title]" :src="item[props.url]" />
<p v-if="item[props.title]" v-ellipsis class="item-date">
{{item[props.title] }}
</p>
</div>
</div>
</div>
<el-button
icon="h-icon-angle_right"
:disabled="disabledNext"
plain
class="right to"
@click="Left"
></el-button>
</div>
</template>
<script>
export default {
name: 'ImagesGroup',
props: {
imgSize: {
type: Object,
default: () => {
return {
width: '120px',
height: '120px'
};
}
},
value: {
type: Number,
default: null
},
data: {
type: Array,
default: () => []
}
},
data() {
return {
props: {
title: 'title',
url: 'url',
key: 'key',
type: 'type'
},
currentIndex: '',
translateX: 0,
pageSize: 0 // 一页展现的图片数
};
},
computed: {
// 偏移度数
itemsStyle() {
return {transform: `translateX(${-this.translateX}px)`
};
},
// 每一项宽度
itemWidth() {return parseInt(this.imgSize.width.replace('px', '')) + 8;
},
disabledPrev() {
// 禁用前一页按钮
return this.translateX <= 0;
},
disabledNext() {
// 禁用后一页按钮
return (this.translateX >= (this.data.length - this.pageSize) * this.itemWidth
);
},
noData() {return this.data.length === 0;},
dataLength() {return this.data.length;}
},
watch: {
value: {
immediate: true,
handler(val) {this.currentIndex = val;}
}
},
mounted() {this.pageSize = this.wrapperWidth() / this.itemWidth;
},
methods: {toRight() {if (this.translateX < this.pageSize * this.itemWidth) {this.translateX = 0;} else {this.translateX = this.translateX - this.pageSize * this.itemWidth;}
},
Left() {
this.translateX = this.translateX + this.pageSize * this.itemWidth;
const maxTrans = this.itemWidth * (this.dataLength - this.pageSize);
if (this.translateX > maxTrans) {this.translateX = maxTrans;}
},
selected(index) {
const center = this.pageSize >> 1;
// 最初一页的两头地位
const lastCenter = this.dataLength - center;
if (index > center && index < lastCenter) {
// 与相册两头相差的图片数量
const step = index - center;
// 将点击图片挪动到两头
this.translateX = this.itemWidth * step;
} else {const maxTrans = this.itemWidth * (this.dataLength - this.pageSize);
this.translateX = index <= center ? 0 : maxTrans;
}
if (this.currentIndex !== index) {
this.currentIndex = index;
this.$emit('input', index);
}
},
wrapperWidth() {if (this.$refs.imagesWrapper) {return this.$refs.imagesWrapper.offsetWidth;}
return 0;
}
}
};
</script>
<style lang="less" scoped>
.img-wrapper {
display: flex;
position: relative;
margin: 20px;
height: 120px;
.to {
width: 32px;
height: 100%;
padding: 0;
}
.images::before {
position: absolute;
z-index: 5;
top: 0;
height: 100%;
width: 84px;
content: '';
pointer-events: none;
background: -webkit-gradient(
linear,
left top,
right top,
from(#fff),
color-stop(50%, rgba(0, 0, 0, 0))
);
background: -o-linear-gradient(left, #fff, rgba(0, 0, 0, 0) 50%);
background: linear-gradient(90deg, #fff, rgba(0, 0, 0, 0) 50%);
}
.images::after {
position: absolute;
z-index: 5;
top: 0;
height: 100%;
right: 0;
width: 84px;
content: '';
pointer-events: none;
background: -webkit-gradient(
linear,
right top,
left top,
from(#fff),
color-stop(50%, rgba(0, 0, 0, 0))
);
background: -o-linear-gradient(right, #fff, rgba(0, 0, 0, 0) 50%);
background: linear-gradient(270deg, #fff, rgba(0, 0, 0, 0) 50%);
}
.images {
position: relative;
overflow: hidden;
width: 100%;
height: 100%;
margin: 0 2px;
.empty-text {color: rgb(158, 158, 158);
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.items {
position: absolute;
top: 0;
left: 0;
display: flex;
// width: 6000px;
height: 100%;
align-items: center;
transition: transform 0.25s ease;
.item-img {
display: inline-block;
box-sizing: border-box;
position: relative;
margin-right: 8px;
border: 2px solid rgba(0, 0, 0, 0);
cursor: pointer;
.item-date {
bottom: 0px;
position: absolute;
width: 100%;
height: 24px;
background: rgba(0, 0, 0, 0.2);
text-align: center;
line-height: 24px;
color: white;
}
img {
width: 100%;
height: 100%;
}
}
.item-img:hover::after {
// border-color: #409EFF;
opacity: 0;
}
.item-img::after {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
content: '';
opacity: 0.2;
pointer-events: none;
-webkit-transition: opacity 0.3s ease;
-o-transition: opacity 0.3s ease;
transition: opacity 0.3s ease;
background-color: #fff;
}
.is-active {border-color: #409eff;}
.is-active:after {opacity: 0;}
}
}
}
</style>