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',