Skip to content

Commit

Permalink
upd: skeleton骨架屏组件 (jd-opensource#882)
Browse files Browse the repository at this point in the history
* upd: 骨架屏组件
  • Loading branch information
liqiong-lab authored Dec 22, 2021
1 parent d4f071d commit 8ccb6a6
Show file tree
Hide file tree
Showing 10 changed files with 490 additions and 0 deletions.
9 changes: 9 additions & 0 deletions src/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -879,6 +879,15 @@
},
{
"version": "3.0.0",
"name": "Skeleton",
"type": "component",
"cName": "骨架屏",
"desc": "骨架屏",
"sort": 23,
"show": true,
"taro": true,
"author": "liqiong"
},{
"name": "Cascader",
"type": "component",
"cName": "级联选择",
Expand Down
105 changes: 105 additions & 0 deletions src/packages/__VUE/skeleton/common.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import { h, onMounted, CSSProperties } from 'vue';
import { computed, PropType, toRefs } from 'vue';
export type avatarShape = 'round' | 'square';

export const component = {
props: {
//每行宽度
width: {
type: String,
default: '100px'
},
//每行高度
height: {
type: String,
default: '100px'
},
//是否显示动画
animated: {
type: Boolean,
default: false
},
//头像
avatar: {
type: Boolean,
default: false
},
//头像形状:正方形/圆形
avatarShape: {
type: String as PropType<avatarShape>,
default: 'round'
},
//头像大小
avatarSize: {
type: String,
default: '50px'
},
//是否显示骨架屏
loading: {
type: Boolean,
default: true
},
//标题/段落 圆角风格
round: {
type: Boolean,
default: false
},

//显示段落行数
row: {
type: String,
default: '1'
},

//是否显示段落标题
title: {
type: Boolean,
default: true
}
},

setup(props: any) {
const { avatarShape, round, avatarSize } = toRefs(props);

const avatarClass = computed(() => {
const prefixCls = 'avatarClass';
return {
[prefixCls]: true,
[`${prefixCls}--${avatarShape.value}`]: avatarShape.value
};
});

const blockClass = computed(() => {
const prefixCls = 'blockClass';
return {
[prefixCls]: true,
[`${prefixCls}--round`]: round.value
};
});

const getStyle = (): CSSProperties => {
const style: CSSProperties = {};
if (avatarSize?.value) {
return {
width: avatarSize.value,
height: avatarSize.value
};
}
return {
width: '50px',
height: '50px'
};
};

onMounted(() => {
console.log('row', props.row);
});

return {
avatarShape,
avatarClass,
blockClass,
getStyle
};
}
};
80 changes: 80 additions & 0 deletions src/packages/__VUE/skeleton/demo.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
<template>
<view class="demo">
<h2>基础用法</h2>

<nut-skeleton width="250px" height="15px" animated> </nut-skeleton>

<h2>传入多行</h2>

<nut-skeleton width="250px" height="15px" title animated row="3"> </nut-skeleton>

<h2>显示头像</h2>
<nut-skeleton width="250px" height="15px" title animated avatar row="3"> </nut-skeleton>

<h2>标题段落圆角风格</h2>
<nut-skeleton width="250px" height="15px" animated round></nut-skeleton>

<h2>显示子组件</h2>

<view class="content">
<nut-switch v-model="checked" size="15px" />

<nut-skeleton width="250px" height="15px" title animated avatar row="3" :loading="!checked">
<view class="container">
<nut-avatar
size="50"
icon="https://img14.360buyimg.com/imagetools/jfs/t1/167902/2/8762/791358/603742d7E9b4275e3/e09d8f9a8bf4c0ef.png"
/>
<view class="right-content">
<view class="title">NutUI</view>
<view class="desc"
>一套京东风格的轻量级移动端Vue组库,提供丰富的基础组件和业务组件,帮助开发者快速搭建移动应用。</view
>
</view>
</view>
</nut-skeleton>
</view>
</view>
</template>

<script lang="ts">
import { ref } from 'vue';
import { createComponent } from '../../utils/create';
const { createDemo } = createComponent('skeleton');
export default createDemo({
setup() {
const checked = ref(false);
return {
checked
};
}
});
</script>

<style lang="scss">
.content {
.nut-switch {
margin: 0 16px 8px 0;
}
.container {
display: flex;
.right-content {
margin-left: 19px;
font-family: PingFangSC;
display: flex;
flex-direction: column;
.title {
font-size: 14px;
color: rgba(51, 51, 51, 1);
}
.desc {
margin-top: 10px;
font-size: 13px;
color: rgba(154, 155, 157, 1);
}
}
}
}
</style>
99 changes: 99 additions & 0 deletions src/packages/__VUE/skeleton/doc.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
# Skeleton 骨架屏

### 介绍

在页面上待加载区域填充灰色的占位图,本质上是界面加载过程中的过渡效果。

### 安装

```javascript

import { createApp } from 'vue';
// vue
import { Skeleton } from '@nutui/nutui';
// taro
import { Skeleton } from '@nutui/nutui-taro';

const app = createApp();
app.use(Skeleton);

```

### 代码实例

### 基础用法

```html
<nut-skeleton width="250px" height="15px" animated> </nut-skeleton>
```

### 传入多行

```html
<nut-skeleton width="250px" height="15px" title animated row="3"> </nut-skeleton>
```


### 显示头像

```html
<nut-skeleton width="250px" height="15px" title animated avatar row="3"> </nut-skeleton>
```


### 标题段落圆角风格

```html
<nut-skeleton width="250px" height="15px" animated round></nut-skeleton>
```


### 显示子组件

```html
<div class="content">
<nut-switch v-model="checked" size="15px" />

<nut-skeleton width="250px" height="15px" title animated avatar row="3" :loading="!checked">
<div class="container">
<nut-avatar
size="50"
icon="https://img14.360buyimg.com/imagetools/jfs/t1/167902/2/8762/791358/603742d7E9b4275e3/e09d8f9a8bf4c0ef.png"
/>
<div class="right-content">
<div class="title">NutUI</div>
<div class="desc"
>一套京东风格的轻量级移动端Vue组库,提供丰富的基础组件和业务组件,帮助开发者快速搭建移动应用。</div
>
</div>
</div>
</nut-skeleton>
</div>
```





### Prop

| 字段 | 说明 | 类型 | 默认值 |
|------------|-------------------------------------------------|---------|----------|
| loading | 是否显示骨架屏 | Boolean | `true` |
| width | 每行宽度 | String | `default` |
| height | 每行高度 | String | `100px` |
| animated | 是否开启骨架屏动画 | Boolean | `false` |
| avatar | 是否显示头像 | Boolean | `false` |
| avatar-shape | 头像形状:正方形/圆形 | String | `round` |
| avatar-size | 头像大小 | String | `50px` |
| round | 标题/段落是否采用圆角风格 | Boolean | `false` |
| row | 设置段落行数 | String | `1` |
| title | 是否显示段落标题 | Boolean | `true` |


### Slots

| 名称 | 说明 |
|---------|---------------|
| default | 骨架屏显示内容 |

57 changes: 57 additions & 0 deletions src/packages/__VUE/skeleton/index.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
.skeleton {
display: inline-block;
position: relative;
overflow: hidden;
vertical-align: middle;
.content {
display: flex;
.avatarClass {
margin-right: 20px;
background: rgb(239, 239, 239);
}

.blockClass,
.blockClass--round {
width: 100%;
height: 100%;
background: rgb(239, 239, 239);
margin-top: 10px;
&:last-child {
width: 70% !important;
}
}
.blockClass--round {
border-radius: 10px;
}

.content-line {
display: flex;
flex-direction: column;
.title {
width: 30%;
height: 15px;
background: #efefef;
}
}
}

.skeleton-animation {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1;
background: linear-gradient(90deg, hsla(0, 0%, 100%, 0), hsla(0, 0%, 100%, 0.5) 50%, hsla(0, 0%, 100%, 0) 80%);
background-repeat: no-repeat;
animation: backpos 2s ease-in-out 0s infinite;
}
@keyframes backpos {
0% {
background-position-x: -500px;
}
to {
background-position-x: calc(500px + 100%);
}
}
}
31 changes: 31 additions & 0 deletions src/packages/__VUE/skeleton/index.taro.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<template>
<view v-if="!loading">
<slot></slot>
</view>
<view v-else class="skeleton">
<view class="skeleton-animation"></view>
<view class="content">
<nut-avatar
v-if="avatar"
:class="avatarClass"
:shape="avatarShape"
:style="getStyle()"
bg-color="rgb(239, 239, 239)"
></nut-avatar>

<view v-if="Number(row) == 1" :class="blockClass" :style="{ width, height }"> </view>

<view class="content-line">
<view v-if="title" class="title"></view>
<view v-for="(item, index) in Number(row)" :key="index" :class="blockClass" :style="{ width, height }"> </view
></view>
</view>
</view>
</template>

<script lang="ts">
import { createComponent } from '../../utils/create';
import { component } from './common';
const { create } = createComponent('skeleton');
export default create(component);
</script>
Loading

0 comments on commit 8ccb6a6

Please sign in to comment.