<template> <view> <view v-if="loading" class="skeleton" :class="{ animate: animate }"> <!-- 轮播图 --> <view v-if="imgTitle" class="skeleton-imgTitle" style="width: 100%;border-radius: 20rpx;height: 260rpx;display: block;" ></view> <!-- 分类图 --> <view class="skeleton-title-content" :style="{ justifyContent: flexType}"> <view v-if="showCategory" class="skeleton-category" v-for="(item, index) in categoryRow" :key="index" :class="[categoryShape]" :style="{ width: categorySize, height: categorySize}" ></view> </view> <view class="skeleton-title-content" :style="{ justifyContent: flexType}"> <view v-if="showCategory" class="skeleton-category square" v-for="(item, index) in categoryRow" :key="index" :style="{ width: categorySize, height: categorySize}" ></view> </view> <view class="skeleton-title-content" v-for="(item, index) in itemRow" :key="index" :style="{ justifyContent: flexType}"> <!-- 头像图 --> <view v-if="showAvatar" class="skeleton-avatar" v-for="(item, index) in nameRow" :key="index" :class="[avatarShape]" :style="{ width: avatarSize, height: avatarSize}" ></view> <!-- 文字条 --> <view class="skeleton-content" v-if="showTitle"> <view class="skeleton-title" :style="{ width: titleWidth }"></view> <view class="skeleton-rows"> <view class="skeleton-row-item" v-for="(item, index) in rowList" :key="index" :style="{ width: item.width }" ></view> </view> </view> </view> </view> <view v-else><slot></slot></view> </view> </template> <script> const DEFAULT_ROW_WIDTH = '100%' const DEFAULT_LAST_ROW_WIDTH = '60%' export default { props: { loading: { type: Boolean, default: true, }, imgTitle: { type: Boolean, default: false, }, nameRow:{ type: Number, default: 1, }, categoryRow:{ type: Number, default: 1 }, itemRow:{ type: Number, default: 4 }, flexType:{ type: String, default: 'flex-start', // center 居中 √ space-between 两端对齐 √ space-around 子元素拉手分布 √ flex-start 居左 flex-end 居右 }, showAvatar: { type: Boolean, default: true, }, showCategory: { type: Boolean, default: true }, avatarSize: { type: String, default: '100rpx' }, categorySize: { type: String, default: '100rpx' }, avatarShape: { type: String, default: 'round', // square | round }, categoryShape: { type: String, default: 'round', // square | round }, showTitle: { type: Boolean, default: false, }, titleWidth: { type: String, default: '40%', }, row: { type: Number, default: 3, }, animate: { type: Boolean, default: true, }, }, data() { return {} }, computed: { rowList() { let list = [] for (let i = 0; i < this.row; i++) { list.push({ width: i === this.row - 1 && i !== 0 ? DEFAULT_LAST_ROW_WIDTH : DEFAULT_ROW_WIDTH, }) } return list }, }, } </script> <style scoped> .skeleton { margin: 32rpx; --bg-color: #f2f3f5; --row-height: 32rpx; --row-margin-top: 32rpx; } .skeleton-title-content{ margin-top: 32rpx; display: flex; } .skeleton-imgTitle { flex-wrap: wrap; background: var(--bg-color); margin: 20rpx auto; } .skeleton-avatar { flex-shrink: 0; background: var(--bg-color); margin-right: 16rpx; } .skeleton-category{ flex-shrink: 0; background: var(--bg-color); margin-right: 16rpx; /* margin-top: 32rpx; */ } .skeleton-avatar.round { border-radius: 50%; } .skeleton-category.round{ border-radius: 50%; } .skeleton-content { width: 100%; } .skeleton-title { background-color: var(--bg-color); height: var(--row-height); } .skeleton-title + .skeleton-rows { margin-top: var(--row-margin-top); } .skeleton-rows { } .skeleton-row-item { background-color: var(--bg-color); height: var(--row-height); } .skeleton-row-item:not(:first-child) { margin-top: var(--row-margin-top); } .skeleton.animate { animation: skeleton-blink 1.2s ease-in-out infinite; } @keyframes skeleton-blink { 0% { opacity: 1; } 50% { opacity: 0.6; } 100% { opacity: 1; } } </style>