From 500903f5783210966dffb9b36da33009537ad6cd Mon Sep 17 00:00:00 2001 From: junjun666 <35680677+junjun666@users.noreply.github.com> Date: Mon, 7 Mar 2022 18:03:24 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20skeleton=20=E9=AA=A8=E6=9E=B6=E5=B1=8F?= =?UTF-8?q?=E7=BB=84=E4=BB=B6=20(#96)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 文档支持在线调试 * feat: 提交skeleton骨架屏代码提交 * fix: 提交骨架屏的review代码 --- src/config.json | 12 +- src/packages/avatar/doc.md | 12 +- src/packages/barrage/doc.md | 1 + src/packages/circleprogress/doc.md | 12 +- src/packages/infiniteloading/doc.md | 6 + src/packages/inputnumber/doc.md | 15 +++ src/packages/overlay/doc.md | 3 + src/packages/skeleton/demo.scss | 24 ++++ src/packages/skeleton/demo.tsx | 47 ++++++++ src/packages/skeleton/doc.md | 167 ++++++++++++++++++++++++++++ src/packages/skeleton/index.ts | 2 + src/packages/skeleton/skeleton.scss | 65 +++++++++++ src/packages/skeleton/skeleton.tsx | 118 ++++++++++++++++++++ src/packages/steps/doc.md | 10 +- src/packages/uploader/doc.md | 23 +++- 15 files changed, 509 insertions(+), 8 deletions(-) create mode 100644 src/packages/skeleton/demo.scss create mode 100644 src/packages/skeleton/demo.tsx create mode 100644 src/packages/skeleton/doc.md create mode 100644 src/packages/skeleton/index.ts create mode 100644 src/packages/skeleton/skeleton.scss create mode 100644 src/packages/skeleton/skeleton.tsx diff --git a/src/config.json b/src/config.json index 9539eb348d..7b4dd29f70 100644 --- a/src/config.json +++ b/src/config.json @@ -566,6 +566,16 @@ "show": false, "exportEmpty": true, "author": "szg2008" + }, + { + "version": "1.0.0", + "name": "Skeleton", + "type": "component", + "cName": "骨架屏", + "desc": "在页面上待加载区域填充灰色的占位图,本质上是界面加载过程中的过渡效果。", + "sort": 15, + "show": true, + "author": "swag~jun" } ] }, @@ -625,4 +635,4 @@ ] } ] -} +} \ No newline at end of file diff --git a/src/packages/avatar/doc.md b/src/packages/avatar/doc.md index ca607ecfb0..d21c5879f4 100644 --- a/src/packages/avatar/doc.md +++ b/src/packages/avatar/doc.md @@ -34,9 +34,11 @@ const App = () => { } export default App; ``` +::: ### 修改形状类型 +:::demo ``` tsx import React from "react"; import { Avatar } from '@nutui/nutui-react'; @@ -51,9 +53,11 @@ const App = () => { } export default App; ``` +::: ### 修改背景色 +:::demo ``` tsx import React from "react"; import { Avatar } from '@nutui/nutui-react'; @@ -70,9 +74,11 @@ const App = () => { } export default App; ``` +::: ### 修改背景icon +:::demo ``` tsx import React from "react"; import { Avatar } from '@nutui/nutui-react'; @@ -85,9 +91,11 @@ const App = () => { } export default App; ``` +::: ### 设置头像的文本内容 +:::demo ``` tsx import React from "react"; import { Avatar } from '@nutui/nutui-react'; @@ -100,9 +108,11 @@ const App = () => { } export default App; ``` +::: ### 点击头像触发事件 +:::demo ``` tsx import React from "react"; import { Avatar } from '@nutui/nutui-react'; @@ -119,7 +129,7 @@ const App = () => { } export default App; ``` - +::: ### Prop diff --git a/src/packages/barrage/doc.md b/src/packages/barrage/doc.md index a6a8fa7662..cf58677d17 100644 --- a/src/packages/barrage/doc.md +++ b/src/packages/barrage/doc.md @@ -49,6 +49,7 @@ const App = () => { } export default App; ``` +::: ## API diff --git a/src/packages/circleprogress/doc.md b/src/packages/circleprogress/doc.md index 97b875a706..cd481128fb 100644 --- a/src/packages/circleprogress/doc.md +++ b/src/packages/circleprogress/doc.md @@ -28,8 +28,11 @@ const App = () => { } export default App; ``` +::: + ### 环形进度条自定义样式 +:::demo ```tsx import React from "react"; import { CircleProgress } from '@nutui/nutui-react'; @@ -49,8 +52,10 @@ const App = () => { } export default App; ``` -### 环形进度条自定义内容 +::: +### 环形进度条自定义内容 +:::demo ```tsx import React from "react"; import { CircleProgress } from '@nutui/nutui-react'; @@ -72,8 +77,10 @@ const App = () => { } export default App; ``` -### 动态改变环形进度条的进度 +::: +### 动态改变环形进度条的进度 +:::demo ```tsx import React, { useState } from "react"; import { Button, CircleProgress } from '@nutui/nutui-react'; @@ -137,6 +144,7 @@ const App = () => { } export default App; ``` +::: ## Prop diff --git a/src/packages/infiniteloading/doc.md b/src/packages/infiniteloading/doc.md index c4a07116d5..9ee2e0cdf4 100644 --- a/src/packages/infiniteloading/doc.md +++ b/src/packages/infiniteloading/doc.md @@ -89,9 +89,11 @@ const App = () => { } export default App; ``` +::: ### 下拉刷新 +:::demo ```tsx import React, { useState, useEffect } from "react"; import { Cell, Infiniteloading } from '@nutui/nutui-react'; @@ -176,8 +178,10 @@ const App = () => { } export default App; ``` +::: ### 自定义加载文案 +:::demo ```tsx import React, { useState, useEffect } from "react"; import { Cell, Infiniteloading } from '@nutui/nutui-react'; @@ -254,6 +258,8 @@ const App = () => { } export default App; ``` +::: + ## API ### Props diff --git a/src/packages/inputnumber/doc.md b/src/packages/inputnumber/doc.md index c90b881f88..7e0512a5fe 100644 --- a/src/packages/inputnumber/doc.md +++ b/src/packages/inputnumber/doc.md @@ -40,11 +40,13 @@ const App = () => { } export default App; ``` +::: ### 步长设置 设置步长 `step` 5 +:::demo ```tsx import React, { useState } from "react"; import { InputNumber } from '@nutui/nutui-react'; @@ -68,11 +70,13 @@ const App = () => { } export default App; ``` +::: ### 限制输入范围 `min` 和 `max` 属性分别表示最小值和最大值 +:::demo ```tsx import React, { useState } from "react"; import { InputNumber } from '@nutui/nutui-react'; @@ -100,11 +104,13 @@ const App = () => { } export default App; ``` +::: ### 禁用状态 `disabled` 禁用状态下无法点击按钮或修改输入框。 +:::demo ```tsx import React, { useState } from "react"; import { InputNumber } from '@nutui/nutui-react'; @@ -128,11 +134,13 @@ const App = () => { } export default App; ``` +::: ### 只读禁用输入框 `readonly` 设置只读禁用输入框输入行为 +:::demo ```tsx import React, { useState } from "react"; import { InputNumber } from '@nutui/nutui-react'; @@ -156,11 +164,13 @@ const App = () => { } export default App; ``` +::: ### 支持小数点 设置步长 `step` 0.1 `decimal-places` 小数保留1位 +:::demo ```tsx import React, { useState } from "react"; import { InputNumber } from '@nutui/nutui-react'; @@ -184,10 +194,12 @@ const App = () => { } export default App; ``` +::: ### 支持异步修改 通过 `change` 事件和 `model-value` 进行异步修改 +:::demo ```tsx import React, { useState } from "react"; import { InputNumber, Toast } from '@nutui/nutui-react'; @@ -219,11 +231,13 @@ const App = () => { } export default App; ``` +::: ### 自定义按钮大小 设置步长 `step` 0.1 `decimal-places` 小数保留1位 +:::demo ```tsx import React, { useState } from "react"; import { InputNumber, Toast } from '@nutui/nutui-react'; @@ -247,6 +261,7 @@ const App = () => { } export default App; ``` +::: ## API diff --git a/src/packages/overlay/doc.md b/src/packages/overlay/doc.md index 2e801b74ff..f3f272bffd 100644 --- a/src/packages/overlay/doc.md +++ b/src/packages/overlay/doc.md @@ -39,9 +39,11 @@ const App = () => { } export default App; ``` +::: ### 嵌套内容 +:::demo ```tsx import React, { useState } from "react"; import { Button, Overlay } from '@nutui/nutui-react'; @@ -85,6 +87,7 @@ const App = () => { } export default App; ``` +::: ## API diff --git a/src/packages/skeleton/demo.scss b/src/packages/skeleton/demo.scss new file mode 100644 index 0000000000..78dd607fef --- /dev/null +++ b/src/packages/skeleton/demo.scss @@ -0,0 +1,24 @@ +.content { + .nut-switch { + display: flex; + 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); + } + } + } +} diff --git a/src/packages/skeleton/demo.tsx b/src/packages/skeleton/demo.tsx new file mode 100644 index 0000000000..103610bf17 --- /dev/null +++ b/src/packages/skeleton/demo.tsx @@ -0,0 +1,47 @@ +import React, { useState } from 'react' +import { Skeleton } from './skeleton' +import Switch from '@/packages/switch' +import Avatar from '@/packages/avatar' +import './demo.scss' + +const SkeletonDemo = () => { + const [checked, setChecked] = useState(false) + const changeStatus = (value: boolean, event: React.MouseEvent) => { + console.log(`触发了change事件,开关状态:${value}`) + setChecked(value) + } + return ( + <> +
+

基础用法

+ +

传入多行

+ +

显示头像

+ +

标题段落圆角风格

+ +

显示子组件

+
+ changeStatus(value, event)}> + +
+ +
+ NutUI-React +
+ 一套京东风格的轻量级移动端React组件库,提供丰富的基础组件和业务组件,帮助开发者快速搭建移动应用。 +
+
+
+
+
+
+ + ) +} + +export default SkeletonDemo diff --git a/src/packages/skeleton/doc.md b/src/packages/skeleton/doc.md new file mode 100644 index 0000000000..25b9660bd6 --- /dev/null +++ b/src/packages/skeleton/doc.md @@ -0,0 +1,167 @@ +# Skeleton组件 + +### 介绍 + +在页面上待加载区域填充灰色的占位图,本质上是界面加载过程中的过渡效果。 + +### 安装 +``` ts +import { Skeleton } from '@nutui/nutui-react'; +``` + + +## 代码演示 + +### 基础用法 + +:::demo +```tsx +import React from "react"; +import { Skeleton } from '@nutui/nutui-react'; + +const App = () => { + return ( + <> + + + ) +} +export default App; +``` +::: + +### 传入多行 + +:::demo +```tsx +import React from "react"; +import { Skeleton } from '@nutui/nutui-react'; + +const App = () => { + return ( + <> + + + ) +} +export default App; +``` +::: + +### 显示头像 + +:::demo +```tsx +import React from "react"; +import { Skeleton } from '@nutui/nutui-react'; + +const App = () => { + return ( + <> + + + ) +} +export default App; +``` +::: + +### 标题段落圆角风格 + +:::demo +```tsx +import React from "react"; +import { Skeleton } from '@nutui/nutui-react'; + +const App = () => { + return ( + <> + + + ) +} +export default App; +``` +::: + +### 显示子组件 + +:::demo +```tsx +import React, { useState } from 'react' +import { Skeleton, Switch, Avatar } from '@nutui/nutui-react'; + +const NutSwitchStyle = { + display: 'flex', + margin: '0 16px 8px 0' +} + +const RightContentStyle = { + marginLeft: '19px', + fontFamily: 'PingFangSC', + display: 'flex', + flexDirection: 'column' +} + +const TitleStyle = { + fontSize: '14px', + color: 'rgba(51, 51, 51, 1)' +} + +const DescStyle = { + marginTop: '10px', + fontSize: '13px', + color: 'rgba(154, 155, 157, 1)' +} + +const App = () => { + const [checked, setChecked] = useState(false) + const changeStatus = (value: boolean, event: React.MouseEvent) => { + console.log(`触发了change事件,开关状态:${value}`) + setChecked(value) + } + return ( + <> +
+ changeStatus(value, event)} className={NutSwitchStyle}> + +
+ +
+ NutUI-React +
+ 一套京东风格的轻量级移动端React组件库,提供丰富的基础组件和业务组件,帮助开发者快速搭建移动应用。 +
+
+
+
+
+ + ) +} +export default App; +``` +::: + + + + +## API + +### Prop + +| 字段 | 说明 | 类型 | 默认值 | +|------------|-------------------------------------------------|---------|----------| +| loading | 是否显示骨架屏 | Boolean | `false` | +| width | 每行宽度 | Number | 100 | +| height | 每行高度 | Number | 100 | +| animated | 是否开启骨架屏动画 | Boolean | `false` | +| avatar | 是否显示头像 | Boolean | `false` | +| avatarShape | 头像形状:正方形/圆形 | String | `round` | +| avatarSize | 头像大小 | String | `50px` | +| round | 标题/段落是否采用圆角风格 | Boolean | `false` | +| row | 设置段落行数 | Number | 1 | +| title | 是否显示段落标题 | Boolean | `false` | diff --git a/src/packages/skeleton/index.ts b/src/packages/skeleton/index.ts new file mode 100644 index 0000000000..dc39e014d9 --- /dev/null +++ b/src/packages/skeleton/index.ts @@ -0,0 +1,2 @@ +import { Skeleton } from './skeleton' +export default Skeleton diff --git a/src/packages/skeleton/skeleton.scss b/src/packages/skeleton/skeleton.scss new file mode 100644 index 0000000000..ea68154598 --- /dev/null +++ b/src/packages/skeleton/skeleton.scss @@ -0,0 +1,65 @@ +.nut-skeleton { + display: inline-block; + position: relative; + overflow: hidden; + vertical-align: middle; + .nut-skeleton-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; + } + + .skeleton-lines { + &:last-child { + width: 70% !important; + } + } + .blockClass--round { + border-radius: 10px; + } + + .skeleton-content-line { + display: flex; + flex-direction: column; + .skeleton-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%); + } + } +} diff --git a/src/packages/skeleton/skeleton.tsx b/src/packages/skeleton/skeleton.tsx new file mode 100644 index 0000000000..2eafe33986 --- /dev/null +++ b/src/packages/skeleton/skeleton.tsx @@ -0,0 +1,118 @@ +import React, { FunctionComponent } from 'react' +import classNames from 'classnames' +import Avatar from '@/packages/avatar' +import bem from '@/utils/bem' +import './skeleton.scss' + +type avatarShape = 'round' | 'square' +export interface SkeletonProps { + width: number + height: number + animated: boolean + row: number + title: boolean + avatar: boolean + className?: string + style?: React.CSSProperties + avatarSize: string + round: boolean + loading: boolean + avatarShape: avatarShape +} +const defaultProps = { + width: 100, + height: 100, + row: 1, + animated: false, + title: false, + avatar: false, + round: false, + avatarSize: '50px', + loading: false, + avatarShape: 'round', +} as SkeletonProps +export const Skeleton: FunctionComponent> = (props) => { + const { + className, + width, + height, + animated, + row, + title, + avatar, + avatarSize, + round, + loading, + children, + avatarShape, + ...restProps + } = { + ...defaultProps, + ...props, + } + + const b = bem('skeleton') + const classes = classNames(className, b()) + const blockClass = classNames({ + ['blockClass']: true, + ['blockClass--round']: round, + }) + const avatarClass = classNames({ + ['avatarClass']: true, + [`avatarClass--${avatarShape}`]: avatarShape, + }) + + const repeatLines = (num: number) => { + return Array.from({ length: num }, (v, i) => i) + } + + const getStyle = () => { + return { + width: avatarSize, + height: avatarSize, + } + } + + return ( + <> + {loading ? ( +
{children}
+ ) : ( +
+
+
+ {avatar && ( + + )} + {row === 1 ? ( +
+ ) : ( +
+ {title &&
} + {repeatLines(row).map((item, index) => { + return ( +
+ ) + })} +
+ )} +
+
+ )} + + ) +} + +Skeleton.defaultProps = defaultProps +Skeleton.displayName = 'NutSkeleton' diff --git a/src/packages/steps/doc.md b/src/packages/steps/doc.md index 6a4079ea4b..9f6839046e 100644 --- a/src/packages/steps/doc.md +++ b/src/packages/steps/doc.md @@ -53,9 +53,11 @@ const App = () => { } export default App; ``` +::: ### 标题和描述信息 +:::demo ```tsx import React, { useState } from "react"; import { Steps, Step, Button } from '@nutui/nutui-react'; @@ -96,9 +98,11 @@ const App = () => { } export default App; ``` +::: ### 自定义图标 +:::demo ```tsx import React, { useState } from "react"; import { Steps, Step, Button } from '@nutui/nutui-react'; @@ -138,9 +142,10 @@ const App = () => { } export default App; ``` +::: ### 竖向步骤条 - +:::demo ```tsx import React, { useState } from "react"; import { Steps, Step, Button } from '@nutui/nutui-react'; @@ -184,8 +189,10 @@ const App = () => { } export default App; ``` +::: ### 点状步骤和垂直方向 +:::demo ```tsx import React, { useState } from "react"; import { Steps, Step, Button } from '@nutui/nutui-react'; @@ -234,6 +241,7 @@ const App = () => { } export default App; ``` +::: ## API diff --git a/src/packages/uploader/doc.md b/src/packages/uploader/doc.md index 12b0cf2fdd..e72ecaf786 100644 --- a/src/packages/uploader/doc.md +++ b/src/packages/uploader/doc.md @@ -33,10 +33,11 @@ const App = () => { } export default App; ``` - +::: ### 自定义上传样式 +:::demo ``` tsx import React, { useState } from "react"; import { Uploader, Button } from '@nutui/nutui-react'; @@ -56,9 +57,11 @@ const App = () => { } export default App; ``` +::: ### 直接调起摄像头(移动端生效) - + +:::demo ``` tsx import React, { useState } from "react"; import { Uploader, Button } from '@nutui/nutui-react'; @@ -74,9 +77,11 @@ const App = () => { } export default App; ``` +::: ### 上传状态 - + +:::demo ``` tsx import React, { useState } from "react"; import { Uploader, Button } from '@nutui/nutui-react'; @@ -95,10 +100,12 @@ const App = () => { } export default App; ``` +::: ### 限制上传数量5个 +:::demo ``` tsx import React, { useState } from "react"; import { Uploader, Button } from '@nutui/nutui-react'; @@ -114,8 +121,11 @@ const App = () => { } export default App; ``` +::: + ### 限制上传大小(每个文件最大不超过 50kb,也可以在beforeupload中自行处理) +:::demo ``` tsx import React, { useState } from "react"; import { Uploader, Button } from '@nutui/nutui-react'; @@ -134,10 +144,12 @@ const App = () => { } export default App; ``` +::: ### 自定义 FormData headers +:::demo ``` tsx import React, { useState } from "react"; import { Uploader, Button } from '@nutui/nutui-react'; @@ -161,9 +173,11 @@ const App = () => { } export default App; ``` +::: ### 手动上传 +:::demo ``` tsx import React, { useState, useRef } from "react"; import { Uploader, Button } from '@nutui/nutui-react'; @@ -187,9 +201,11 @@ const App = () => { } export default App; ``` +::: ### 禁用状态 +:::demo ``` tsx import React, { useState } from "react"; import { Uploader, Button } from '@nutui/nutui-react'; @@ -204,6 +220,7 @@ const App = () => { } export default App; ``` +::: ### Prop