diff --git a/src/action-bar-icon/index.less b/src/action-bar-icon/index.less index 0cb001cc6..9ad5b129b 100644 --- a/src/action-bar-icon/index.less +++ b/src/action-bar-icon/index.less @@ -18,7 +18,6 @@ } &__icon { - position: relative; width: 1em; margin: 0 auto 5px; color: @action-bar-icon-color; diff --git a/src/action-bar-icon/index.tsx b/src/action-bar-icon/index.tsx index 8dc03cc94..7fb8f25c4 100644 --- a/src/action-bar-icon/index.tsx +++ b/src/action-bar-icon/index.tsx @@ -32,10 +32,9 @@ export default createComponent({ if (slots.icon) { return ( -
+ {slots.icon()} - -
+ ); } diff --git a/src/badge/README.md b/src/badge/README.md new file mode 100644 index 000000000..fb30c4663 --- /dev/null +++ b/src/badge/README.md @@ -0,0 +1,78 @@ +# Badge + +### Install + +```js +import { createApp } from 'vue'; +import { Badge } from 'vant'; + +const app = createApp(); +app.use(Badge); +``` + +## Usage + +### Basic Usage + +```html + +
+ + +
+ + + +``` + +### Max + +```html + +
+ + +
+ +``` + +### Custom Color + +```html + +
+ + +
+ +``` + +### Standaline + +```html + +``` + +## API + +### Props + +| Attribute | Description | Type | Default | +| --- | --- | --- | --- | +| content | Badge content | _string \| number_ | - | +| color | Background color | _string_ | `#ee0a24` | +| dot | Whether to show dot | _boolean_ | `false` | +| max | Max value,show `{max}+` when exceed,only works when content is number type | _number_ | - | + +### Slots + +| Name | Description | +| ------- | ------------ | +| default | Default slot | diff --git a/src/badge/README.zh-CN.md b/src/badge/README.zh-CN.md new file mode 100644 index 000000000..b76626f25 --- /dev/null +++ b/src/badge/README.zh-CN.md @@ -0,0 +1,91 @@ +# Badge 徽标 + +### 介绍 + +在右上角展示徽标数字或小红点。 + +### 引入 + +```js +import { createApp } from 'vue'; +import { Badge } from 'vant'; + +const app = createApp(); +app.use(Badge); +``` + +## 代码演示 + +### 基础用法 + +设置 `content` 属性后,Badge 会在子元素的右上角显示对应的徽标,也可以通过 `dot` 来显示小红点。 + +```html + +
+ + +
+ + + +``` + +### 最大值 + +设置 `max` 属性后,当 `content` 的数值超过最大值时,会自动显示为 `{max}+`。 + +```html + +
+ + +
+ +``` + +### 自定义颜色 + +通过 `color` 属性来设置徽标的颜色。 + +```html + +
+ + +
+ +``` + +### 独立展示 + +当 Badge 没有子元素时,会作为一个独立的元素进行展示。 + +```html + +``` + +## API + +### Props + +| 参数 | 说明 | 类型 | 默认值 | +| --- | --- | --- | --- | +| content | 徽标内容 | _string \| number_ | - | +| color | 徽标背景颜色 | _string_ | `#ee0a24` | +| dot | 是否展示为小红点 | _boolean_ | `false` | +| max | 最大值,超过最大值会显示 `{max}+`,仅当 content 为 number 类型时有效 | _number_ | - | + +### Slots + +| 名称 | 说明 | +| ------- | ---------------- | +| default | 徽标包裹的子元素 | +| content | 自定义徽标内容 | diff --git a/src/badge/demo/index.vue b/src/badge/demo/index.vue new file mode 100644 index 000000000..a40843cf3 --- /dev/null +++ b/src/badge/demo/index.vue @@ -0,0 +1,78 @@ + + + + + diff --git a/src/badge/index.less b/src/badge/index.less index 31fb14856..6bbd1c791 100644 --- a/src/badge/index.less +++ b/src/badge/index.less @@ -1,9 +1,7 @@ @import '../style/var'; .van-badge { - position: absolute; - top: 0; - right: 0; + display: inline-block; box-sizing: border-box; min-width: @badge-size; padding: @badge-padding; @@ -15,9 +13,15 @@ text-align: center; background-color: @badge-background-color; border: @badge-border-width solid @white; - border-radius: @badge-size; - transform: translate(50%, -50%); - transform-origin: 100%; + border-radius: @border-radius-max; + + &--fixed { + position: absolute; + top: 0; + right: 0; + transform: translate(50%, -50%); + transform-origin: 100%; + } &--dot { width: @badge-dot-size; @@ -26,4 +30,9 @@ background-color: @badge-dot-color; border-radius: 100%; } + + &__wrapper { + position: relative; + display: inline-block; + } } diff --git a/src/badge/index.tsx b/src/badge/index.tsx index bea6bbeaf..48d688d33 100644 --- a/src/badge/index.tsx +++ b/src/badge/index.tsx @@ -1,21 +1,65 @@ +import type { PropType } from 'vue'; import { isDef, createNamespace } from '../utils'; const [createComponent, bem] = createNamespace('badge'); export default createComponent({ props: { + max: Number, dot: Boolean, - badge: [Number, String], + color: String, + content: [Number, String], + tag: { + type: String as PropType, + default: 'div', + }, }, - setup(props) { - return () => { - const { dot, badge } = props; - const hasBadge = isDef(badge) && badge !== ''; + setup(props, { slots }) { + const hasContent = () => + !!(slots.default || (isDef(props.content) && props.content !== '')); - if (dot || hasBadge) { - return
{dot ? '' : badge}
; + const renderContent = () => { + const { dot, max, content } = props; + + if (!dot && hasContent()) { + if (slots.content) { + return slots.content(); + } + + if (isDef(max) && typeof content === 'number' && content > max) { + return `${max}+`; + } + + return content; } }; + + const renderBadge = () => { + if (hasContent() || props.dot) { + return ( +
+ {renderContent()} +
+ ); + } + }; + + return () => { + if (slots.default) { + const { tag } = props; + return ( + + {slots.default()} + {renderBadge()} + + ); + } + + return renderBadge(); + }; }, }); diff --git a/src/grid-item/index.js b/src/grid-item/index.js index 4ff882c63..b6d6512a0 100644 --- a/src/grid-item/index.js +++ b/src/grid-item/index.js @@ -66,10 +66,9 @@ export default createComponent({ const renderIcon = () => { if (slots.icon) { return ( -
+ {slots.icon()} - -
+ ); } diff --git a/src/grid-item/index.less b/src/grid-item/index.less index 63d2f951c..deaf52c78 100644 --- a/src/grid-item/index.less +++ b/src/grid-item/index.less @@ -12,10 +12,6 @@ font-size: @grid-item-icon-size; } - &__icon-wrapper { - position: relative; - } - &__text { color: @grid-item-text-color; font-size: @grid-item-text-font-size; diff --git a/src/icon/index.tsx b/src/icon/index.tsx index d7b920172..82849f5bb 100644 --- a/src/icon/index.tsx +++ b/src/icon/index.tsx @@ -31,7 +31,10 @@ export default createComponent({ const isImageIcon = isImage(name); return ( - {slots.default?.()} {isImageIcon && } - - + ); }; }, diff --git a/src/sidebar-item/index.js b/src/sidebar-item/index.js index de033c5f6..e632277ff 100644 --- a/src/sidebar-item/index.js +++ b/src/sidebar-item/index.js @@ -38,10 +38,9 @@ export default createComponent({ return ( -
+ {slots.title ? slots.title() : title} - -
+
); }; diff --git a/src/sidebar-item/index.less b/src/sidebar-item/index.less index 49b6cd2d9..39d075c6c 100644 --- a/src/sidebar-item/index.less +++ b/src/sidebar-item/index.less @@ -18,11 +18,6 @@ background-color: @sidebar-active-color; } - &__text { - position: relative; - display: inline-block; - } - &:not(:last-child)::after { border-bottom-width: 1px; } diff --git a/src/tabbar-item/index.js b/src/tabbar-item/index.js index 6d8331996..cfc064997 100644 --- a/src/tabbar-item/index.js +++ b/src/tabbar-item/index.js @@ -73,10 +73,9 @@ export default createComponent({ style={{ color }} onClick={onClick} > -
+ {renderIcon()} - -
+
{slots.default?.({ active: active.value })}
diff --git a/src/tabbar-item/index.less b/src/tabbar-item/index.less index 030c11575..545fce804 100644 --- a/src/tabbar-item/index.less +++ b/src/tabbar-item/index.less @@ -12,7 +12,6 @@ cursor: pointer; &__icon { - position: relative; margin-bottom: @tabbar-item-margin-bottom; font-size: @tabbar-item-icon-size; diff --git a/src/tabs/TabsTitle.tsx b/src/tabs/TabsTitle.tsx index e89b6fed8..2ac2a2f30 100644 --- a/src/tabs/TabsTitle.tsx +++ b/src/tabs/TabsTitle.tsx @@ -63,10 +63,9 @@ export default createComponent({ if (props.dot || (isDef(props.badge) && props.badge !== '')) { return ( - + {Text} - {} - + ); } diff --git a/src/tabs/index.less b/src/tabs/index.less index b4e1a54c0..768db451c 100644 --- a/src/tabs/index.less +++ b/src/tabs/index.less @@ -31,10 +31,6 @@ -webkit-box-orient: vertical; } } - - &__text-wrapper { - position: relative; - } } .van-tabs { diff --git a/vant.config.js b/vant.config.js index bcfb06ccd..b6914beb7 100644 --- a/vant.config.js +++ b/vant.config.js @@ -240,6 +240,10 @@ module.exports = { { title: '展示组件', items: [ + { + path: 'badge', + title: 'Badge 徽标', + }, { path: 'circle', title: 'Circle 环形进度条', @@ -570,6 +574,10 @@ module.exports = { { title: 'Display Components', items: [ + { + path: 'badge', + title: 'Badge', + }, { path: 'circle', title: 'Circle',