瑶都万能墙
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

200 lines
4.1 KiB

  1. <template>
  2. <view class="avatar-stack" v-if="avatars && avatars.length > 0">
  3. <view class="avatar-container">
  4. <!-- 显示的头像列表 -->
  5. <view
  6. class="avatar-item"
  7. v-for="(avatar, index) in displayAvatars"
  8. :key="index"
  9. :style="{
  10. width: avatarSize + 'rpx',
  11. height: avatarSize + 'rpx',
  12. marginLeft: index > 0 ? (-overlapOffset + 'rpx') : '0',
  13. zIndex: displayAvatars.length - index
  14. }"
  15. @click="handleAvatarClick(avatar, index)"
  16. >
  17. <image
  18. :src="avatar.userHead || '/static/image/center/default-avatar.png'"
  19. mode="aspectFill"
  20. class="avatar-image"
  21. />
  22. </view>
  23. <!-- 更多数量显示 -->
  24. <view
  25. class="more-count"
  26. v-if="remainingCount > 0"
  27. :style="{
  28. width: avatarSize + 'rpx',
  29. height: avatarSize + 'rpx',
  30. marginLeft: displayAvatars.length > 0 ? (-overlapOffset + 'rpx') : '0',
  31. zIndex: 1
  32. }"
  33. @click="handleMoreClick"
  34. >
  35. <text class="count-text">+{{ remainingCount }}</text>
  36. </view>
  37. </view>
  38. <!-- 描述文本 -->
  39. <view class="description" v-if="showDescription">
  40. <text class="desc-text">{{ getDescriptionText() }}</text>
  41. </view>
  42. </view>
  43. </template>
  44. <script>
  45. export default {
  46. name: 'AvatarStack',
  47. props: {
  48. // 头像数据数组
  49. avatars: {
  50. type: Array,
  51. default: () => []
  52. },
  53. // 最大显示数量
  54. maxDisplay: {
  55. type: Number,
  56. default: 5
  57. },
  58. // 头像大小
  59. avatarSize: {
  60. type: Number,
  61. default: 60 // rpx
  62. },
  63. // 重叠偏移量
  64. overlapOffset: {
  65. type: Number,
  66. default: 15 // rpx
  67. },
  68. // 是否显示描述文本
  69. showDescription: {
  70. type: Boolean,
  71. default: true
  72. },
  73. // 描述文本类型
  74. descriptionType: {
  75. type: String,
  76. default: 'viewed' // viewed, liked, shared
  77. },
  78. // 自定义描述文本
  79. customDescription: {
  80. type: String,
  81. default: ''
  82. }
  83. },
  84. computed: {
  85. // 显示的头像列表
  86. displayAvatars() {
  87. return this.avatars.slice(0, this.maxDisplay)
  88. },
  89. // 剩余数量
  90. remainingCount() {
  91. return Math.max(0, this.avatars.length - this.maxDisplay)
  92. }
  93. },
  94. methods: {
  95. // 获取描述文本
  96. getDescriptionText() {
  97. if (this.customDescription) {
  98. return this.customDescription
  99. }
  100. const total = this.avatars.length
  101. if (total === 0) return ''
  102. switch (this.descriptionType) {
  103. case 'viewed':
  104. return `${total}人看过`
  105. case 'liked':
  106. return `${total}人点赞`
  107. case 'shared':
  108. return `${total}人分享`
  109. default:
  110. return `${total}人参与`
  111. }
  112. },
  113. // 头像点击事件
  114. handleAvatarClick(avatar, index) {
  115. this.$emit('avatarClick', { avatar, index })
  116. },
  117. // 更多按钮点击事件
  118. handleMoreClick() {
  119. this.$emit('moreClick', {
  120. total: this.avatars.length,
  121. remaining: this.remainingCount
  122. })
  123. }
  124. }
  125. }
  126. </script>
  127. <style scoped lang="scss">
  128. .avatar-stack {
  129. display: flex;
  130. flex-direction: column;
  131. align-items: flex-start;
  132. .avatar-container {
  133. display: flex;
  134. align-items: center;
  135. .avatar-item {
  136. position: relative;
  137. border-radius: 50%;
  138. overflow: hidden;
  139. background-color: #fff;
  140. border: 4rpx solid #fff;
  141. box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
  142. transition: transform 0.2s ease;
  143. &:hover {
  144. transform: scale(1.1);
  145. }
  146. .avatar-image {
  147. width: 100%;
  148. height: 100%;
  149. border-radius: 50%;
  150. }
  151. }
  152. .more-count {
  153. position: relative;
  154. border-radius: 50%;
  155. background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  156. display: flex;
  157. align-items: center;
  158. justify-content: center;
  159. border: 4rpx solid #fff;
  160. box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
  161. .count-text {
  162. color: #fff;
  163. font-size: 20rpx;
  164. font-weight: 600;
  165. }
  166. }
  167. }
  168. .description {
  169. margin-top: 15rpx;
  170. .desc-text {
  171. font-size: 24rpx;
  172. color: #666;
  173. line-height: 1.4;
  174. }
  175. }
  176. }
  177. // 不同尺寸适配
  178. @media screen and (max-width: 750rpx) {
  179. .avatar-stack .description .desc-text {
  180. font-size: 22rpx;
  181. }
  182. }
  183. </style>