diff --git a/packages/vant/src/skeleton/Avatar.tsx b/packages/vant/src/skeleton/Avatar.tsx new file mode 100644 index 000000000..3c489d017 --- /dev/null +++ b/packages/vant/src/skeleton/Avatar.tsx @@ -0,0 +1,35 @@ +import { defineComponent, ExtractPropTypes } from 'vue'; + +// Utils +import { + numericProp, + getSizeStyle, + makeStringProp, + createNamespace, +} from '../utils'; + +const [name, bem] = createNamespace('skeleton-avatar'); + +export type SkeletonAvatarShape = 'square' | 'round'; + +export const skeletonAvatarProps = { + avatarSize: numericProp, + avatarShape: makeStringProp('round'), +}; + +export type SkeletonAvatarProps = ExtractPropTypes; + +export default defineComponent({ + name, + + props: skeletonAvatarProps, + + setup(props) { + return () => ( +
+ ); + }, +}); diff --git a/packages/vant/src/skeleton/Image.tsx b/packages/vant/src/skeleton/Image.tsx new file mode 100644 index 000000000..237159dfb --- /dev/null +++ b/packages/vant/src/skeleton/Image.tsx @@ -0,0 +1,38 @@ +import { defineComponent, type ExtractPropTypes } from 'vue'; + +import { + numericProp, + getSizeStyle, + makeStringProp, + createNamespace, +} from '../utils'; + +import { Icon } from '../icon'; + +const [name, bem] = createNamespace('skeleton-image'); + +export type SkeletonImageShape = 'square' | 'round'; + +export const skeletonImageProps = { + imageSize: numericProp, + imageShape: makeStringProp('square'), +}; + +export type SkeletonImageProps = ExtractPropTypes; + +export default defineComponent({ + name, + + props: skeletonImageProps, + + setup(props) { + return () => ( +
+ +
+ ); + }, +}); diff --git a/packages/vant/src/skeleton/Paragraph.tsx b/packages/vant/src/skeleton/Paragraph.tsx new file mode 100644 index 000000000..5201310eb --- /dev/null +++ b/packages/vant/src/skeleton/Paragraph.tsx @@ -0,0 +1,34 @@ +import { defineComponent, ExtractPropTypes } from 'vue'; + +import { createNamespace, numericProp } from '../utils'; + +export const DEFAULT_ROW_WIDTH = '100%'; + +export const skeletonParagraphProps = { + round: Boolean, + rowWidth: { + type: numericProp, + default: DEFAULT_ROW_WIDTH, + }, +}; + +export type SkeletonParagraphProps = ExtractPropTypes< + typeof skeletonParagraphProps +>; + +const [name, bem] = createNamespace('skeleton-paragraph'); + +export default defineComponent({ + name, + + props: skeletonParagraphProps, + + setup(props) { + return () => ( +
+ ); + }, +}); diff --git a/packages/vant/src/skeleton/README.md b/packages/vant/src/skeleton/README.md index 0a9018194..921f07a15 100644 --- a/packages/vant/src/skeleton/README.md +++ b/packages/vant/src/skeleton/README.md @@ -10,10 +10,20 @@ Register component globally via `app.use`, refer to [Component Registration](#/e ```js import { createApp } from 'vue'; -import { Skeleton } from 'vant'; +import { + Skeleton, + VanSkeletonTitle, + VanSkeletonImage, + VanSkeletonAvatar, + VanSkeletonParagraph, +} from 'vant'; const app = createApp(); app.use(Skeleton); +app.use(VanSkeletonTitle); +app.use(VanSkeletonImage); +app.use(VanSkeletonAvatar); +app.use(VanSkeletonParagraph); ``` ## Usage @@ -56,9 +66,29 @@ export default { }; ``` +### Custom Content + +Using `template` slots to display custom content. + +```html + + + +``` + ## API -### Props +### Skeleton Props | Attribute | Description | Type | Default | | --- | --- | --- | --- | @@ -68,17 +98,58 @@ export default { | 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 | Whether to show round title and row | _boolean_ | `false` | +| round | Whether to show round title and paragraph | _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` | +### SkeletonParagraph Props + +| Attribute | Description | Type | Default | +| --------- | ------------------------------- | --------- | ------- | +| round | Whether to show round paragraph | _boolean_ | `false` | +| row-width | Paragraph width | _string_ | `100%` | + +### SkeletonTitle Props + +| Attribute | Description | Type | Default | +| ----------- | --------------------------- | ------------------ | ------- | +| round | Whether to show round title | _boolean_ | `false` | +| title-width | Title width | _number \| string_ | `40%` | + +### SkeletonAvatar Props + +| Attribute | Description | Type | Default | +| --- | --- | --- | --- | +| avatar-size | Size of avatar placeholder | _number \| string_ | `32px` | +| avatar-shape | Shape of avatar placeholder, can be set to `square` | _string_ | `round` | + +### SkeletonImage Props + +| Attribute | Description | Type | Default | +| --- | --- | --- | --- | +| image-size | Size of image placeholder | _number \| string_ | `32px` | +| image-shape | Shape of image placeholder, can be set to `square` | _string_ | `round` | + +### Skeleton Slots + +| Name | Description | +| -------- | -------------- | +| default | Default slot | +| template | Custom content | + ### Types The component exports the following type definitions: ```ts -import type { SkeletonProps, SkeletonAvatarShape } from 'vant'; +import type { + SkeletonProps, + SkeletonImageProps, + SkeletonTitleProps, + SkeletonAvatarShape, + SkeletonParagraphProps, +} from 'vant'; ``` ## Theming @@ -96,3 +167,5 @@ The component provides the following CSS variables, which can be used to customi | --van-skeleton-avatar-size | _32px_ | - | | --van-skeleton-avatar-background | _var(--van-active-color)_ | - | | --van-skeleton-duration | _1.2s_ | - | +| --van-skeleton-image-size | _96px_ | +| --van-skeleton-image-radius | _24px_ | - | diff --git a/packages/vant/src/skeleton/README.zh-CN.md b/packages/vant/src/skeleton/README.zh-CN.md index 4d0552dfa..d243e3726 100644 --- a/packages/vant/src/skeleton/README.zh-CN.md +++ b/packages/vant/src/skeleton/README.zh-CN.md @@ -10,10 +10,20 @@ ```js import { createApp } from 'vue'; -import { Skeleton } from 'vant'; +import { + Skeleton, + VanSkeletonTitle, + VanSkeletonImage, + VanSkeletonAvatar, + VanSkeletonParagraph, +} from 'vant'; const app = createApp(); app.use(Skeleton); +app.use(VanSkeletonTitle); +app.use(VanSkeletonImage); +app.use(VanSkeletonAvatar); +app.use(VanSkeletonParagraph); ``` ## 代码演示 @@ -62,9 +72,29 @@ export default { }; ``` +### 自定义展示内容 + +通过 `template` 插槽完成自定义内容的展示。 + +```html + + + +``` + ## API -### Props +### Skeleton Props | 参数 | 说明 | 类型 | 默认值 | | --- | --- | --- | --- | @@ -79,12 +109,53 @@ export default { | avatar-size | 头像占位图大小 | _number \| string_ | `32px` | | avatar-shape | 头像占位图形状,可选值为 `square` | _string_ | `round` | +### SkeletonParagraph Props + +| 参数 | 说明 | 类型 | 默认值 | +| --------- | ------------------------ | --------- | ------- | +| round | 是否将段落显示为圆角风格 | _boolean_ | `false` | +| row-width | 段落占位图宽度 | _string_ | `100%` | + +### SkeletonTitle Props + +| 参数 | 说明 | 类型 | 默认值 | +| ----------- | ------------------------ | ------------------ | ------- | +| round | 是否将标题显示为圆角风格 | _boolean_ | `false` | +| title-width | 标题占位图宽度 | _number \| string_ | `40%` | + +### SkeletonAvatar Props + +| 参数 | 说明 | 类型 | 默认值 | +| --- | --- | --- | --- | +| avatar-size | 头像占位图大小 | _number \| string_ | `32px` | +| avatar-shape | 头像占位图形状,可选值为 `square` | _string_ | `round` | + +### SkeletonImage Props + +| 参数 | 说明 | 类型 | 默认值 | +| --- | --- | --- | --- | +| image-size | 图片占位图大小 | _number \| string_ | `32px` | +| image-shape | 图片占位图形状,可选值为 `square` | _string_ | `round` | + +### Skeleton Slots + +| 名称 | 说明 | +| -------- | ---------- | +| default | 骨架屏内容 | +| template | 自定义内容 | + ### 类型定义 组件导出以下类型定义: ```ts -import type { SkeletonProps, SkeletonAvatarShape } from 'vant'; +import type { + SkeletonProps, + SkeletonImageProps, + SkeletonTitleProps, + SkeletonAvatarShape, + SkeletonParagraphProps, +} from 'vant'; ``` ## 主题定制 @@ -93,12 +164,14 @@ import type { SkeletonProps, SkeletonAvatarShape } from 'vant'; 组件提供了下列 CSS 变量,可用于自定义样式,使用方法请参考 [ConfigProvider 组件](#/zh-CN/config-provider)。 -| 名称 | 默认值 | 描述 | -| -------------------------------- | ------------------------- | ---- | -| --van-skeleton-row-height | _16px_ | - | -| --van-skeleton-row-background | _var(--van-active-color)_ | - | -| --van-skeleton-row-margin-top | _var(--van-padding-sm)_ | - | -| --van-skeleton-title-width | _40%_ | - | -| --van-skeleton-avatar-size | _32px_ | - | -| --van-skeleton-avatar-background | _var(--van-active-color)_ | - | -| --van-skeleton-duration | _1.2s_ | - | +| 名称 | 默认值 | 描述 | +| ----------------------------------- | ------------------------- | ---- | +| --van-skeleton-paragraph-height | _16px_ | - | +| --van-skeleton-paragraph-background | _var(--van-active-color)_ | - | +| --van-skeleton-paragraph-margin-top | _var(--van-padding-sm)_ | - | +| --van-skeleton-title-width | _40%_ | - | +| --van-skeleton-avatar-size | _32px_ | - | +| --van-skeleton-avatar-background | _var(--van-active-color)_ | - | +| --van-skeleton-duration | _1.2s_ | - | +| --van-skeleton-image-size | _96px_ | +| --van-skeleton-image-radius | _24px_ | - | diff --git a/packages/vant/src/skeleton/Skeleton.tsx b/packages/vant/src/skeleton/Skeleton.tsx index 84e2a2ecf..55368c00b 100644 --- a/packages/vant/src/skeleton/Skeleton.tsx +++ b/packages/vant/src/skeleton/Skeleton.tsx @@ -1,31 +1,34 @@ import { defineComponent, type PropType, type ExtractPropTypes } from 'vue'; + +// Utils import { addUnit, truthProp, numericProp, - getSizeStyle, makeStringProp, makeNumericProp, createNamespace, type Numeric, } from '../utils'; -const [name, bem] = createNamespace('skeleton'); -const DEFAULT_ROW_WIDTH = '100%'; -const DEFAULT_LAST_ROW_WIDTH = '60%'; +// Components +import SkeletonTitle from './Title'; +import SkeletonAvatar, { type SkeletonAvatarShape } from './Avatar'; +import SkeletonParagraph, { DEFAULT_ROW_WIDTH } from './Paragraph'; -export type SkeletonAvatarShape = 'square' | 'round'; +const [name, bem] = createNamespace('skeleton'); +const DEFAULT_LAST_ROW_WIDTH = '60%'; export const skeletonProps = { row: makeNumericProp(0), - title: Boolean, round: Boolean, + title: Boolean, + titleWidth: numericProp, avatar: Boolean, + avatarSize: numericProp, + avatarShape: makeStringProp('round'), loading: truthProp, animate: truthProp, - avatarSize: numericProp, - titleWidth: numericProp, - avatarShape: makeStringProp('round'), rowWidth: { type: [Number, String, Array] as PropType, default: DEFAULT_ROW_WIDTH, @@ -45,9 +48,9 @@ export default defineComponent({ const renderAvatar = () => { if (props.avatar) { return ( -
); } @@ -56,10 +59,7 @@ export default defineComponent({ const renderTitle = () => { if (props.title) { return ( -

+ ); } }; @@ -82,9 +82,29 @@ export default defineComponent({ Array(+props.row) .fill('') .map((_, i) => ( -
+ )); + const renderContents = () => { + if (slots.template) { + return slots.template(); + } + + return ( + <> + {renderAvatar()} +
+ {renderTitle()} + {renderRows()} +
+ + ); + }; + return () => { if (!props.loading) { return slots.default?.(); @@ -95,11 +115,7 @@ export default defineComponent({ class={bem({ animate: props.animate, round: props.round })} {...attrs} > - {renderAvatar()} -
- {renderTitle()} - {renderRows()} -
+ {renderContents()}
); }; diff --git a/packages/vant/src/skeleton/Title.tsx b/packages/vant/src/skeleton/Title.tsx new file mode 100644 index 000000000..1a20a279a --- /dev/null +++ b/packages/vant/src/skeleton/Title.tsx @@ -0,0 +1,27 @@ +import { defineComponent, type ExtractPropTypes } from 'vue'; + +import { createNamespace, numericProp, addUnit } from '../utils'; + +const [name, bem] = createNamespace('skeleton-title'); + +export const skeletonTitleProps = { + round: Boolean, + titleWidth: numericProp, +}; + +export type SkeletonTitleProps = ExtractPropTypes; + +export default defineComponent({ + name, + + props: skeletonTitleProps, + + setup(props) { + return () => ( +

+ ); + }, +}); diff --git a/packages/vant/src/skeleton/demo/index.vue b/packages/vant/src/skeleton/demo/index.vue index 3c4ed9a6c..5b9643c7e 100644 --- a/packages/vant/src/skeleton/demo/index.vue +++ b/packages/vant/src/skeleton/demo/index.vue @@ -1,5 +1,5 @@