<template>
|
|
<view class="avatar-stack" v-if="avatars && avatars.length > 0">
|
|
<view class="avatar-container">
|
|
<!-- 显示的头像列表 -->
|
|
<view
|
|
class="avatar-item"
|
|
v-for="(avatar, index) in displayAvatars"
|
|
:key="index"
|
|
:style="{
|
|
width: avatarSize + 'rpx',
|
|
height: avatarSize + 'rpx',
|
|
marginLeft: index > 0 ? (-overlapOffset + 'rpx') : '0',
|
|
zIndex: displayAvatars.length - index
|
|
}"
|
|
@click="handleAvatarClick(avatar, index)"
|
|
>
|
|
<image
|
|
:src="avatar.userHead || '/static/image/center/default-avatar.png'"
|
|
mode="aspectFill"
|
|
class="avatar-image"
|
|
/>
|
|
</view>
|
|
|
|
<!-- 更多数量显示 -->
|
|
<view
|
|
class="more-count"
|
|
v-if="remainingCount > 0"
|
|
:style="{
|
|
width: avatarSize + 'rpx',
|
|
height: avatarSize + 'rpx',
|
|
marginLeft: displayAvatars.length > 0 ? (-overlapOffset + 'rpx') : '0',
|
|
zIndex: 1
|
|
}"
|
|
@click="handleMoreClick"
|
|
>
|
|
<text class="count-text">+{{ remainingCount }}</text>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 描述文本 -->
|
|
<!-- <view class="description" v-if="showDescription">
|
|
<text class="desc-text">{{ getDescriptionText() }}</text>
|
|
</view> -->
|
|
</view>
|
|
</template>
|
|
|
|
<script>
|
|
export default {
|
|
name: 'AvatarStack',
|
|
props: {
|
|
// 头像数据数组
|
|
avatars: {
|
|
type: Array,
|
|
default: () => []
|
|
},
|
|
// 最大显示数量
|
|
maxDisplay: {
|
|
type: Number,
|
|
default: 5
|
|
},
|
|
// 头像大小
|
|
avatarSize: {
|
|
type: Number,
|
|
default: 60 // rpx
|
|
},
|
|
// 重叠偏移量
|
|
overlapOffset: {
|
|
type: Number,
|
|
default: 15 // rpx
|
|
},
|
|
// 是否显示描述文本
|
|
showDescription: {
|
|
type: Boolean,
|
|
default: true
|
|
},
|
|
// 描述文本类型
|
|
descriptionType: {
|
|
type: String,
|
|
default: 'viewed' // viewed, liked, shared
|
|
},
|
|
// 自定义描述文本
|
|
customDescription: {
|
|
type: String,
|
|
default: ''
|
|
}
|
|
},
|
|
computed: {
|
|
// 显示的头像列表
|
|
displayAvatars() {
|
|
return this.avatars.slice(0, this.maxDisplay)
|
|
},
|
|
|
|
// 剩余数量
|
|
remainingCount() {
|
|
return Math.max(0, this.avatars.length - this.maxDisplay)
|
|
}
|
|
},
|
|
methods: {
|
|
// 获取描述文本
|
|
getDescriptionText() {
|
|
if (this.customDescription) {
|
|
return this.customDescription
|
|
}
|
|
|
|
const total = this.avatars.length
|
|
if (total === 0) return ''
|
|
|
|
switch (this.descriptionType) {
|
|
case 'viewed':
|
|
return `${total}人看过`
|
|
case 'liked':
|
|
return `${total}人点赞`
|
|
case 'shared':
|
|
return `${total}人分享`
|
|
default:
|
|
return `${total}人参与`
|
|
}
|
|
},
|
|
|
|
// 头像点击事件
|
|
handleAvatarClick(avatar, index) {
|
|
this.$emit('avatarClick', { avatar, index })
|
|
},
|
|
|
|
// 更多按钮点击事件
|
|
handleMoreClick() {
|
|
this.$emit('moreClick', {
|
|
total: this.avatars.length,
|
|
remaining: this.remainingCount
|
|
})
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style scoped lang="scss">
|
|
.avatar-stack {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: flex-start;
|
|
|
|
.avatar-container {
|
|
display: flex;
|
|
align-items: center;
|
|
|
|
.avatar-item {
|
|
position: relative;
|
|
border-radius: 50%;
|
|
overflow: hidden;
|
|
background-color: #fff;
|
|
border: 4rpx solid #fff;
|
|
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
|
|
transition: transform 0.2s ease;
|
|
|
|
&:hover {
|
|
transform: scale(1.1);
|
|
}
|
|
|
|
.avatar-image {
|
|
width: 100%;
|
|
height: 100%;
|
|
border-radius: 50%;
|
|
}
|
|
}
|
|
|
|
.more-count {
|
|
position: relative;
|
|
border-radius: 50%;
|
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
border: 4rpx solid #fff;
|
|
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
|
|
|
|
.count-text {
|
|
color: #fff;
|
|
font-size: 20rpx;
|
|
font-weight: 600;
|
|
}
|
|
}
|
|
}
|
|
|
|
.description {
|
|
margin-top: 15rpx;
|
|
|
|
.desc-text {
|
|
font-size: 24rpx;
|
|
color: #666;
|
|
line-height: 1.4;
|
|
}
|
|
}
|
|
}
|
|
|
|
// 不同尺寸适配
|
|
@media screen and (max-width: 750rpx) {
|
|
.avatar-stack .description .desc-text {
|
|
font-size: 22rpx;
|
|
}
|
|
}
|
|
</style>
|