Skip to content

Commit e3157ef

Browse files
committed
feat: [components] add Skeleton Components
1 parent a1bc7a8 commit e3157ef

File tree

7 files changed

+245
-3
lines changed

7 files changed

+245
-3
lines changed

components/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
export type * from "./button";
22
export type * from "./list";
3+
export type * from "./skeleton";

components/list/list.vue

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
<script lang="ts" setup>
22
import type { CSSProperties } from "vue";
33
import { computed, defineComponent, onMounted, ref } from "vue";
4-
import { PREFIX } from "../_constants";
54
import type {
65
ScrollViewOnRefresherrefresh,
76
ScrollViewOnScrolltolower,
87
ScrollViewProps,
8+
ScrollViewOnRefresherpulling,
99
} from "@uni-helper/uni-app-types";
10-
import { listProps, ListEmits } from "./list";
10+
import { listProps, type ListEmits } from "./list";
1111
import type { ListInst } from "./type";
12+
import UpSkeleton from "../skeleton/skeleton.vue";
1213
1314
const props = defineProps(listProps);
1415
const emit = defineEmits<ListEmits>();
@@ -100,7 +101,9 @@ export default {
100101
<template v-if="listObj?.loading">
101102
<view :class="scrollViewProps.scrollX ? 'loading-box' : ''">
102103
<!-- 骨架屏 -->
103-
<slot name="loading"> loading... </slot>
104+
<slot name="loading">
105+
<UpSkeleton />
106+
</slot>
104107
</view>
105108
</template>
106109
</scroll-view>

components/skeleton/index.scss

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
@mixin background {
2+
/* #ifdef APP-NVUE */
3+
background-color: #f1f2f4;
4+
/* #endif */
5+
/* #ifndef APP-NVUE */
6+
background: linear-gradient(90deg, #f1f2f4 25%, #e6e6e6 37%, #f1f2f4 50%);
7+
background-size: 400% 100%;
8+
/* #endif */
9+
};
10+
11+
.unip-skeleton {
12+
flex: 1;
13+
width: 100%;
14+
15+
&__wrapper {
16+
&__avatar {
17+
@include background;
18+
margin-right: 15px;
19+
20+
&--circle {
21+
border-radius: 100px;
22+
}
23+
24+
&--square {
25+
border-radius: 4px;
26+
}
27+
}
28+
29+
&__title {
30+
margin-top: 16rpx;
31+
width: 100%;
32+
height: 36rpx;
33+
border-radius: 3px;
34+
35+
&:first-child {
36+
margin-top: 0;
37+
}
38+
39+
@include background;
40+
41+
&__list {
42+
width: 100%;
43+
display: flex;
44+
flex-direction: column;
45+
}
46+
}
47+
48+
&__content {
49+
flex: 1;
50+
51+
&__rows,
52+
&__title {
53+
@include background;
54+
border-radius: 3px;
55+
}
56+
}
57+
}
58+
}
59+
60+
.animate {
61+
animation: skeleton 1.8s ease infinite;
62+
}
63+
64+
@keyframes skeleton {
65+
0% {
66+
background-position: 100% 50%;
67+
}
68+
69+
100% {
70+
background-position: 0 50%;
71+
}
72+
}
73+
.unip-skeleton__wrapper__title {
74+
margin-top: 0.5rem;
75+
width: 100%;
76+
height: 1.125rem;
77+
border-radius: 3px;
78+
// background: $backgroundL-g-6;
79+
background-size: 400% 100%;
80+
}

components/skeleton/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from "./skeleton";

components/skeleton/skeleton.ts

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import type { ExtractPropTypes, PropType } from "vue";
2+
import type { SkeletonType,AvatarShapeType } from "./type";
3+
import { makeStringProp } from "../_utils";
4+
5+
6+
// 定义 props
7+
export const skeletonProps = {
8+
/**
9+
* @description 骨架屏类型
10+
*/
11+
type: makeStringProp<SkeletonType>("title"),
12+
/**
13+
* @description 是否禁用刷新功能
14+
* @default false
15+
*/
16+
loading: {
17+
type: Boolean,
18+
default: true,
19+
},
20+
/**
21+
* @description 是否开启骨架屏
22+
* @default false
23+
*/
24+
animate: {
25+
type: Boolean,
26+
default: true,
27+
},
28+
/**
29+
* @description 头像形状
30+
* @default "circle"
31+
*/
32+
avatarShape: makeStringProp<AvatarShapeType>("circle"),
33+
/**
34+
* @description 头像大小
35+
* @default 60
36+
*/
37+
avatarSize: {
38+
type: [Number, String] as PropType<number | string>,
39+
default: 60,
40+
},
41+
/**
42+
* @description 标题高度
43+
* @default 36
44+
*/
45+
titleHeight: {
46+
type: [Number, String] as PropType<number | string>,
47+
default: 36,
48+
},
49+
/**
50+
* @description 标题宽度
51+
* @default "100%"
52+
*/
53+
titleWidth: {
54+
type: [Number, String] as PropType<number | string>,
55+
default: "100%",
56+
},
57+
/**
58+
* @description 行数
59+
* @default 3
60+
*/
61+
rows: {
62+
type: Number,
63+
default: 3,
64+
},
65+
66+
67+
68+
} as const;
69+
70+
export type SkeletonProps = ExtractPropTypes<typeof skeletonProps>;

components/skeleton/skeleton.vue

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
<script lang="ts" setup>
2+
import { onMounted } from "vue";
3+
import { skeletonProps } from "./skeleton";
4+
import { isString } from "../_utils";
5+
6+
defineProps(skeletonProps);
7+
8+
onMounted(() => {});
9+
function getStyleVal(target: number | string) {
10+
if (isString(target)) {
11+
return target;
12+
}
13+
return `${target}rpx`;
14+
}
15+
</script>
16+
17+
<script lang="ts">
18+
import { PREFIX } from "../_constants";
19+
const componentName = `${PREFIX}-skeleton`;
20+
21+
export default {
22+
name: componentName,
23+
options: {
24+
virtualHost: true,
25+
addGlobalClass: true,
26+
// #ifndef H5
27+
styleIsolation: "shared",
28+
// #endif
29+
},
30+
};
31+
</script>
32+
33+
<template>
34+
<view class="unip-skeleton">
35+
<view
36+
v-if="loading"
37+
class="unip-skeleton__wrapper"
38+
style="display: flex; flex-direction: row"
39+
>
40+
<!-- 头像 -->
41+
<template v-if="type === 'avatar'">
42+
<view
43+
class="unip-skeleton__wrapper__avatar"
44+
:class="[
45+
`unip-skeleton__wrapper__avatar--${avatarShape}`,
46+
animate && 'animate',
47+
]"
48+
:style="{
49+
width: getStyleVal(avatarSize),
50+
height: getStyleVal(avatarSize),
51+
}"
52+
/>
53+
</template>
54+
<!-- 标题 -->
55+
<template v-else-if="type === 'title'">
56+
<view class="unip-skeleton__wrapper__title__list">
57+
<view
58+
v-for="idx in rows"
59+
:key="idx"
60+
class="unip-skeleton__wrapper__title"
61+
:class="[animate && 'animate']"
62+
:style="{
63+
height: getStyleVal(titleHeight),
64+
width: idx === 1 ? '50%' : getStyleVal(titleWidth),
65+
}"
66+
/>
67+
</view>
68+
</template>
69+
</view>
70+
</view>
71+
</template>
72+
73+
<style lang="scss">
74+
@import "./index";
75+
</style>

components/skeleton/type.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
export const skeletonType = [
2+
"title",
3+
"avatar",
4+
] as const;
5+
export type SkeletonType = (typeof skeletonType)[number];
6+
7+
export const avatarShapeType = [
8+
"circle",
9+
"square",
10+
] as const;
11+
export type AvatarShapeType = (typeof avatarShapeType)[number];
12+

0 commit comments

Comments
 (0)