diff --git a/src-next/skeleton/README.md b/src-next/skeleton/README.md new file mode 100644 index 000000000..3cf31e308 --- /dev/null +++ b/src-next/skeleton/README.md @@ -0,0 +1,62 @@ +# Skeleton + +### Install + +```js +import Vue from 'vue'; +import { Skeleton } from 'vant'; + +Vue.use(Skeleton); +``` + +## Usage + +### Basic Usage + +```html + +``` + +### Show Avatar + +```html + +``` + +### Show Children + +```html + +
Content
+
+``` + +```js +export default { + data() { + return { + loading: true, + }; + }, + mounted() { + this.loading = false; + }, +}; +``` + +## API + +### Props + +| Attribute | Description | Type | Default | +| --- | --- | --- | --- | +| row | Row count | _number \| string_ | `0` | +| row-width | Row width, can be array | _number \| string \|
(number \| string)[]_ | `100%` | +| title | Whether to show title placeholder | _boolean_ | `false` | +| avatar | Whether to show avatar placeholder | _boolean_ | `false` | +| loading | Whether to show skeleton,pass `false` to show child component | _boolean_ | `true` | +| animate | Whether to enable animation | _boolean_ | `true` | +| round `v2.8.5` | Whether to show round title and row | _boolean_ | `false` | +| title-width | Title width | _number \| string_ | `40%` | +| avatar-size | Size of avatar placeholder | _number \| string_ | `32px` | +| avatar-shape | Shape of avatar placeholder,can be set to `square` | _string_ | `round` | diff --git a/src-next/skeleton/README.zh-CN.md b/src-next/skeleton/README.zh-CN.md new file mode 100644 index 000000000..fc69a07ee --- /dev/null +++ b/src-next/skeleton/README.zh-CN.md @@ -0,0 +1,68 @@ +# Skeleton 骨架屏 + +### 引入 + +```js +import Vue from 'vue'; +import { Skeleton } from 'vant'; + +Vue.use(Skeleton); +``` + +## 代码演示 + +### 基础用法 + +通过`title`属性显示标题占位图,通过`row`属性配置占位段落行数 + +```html + +``` + +### 显示头像 + +通过`avatar`属性显示头像占位图 + +```html + +``` + +### 展示子组件 + +将`loading`属性设置成`false`表示内容加载完成,此时会隐藏占位图,并显示`Skeleton`的子组件 + +```html + +
实际内容
+
+``` + +```js +export default { + data() { + return { + loading: true, + }; + }, + mounted() { + this.loading = false; + }, +}; +``` + +## API + +### Props + +| 参数 | 说明 | 类型 | 默认值 | +| --- | --- | --- | --- | +| row | 段落占位图行数 | _number \| string_ | `0` | +| row-width | 段落占位图宽度,可传数组来设置每一行的宽度 | _number \| string \|
(number \| string)[]_ | `100%` | +| title | 是否显示标题占位图 | _boolean_ | `false` | +| avatar | 是否显示头像占位图 | _boolean_ | `false` | +| loading | 是否显示骨架屏,传 `false` 时会展示子组件内容 | _boolean_ | `true` | +| animate | 是否开启动画 | _boolean_ | `true` | +| round `v2.8.5` | 是否将标题和段落显示为圆角风格 | _boolean_ | `false` | +| title-width | 标题占位图宽度 | _number \| string_ | `40%` | +| avatar-size | 头像占位图大小 | _number \| string_ | `32px` | +| avatar-shape | 头像占位图形状,可选值为`square` | _string_ | `round` | diff --git a/src-next/skeleton/demo/index.vue b/src-next/skeleton/demo/index.vue new file mode 100644 index 000000000..9dc9591d7 --- /dev/null +++ b/src-next/skeleton/demo/index.vue @@ -0,0 +1,90 @@ + + + + + diff --git a/src-next/skeleton/index.js b/src-next/skeleton/index.js new file mode 100644 index 000000000..c7b767726 --- /dev/null +++ b/src-next/skeleton/index.js @@ -0,0 +1,110 @@ +import { createNamespace, addUnit } from '../utils'; + +const [createComponent, bem] = createNamespace('skeleton'); +const DEFAULT_ROW_WIDTH = '100%'; +const DEFAULT_LAST_ROW_WIDTH = '60%'; + +export default createComponent({ + props: { + title: Boolean, + round: Boolean, + avatar: Boolean, + row: { + type: [Number, String], + default: 0, + }, + loading: { + type: Boolean, + default: true, + }, + animate: { + type: Boolean, + default: true, + }, + avatarSize: { + type: String, + default: '32px', + }, + avatarShape: { + type: String, + default: 'round', + }, + titleWidth: { + type: [Number, String], + default: '40%', + }, + rowWidth: { + type: [Number, String, Array], + default: DEFAULT_ROW_WIDTH, + }, + }, + + setup(props, { slots }) { + return function () { + if (!props.loading) { + return slots.default && slots.default(); + } + + function Title() { + if (props.title) { + return ( +

+ ); + } + } + + function Rows() { + const Rows = []; + const { rowWidth } = props; + + function getRowWidth(index) { + if (rowWidth === DEFAULT_ROW_WIDTH && index === +props.row - 1) { + return DEFAULT_LAST_ROW_WIDTH; + } + + if (Array.isArray(rowWidth)) { + return rowWidth[index]; + } + + return rowWidth; + } + + for (let i = 0; i < props.row; i++) { + Rows.push( +
+ ); + } + + return Rows; + } + + function Avatar() { + if (props.avatar) { + const size = addUnit(props.avatarSize); + return ( +
+ ); + } + } + + return ( +
+ {Avatar()} +
+ {Title()} + {Rows()} +
+
+ ); + }; + }, +}); diff --git a/src-next/skeleton/index.less b/src-next/skeleton/index.less new file mode 100644 index 000000000..95ab87c47 --- /dev/null +++ b/src-next/skeleton/index.less @@ -0,0 +1,62 @@ +@import '../style/var'; + +.van-skeleton { + display: flex; + padding: 0 @padding-md; + + &__avatar { + flex-shrink: 0; + margin-right: @padding-md; + background-color: @skeleton-avatar-background-color; + + &--round { + border-radius: @border-radius-max; + } + } + + &__content { + width: 100%; + } + + &__avatar + &__content { + padding-top: @padding-xs; + } + + &__row, + &__title { + height: @skeleton-row-height; + background-color: @skeleton-row-background-color; + } + + &__title { + margin: 0; + } + + &__row { + &:not(:first-child) { + margin-top: @skeleton-row-margin-top; + } + } + + &__title + &__row { + margin-top: 20px; + } + + &--animate { + animation: van-skeleton-blink @skeleton-animation-duration ease-in-out + infinite; + } + + &--round { + .van-skeleton__row, + .van-skeleton__title { + border-radius: @border-radius-max; + } + } +} + +@keyframes van-skeleton-blink { + 50% { + opacity: 0.6; + } +} diff --git a/src-next/skeleton/test/__snapshots__/demo.spec.js.snap b/src-next/skeleton/test/__snapshots__/demo.spec.js.snap new file mode 100644 index 000000000..785a20ad3 --- /dev/null +++ b/src-next/skeleton/test/__snapshots__/demo.spec.js.snap @@ -0,0 +1,41 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`renders demo correctly 1`] = ` +
+
+
+
+

+
+
+
+
+
+
+
+
+
+
+

+
+
+
+
+
+
+
+
+
+
+
+
+
+

+
+
+
+
+
+
+
+`; diff --git a/src-next/skeleton/test/__snapshots__/index.spec.js.snap b/src-next/skeleton/test/__snapshots__/index.spec.js.snap new file mode 100644 index 000000000..0ffcccc95 --- /dev/null +++ b/src-next/skeleton/test/__snapshots__/index.spec.js.snap @@ -0,0 +1,38 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`avatar shape 1`] = ` +
+
+
+
+`; + +exports[`disable animate 1`] = ` +
+
+
+
+
+`; + +exports[`render chidren 1`] = `
Content
`; + +exports[`round prop 1`] = ` +
+
+
+

+
+
+`; + +exports[`row-width array 1`] = ` +
+
+
+
+
+
+
+
+`; diff --git a/src-next/skeleton/test/demo.spec.js b/src-next/skeleton/test/demo.spec.js new file mode 100644 index 000000000..5c70922b5 --- /dev/null +++ b/src-next/skeleton/test/demo.spec.js @@ -0,0 +1,4 @@ +import Demo from '../demo'; +import { snapshotDemo } from '../../../test/demo'; + +snapshotDemo(Demo); diff --git a/src-next/skeleton/test/index.spec.js b/src-next/skeleton/test/index.spec.js new file mode 100644 index 000000000..d46140c9d --- /dev/null +++ b/src-next/skeleton/test/index.spec.js @@ -0,0 +1,56 @@ +import { mount } from '../../../test'; +import Skeleton from '..'; + +test('row-width array', () => { + const wrapper = mount(Skeleton, { + propsData: { + row: 4, + rowWidth: ['100%', 30, '5rem'], + }, + }); + expect(wrapper).toMatchSnapshot(); +}); + +test('render chidren', () => { + const wrapper = mount({ + template: ` + +
Content
+
+ `, + components: { Skeleton }, + }); + expect(wrapper).toMatchSnapshot(); +}); + +test('avatar shape', () => { + const wrapper = mount(Skeleton, { + propsData: { + avatar: true, + avatarSize: 20, + avatarShape: 'square', + }, + }); + expect(wrapper).toMatchSnapshot(); +}); + +test('round prop', () => { + const wrapper = mount(Skeleton, { + propsData: { + title: true, + round: true, + avatar: true, + }, + }); + expect(wrapper).toMatchSnapshot(); +}); + +test('disable animate', () => { + const wrapper = mount(Skeleton, { + propsData: { + row: 1, + aniamte: false, + }, + }); + expect(wrapper).toMatchSnapshot(); +}); diff --git a/vant.config.js b/vant.config.js index 71e7cf38f..208884089 100644 --- a/vant.config.js +++ b/vant.config.js @@ -261,10 +261,10 @@ module.exports = { // path: 'progress', // title: 'Progress 进度条', // }, - // { - // path: 'skeleton', - // title: 'Skeleton 骨架屏', - // }, + { + path: 'skeleton', + title: 'Skeleton 骨架屏', + }, // { // path: 'steps', // title: 'Steps 步骤条', @@ -595,10 +595,10 @@ module.exports = { // path: 'progress', // title: 'Progress', // }, - // { - // path: 'skeleton', - // title: 'Skeleton', - // }, + { + path: 'skeleton', + title: 'Skeleton', + }, // { // path: 'steps', // title: 'Steps',