Browse Source

feat: badge

zhangjunfeng5 5 years ago
parent
commit
475d34bf2f

+ 10 - 0
src/config.json

@@ -388,6 +388,16 @@
       "sort": "0",
       "showDemo": true,
       "author": "ivanwancy"
+    },
+    {
+      "version": "1.0.0",
+      "name": "Badge",
+      "sort": "0",
+      "chnName": "徽标",
+      "desc": "出现在图标或文字右上角的红色圆点、数字或者文字,表示有新内容或者待处理的信息",
+      "type": "component",
+      "showDemo": true,
+      "author": "jeffreyzhang23"
     }
   ]
 }

+ 4 - 1
src/nutui.js

@@ -80,6 +80,8 @@ import Swiper from './packages/swiper/index.js';
 import './packages/swiper/swiper.scss';
 import ImagePreview from './packages/imagepreview/index.js';
 import './packages/imagepreview/imagepreview.scss';
+import Badge from './packages/badge/index.js';
+import './packages/badge/badge.scss';
 
 const packages = {
   Cell,
@@ -122,7 +124,8 @@ const packages = {
   Address: Address,
   Tag,
   Swiper,
-  ImagePreview
+  ImagePreview,
+  Badge,
 };
 
 const components = {};

+ 38 - 0
src/packages/badge/__test__/badge.spec.js

@@ -0,0 +1,38 @@
+import { shallowMount, mount } from '@vue/test-utils'
+import Badge from '../badge.vue';
+import Vue from 'vue';
+
+describe('Badge.vue', () => {
+    const wrapper = shallowMount(Badge, {});
+    it('创建结构', () => {
+        wrapper.setProps({ value: '9'});
+        return Vue.nextTick().then(function () {
+            expect(wrapper.contains('sup')).toBe(true);            
+        })
+    });
+    it('字数设置', () => {
+        wrapper.setProps({ value: '9'});
+        return Vue.nextTick().then(function () {
+            expect(wrapper.find('.nut-badge__content').text()).toBe('9');            
+        })
+    });
+
+    it('最大值设置', () => {
+        wrapper.setProps({ value: 200, max: 99 });
+        return Vue.nextTick().then(function () {
+            expect(wrapper.find('.nut-badge__content').text()).toBe('99+');
+        })
+    });
+    it('文字设置',() => {
+        wrapper.setProps({value: 'new'});
+        return Vue.nextTick().then(function() {
+            expect(wrapper.find('.nut-badge__content').text()).toBe('new');
+        })
+    })
+    it('设置为点操作',() => {
+        wrapper.setProps({value: 'new', isDot: true});
+        return Vue.nextTick().then(function() {
+            expect(wrapper.find('.nut-badge__content').text()).toBe('');
+        })
+    })
+});

+ 39 - 0
src/packages/badge/badge.scss

@@ -0,0 +1,39 @@
+.nut-badge {
+  position: relative;
+  display: inline-block;
+  sup {
+    position: absolute;
+    height: 14px;
+    min-width: 8px;
+    line-height: 14px;
+    padding: 1px 7px;
+    background-color: $primary-color;
+    text-align: center;
+    color: #FFFFFF;
+    font-size: $badge-font-size;
+    border-radius: 9px 9px 9px 0px;
+    z-index: $zindex-mask;
+    font-family: PingFangSC-Regular;
+  }
+  .nut-badge__content {
+    transform: translateY(-50%) translateX(100%);
+  }
+  .is-dot {
+    width: 6px;
+    height: 6px;
+    min-width: 0;
+    padding: 0;
+    border-radius: 50%;
+    background: $primary-color;
+  }
+  .single-val {
+    width: 16px;
+    height: 16px;
+    line-height: 16px;
+    padding: 0;
+    border-radius: 50%;
+  }
+  .max-val {
+    padding: 1px 4px;
+  }
+}

+ 79 - 0
src/packages/badge/badge.vue

@@ -0,0 +1,79 @@
+<template>
+  <div class="nut-badge">
+    <slot></slot>
+    <sup
+      v-show="!hidden && (content || isDot)"
+      v-text="content"
+      class="nut-badge__content"
+      :class="{ 'is-dot': isDot, 'single-val': isSingleVal, 'max-val': isMaxVal }"
+      :style="stl"
+    ></sup>
+  </div>
+</template>
+<script>
+export default {
+  name: 'nut-badge',
+  props: {
+    value: {
+      type: [String, Number]
+    },
+    max: {
+      type: Number,
+      default: 10000
+    },
+    isDot: {
+      type: Boolean,
+      default: false
+    },
+    hidden: {
+      type: Boolean,
+      default: false
+    },
+    top: {
+      type: String,
+      default: '2px'
+    },
+    right: {
+      type: String,
+      default: '-5px'
+    },
+    zIndex: {
+      type: Number,
+      default: 10
+    }
+  },
+  data() {
+    return {
+      stl: {
+        top: this.top,
+        right: this.right,
+        zIndex: this.zIndex
+      }
+    };
+  },
+  computed: {
+    content() {
+      if (this.isDot) return;
+      const value = this.value;
+      const max = this.max;
+      if (typeof value === 'number' && typeof max === 'number') {
+        return max < value ? `${max}+` : value;
+      }
+      return value;
+    },
+    isSingleVal() {
+      if (this.isDot) return false;
+      return this.value.toString().length === 1;
+    },
+    isMaxVal() {
+      if (this.isDot) return false;
+      const value = this.value;
+      const max = this.max;
+      if (typeof value === 'number' && typeof max === 'number') {
+        return max < value;
+      }
+      return false;
+    }
+  }
+};
+</script>

+ 52 - 0
src/packages/badge/demo.vue

@@ -0,0 +1,52 @@
+<template>
+  <div class="container">
+    <h4>无内容样式</h4>
+    <div class="demo-w">
+      <nut-badge :isDot="true" class="item">拜访提醒</nut-badge>
+    </div>
+    <div class="demo-w">
+      <nut-badge :isDot="true" class="item"><div class="demo-svg"></div></nut-badge>
+    </div>
+
+    <h4>数字角标</h4>
+    <div class="demo-w">
+      <nut-badge :value="9" :max="99" class="item">拜访提醒</nut-badge>
+      <nut-badge :value="99" :max="99" class="item">拜访提醒</nut-badge>
+      <nut-badge :value="200" :max="99" class="item">拜访提醒</nut-badge>
+    </div>
+    <div class="demo-w">
+      <nut-badge :value="9" :max="99" class="item"><div class="demo-svg"></div></nut-badge>
+      <nut-badge :value="99" :max="99" class="item"><div class="demo-svg"></div></nut-badge>
+      <nut-badge :value="200" :max="99" class="item"><div class="demo-svg"></div></nut-badge>
+    </div>
+
+  </div>
+</template>
+
+<script>
+export default {
+  data() {
+    return {};
+  },
+  created() {},
+  methods: {}
+};
+</script>
+
+<style lang="scss" scoped>
+.item {
+  margin: 16px 26px 10px 10px;
+}
+.demo-w {
+  margin: 0;
+  background: white;
+}
+.demo-svg {
+  display: inline-block;
+  height: 17px;
+  width: 19px;
+  background-size: 100% 100%;
+  background-image: url('#{$assetsPath}/img/gift.png');
+  background-repeat: no-repeat;
+}
+</style>

+ 143 - 0
src/packages/badge/doc.md

@@ -0,0 +1,143 @@
+# Badge 徽标
+
+出现在图标或文字右上角的红色圆点、数字或者文字,表示有新内容或者待处理的信息。
+
+## 基本用法
+
+```html
+<nut-badge 
+    :value="9" 
+    class="item"
+>
+    <div class="demo-svg"></div>
+</nut-badge>
+
+<nut-badge 
+    :value="9" 
+    class="item"
+>
+    购物车
+</nut-badge>
+
+<nut-badge 
+    :value="9" 
+    class="item"
+>
+    <nut-button>
+        购物车
+    </nut-button>
+</nut-badge>
+```
+
+## Max用法
+
+```html
+<nut-badge 
+    :value="200" 
+    :max="99" 
+    class="item"
+>
+    <div class="demo-svg"></div>
+</nut-badge>
+
+<nut-badge 
+    :value="200" 
+    :max="99" 
+    class="item"
+>
+    购物车
+</nut-badge>
+
+<nut-badge 
+    :value="200" 
+    :max="99" 
+    class="item"
+>
+    <nut-button>
+        购物车
+    </nut-button>
+</nut-badge>
+```
+
+## 文字用法
+
+```html
+<nut-badge 
+    value="new" 
+    class="item"
+>
+    <div class="demo-svg"></div>
+</nut-badge>
+
+<nut-badge 
+    value="new" 
+    class="item"
+>
+    购物车
+</nut-badge>
+
+<nut-badge 
+    value="new" 
+    :max="99" 
+    class="item"
+>
+    <nut-button>
+        购物车
+    </nut-button>
+</nut-badge>
+```
+
+## 小圆点
+
+```html
+<nut-badge 
+    :isDot="true" 
+    class="item"
+>
+    <div class="demo-svg"></div>
+</nut-badge>
+
+<nut-badge 
+    :isDot="true" 
+    class="item"
+>
+    文字内容
+</nut-badge>
+
+<nut-badge 
+    :isDot="true" 
+    :max="99" 
+    class="item"
+>
+    <nut-button>
+        购物车
+    </nut-button>
+</nut-badge>
+```
+
+## 自定义位置
+
+```html
+<nut-badge 
+    :value="200" 
+    top="5px" 
+    right="10px" 
+    class="item"
+>
+    <div class="demo-svg">
+    </div>
+</nut-badge>
+```
+
+
+## Prop
+
+| 字段 | 说明 | 类型 | 默认值
+|----- | ----- | ----- | ----- 
+| value | 显示的内容 | String | -
+| max | value为数值时,最大值 | Number | 10000
+| zIndex | 徽标的z-index值 | Number | 10
+| isDot | 是否为小点 | Boolean | false
+| hidden | 是否隐藏 | Boolean | false
+| top   | 上下偏移量,支持单位设置,可设置为:5px、5rem等 | String | 0
+| left  | 左右偏移量,支持单位设置,可设置为:5px、5rem等 | String | 0

+ 8 - 0
src/packages/badge/index.js

@@ -0,0 +1,8 @@
+import Badge from './badge.vue';
+import './badge.scss';
+
+Badge.install = function(Vue) {
+  Vue.component(Badge.name, Badge);
+};
+
+export default Badge;

+ 3 - 0
src/styles/variable.scss

@@ -132,3 +132,6 @@ $tag-height-big: 24px !default;
 $tag-border-radius: 2px !default;
 $tag-border-radius-circle: 10px !default;
 
+// ---- Badge ----
+$badge-font-size: 11px !default;
+