J-skeleton.vue 4.37 KB
<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>