<template> 
 | 
    <view class="uni-badge--x"> 
 | 
        <slot /> 
 | 
        <text v-if="text" :class="classNames" :style="[positionStyle, customStyle, dotStyle]" 
 | 
            class="uni-badge" @click="onClick()">{{displayValue}}</text> 
 | 
    </view> 
 | 
</template> 
 | 
  
 | 
<script> 
 | 
    /** 
 | 
     * Badge 数字角标 
 | 
     * @description 数字角标一般和其它控件(列表、9宫格等)配合使用,用于进行数量提示,默认为实心灰色背景 
 | 
     * @tutorial https://ext.dcloud.net.cn/plugin?id=21 
 | 
     * @property {String} text 角标内容 
 | 
     * @property {String} size = [normal|small] 角标内容 
 | 
     * @property {String} type = [info|primary|success|warning|error] 颜色类型 
 | 
     *     @value info 灰色 
 | 
     *     @value primary 蓝色 
 | 
     *     @value success 绿色 
 | 
     *     @value warning 黄色 
 | 
     *     @value error 红色 
 | 
     * @property {String} inverted = [true|false] 是否无需背景颜色 
 | 
     * @property {Number} maxNum 展示封顶的数字值,超过 99 显示 99+ 
 | 
     * @property {String} absolute = [rightTop|rightBottom|leftBottom|leftTop] 开启绝对定位, 角标将定位到其包裹的标签的四角上         
 | 
     *     @value rightTop 右上 
 | 
     *     @value rightBottom 右下 
 | 
     *     @value leftTop 左上 
 | 
     *     @value leftBottom 左下 
 | 
     * @property {Array[number]} offset    距定位角中心点的偏移量,只有存在 absolute 属性时有效,例如:[-10, -10] 表示向外偏移 10px,[10, 10] 表示向 absolute 指定的内偏移 10px 
 | 
     * @property {String} isDot = [true|false] 是否显示为一个小点 
 | 
     * @event {Function} click 点击 Badge 触发事件 
 | 
     * @example <uni-badge text="1"></uni-badge> 
 | 
     */ 
 | 
  
 | 
    export default { 
 | 
        name: 'UniBadge', 
 | 
        emits: ['click'], 
 | 
        props: { 
 | 
            type: { 
 | 
                type: String, 
 | 
                default: 'error' 
 | 
            }, 
 | 
            inverted: { 
 | 
                type: Boolean, 
 | 
                default: false 
 | 
            }, 
 | 
            isDot: { 
 | 
                type: Boolean, 
 | 
                default: false 
 | 
            }, 
 | 
            maxNum: { 
 | 
                type: Number, 
 | 
                default: 99 
 | 
            }, 
 | 
            absolute: { 
 | 
                type: String, 
 | 
                default: '' 
 | 
            }, 
 | 
            offset: { 
 | 
                type: Array, 
 | 
                default () { 
 | 
                    return [0, 0] 
 | 
                } 
 | 
            }, 
 | 
            text: { 
 | 
                type: [String, Number], 
 | 
                default: '' 
 | 
            }, 
 | 
            size: { 
 | 
                type: String, 
 | 
                default: 'small' 
 | 
            }, 
 | 
            customStyle: { 
 | 
                type: Object, 
 | 
                default () { 
 | 
                    return {} 
 | 
                } 
 | 
            } 
 | 
        }, 
 | 
        data() { 
 | 
            return {}; 
 | 
        }, 
 | 
        computed: { 
 | 
            width() { 
 | 
                return String(this.text).length * 8 + 12 
 | 
            }, 
 | 
            classNames() { 
 | 
                const { 
 | 
                    inverted, 
 | 
                    type, 
 | 
                    size, 
 | 
                    absolute 
 | 
                } = this 
 | 
                return [ 
 | 
                    inverted ? 'uni-badge--' + type + '-inverted' : '', 
 | 
                    'uni-badge--' + type, 
 | 
                    'uni-badge--' + size, 
 | 
                    absolute ? 'uni-badge--absolute' : '' 
 | 
                ].join(' ') 
 | 
            }, 
 | 
            positionStyle() { 
 | 
                if (!this.absolute) return {} 
 | 
                let w = this.width / 2, 
 | 
                    h = 10 
 | 
                if (this.isDot) { 
 | 
                    w = 5 
 | 
                    h = 5 
 | 
                } 
 | 
                const x = `${- w  + this.offset[0]}px` 
 | 
                const y = `${- h + this.offset[1]}px` 
 | 
  
 | 
                const whiteList = { 
 | 
                    rightTop: { 
 | 
                        right: x, 
 | 
                        top: y 
 | 
                    }, 
 | 
                    rightBottom: { 
 | 
                        right: x, 
 | 
                        bottom: y 
 | 
                    }, 
 | 
                    leftBottom: { 
 | 
                        left: x, 
 | 
                        bottom: y 
 | 
                    }, 
 | 
                    leftTop: { 
 | 
                        left: x, 
 | 
                        top: y 
 | 
                    } 
 | 
                } 
 | 
                const match = whiteList[this.absolute] 
 | 
                return match ? match : whiteList['rightTop'] 
 | 
            }, 
 | 
            dotStyle() { 
 | 
                if (!this.isDot) return {} 
 | 
                return { 
 | 
                    width: '10px', 
 | 
                    minWidth: '0', 
 | 
                    height: '10px', 
 | 
                    padding: '0', 
 | 
                    borderRadius: '10px' 
 | 
                } 
 | 
            }, 
 | 
            displayValue() { 
 | 
                const { 
 | 
                    isDot, 
 | 
                    text, 
 | 
                    maxNum 
 | 
                } = this 
 | 
                return isDot ? '' : (Number(text) > maxNum ? `${maxNum}+` : text) 
 | 
            } 
 | 
        }, 
 | 
        methods: { 
 | 
            onClick() { 
 | 
                this.$emit('click'); 
 | 
            } 
 | 
        } 
 | 
    }; 
 | 
</script> 
 | 
  
 | 
<style lang="scss" > 
 | 
    $uni-primary: #2979ff !default; 
 | 
    $uni-success: #4cd964 !default; 
 | 
    $uni-warning: #f0ad4e !default; 
 | 
    $uni-error: #dd524d !default; 
 | 
    $uni-info: #909399 !default; 
 | 
  
 | 
  
 | 
    $bage-size: 12px; 
 | 
    $bage-small: scale(0.8); 
 | 
  
 | 
    .uni-badge--x { 
 | 
        /* #ifdef APP-NVUE */ 
 | 
        // align-self: flex-start; 
 | 
        /* #endif */ 
 | 
        /* #ifndef APP-NVUE */ 
 | 
        display: inline-block; 
 | 
        /* #endif */ 
 | 
        position: relative; 
 | 
    } 
 | 
  
 | 
    .uni-badge--absolute { 
 | 
        position: absolute; 
 | 
    } 
 | 
  
 | 
    .uni-badge--small { 
 | 
        transform: $bage-small; 
 | 
        transform-origin: center center; 
 | 
    } 
 | 
  
 | 
    .uni-badge { 
 | 
        /* #ifndef APP-NVUE */ 
 | 
        display: flex; 
 | 
        overflow: hidden; 
 | 
        box-sizing: border-box; 
 | 
        /* #endif */ 
 | 
        justify-content: center; 
 | 
        flex-direction: row; 
 | 
        height: 20px; 
 | 
        min-width: 20px; 
 | 
        padding: 0 4px; 
 | 
        line-height: 18px; 
 | 
        color: #fff; 
 | 
        border-radius: 100px; 
 | 
        background-color: $uni-info; 
 | 
        background-color: transparent; 
 | 
        border: 1px solid #fff; 
 | 
        text-align: center; 
 | 
        font-family: 'Helvetica Neue', Helvetica, sans-serif; 
 | 
        font-feature-settings: "tnum"; 
 | 
        font-size: $bage-size; 
 | 
        /* #ifdef H5 */ 
 | 
        z-index: 999; 
 | 
        cursor: pointer; 
 | 
        /* #endif */ 
 | 
  
 | 
        &--info { 
 | 
            color: #fff; 
 | 
            background-color: $uni-info; 
 | 
        } 
 | 
  
 | 
        &--primary { 
 | 
            background-color: $uni-primary; 
 | 
        } 
 | 
  
 | 
        &--success { 
 | 
            background-color: $uni-success; 
 | 
        } 
 | 
  
 | 
        &--warning { 
 | 
            background-color: $uni-warning; 
 | 
        } 
 | 
  
 | 
        &--error { 
 | 
            background-color: $uni-error; 
 | 
        } 
 | 
  
 | 
        &--inverted { 
 | 
            padding: 0 5px 0 0; 
 | 
            color: $uni-info; 
 | 
        } 
 | 
  
 | 
        &--info-inverted { 
 | 
            color: $uni-info; 
 | 
            background-color: transparent; 
 | 
        } 
 | 
  
 | 
        &--primary-inverted { 
 | 
            color: $uni-primary; 
 | 
            background-color: transparent; 
 | 
        } 
 | 
  
 | 
        &--success-inverted { 
 | 
            color: $uni-success; 
 | 
            background-color: transparent; 
 | 
        } 
 | 
  
 | 
        &--warning-inverted { 
 | 
            color: $uni-warning; 
 | 
            background-color: transparent; 
 | 
        } 
 | 
  
 | 
        &--error-inverted { 
 | 
            color: $uni-error; 
 | 
            background-color: transparent; 
 | 
        } 
 | 
  
 | 
    } 
 | 
</style> 
 |