widget-icon-btn.vue 3.59 KB
<template>
  <div class="icon-btn" @click="onClick" :style="btnStyle">
    <i class="iconfont" :class="iconClass" :style="iconStyle"></i>
    <span v-if="text" class="icon-btn-text" :style="textStyle">{{text}}</span>
  </div>
</template>

<script>
  import { pxToRem } from '../../../utils/helpers.js';

  const classMap = {
    fav: {
      default: 'icon-zan',
      selected: 'icon-zan-fill'
    },
    star: {
      default: 'icon-star',
      selected: 'icon-star-fill'
    },
    share: {
      default: 'icon-share'
    },
    msg: {
      default: 'icon-msg'
    }
  };

  const defaultOption = {
    canSelect: true,                  // 是否支持选中
    selected: false,                  // 初始选中状态(不受是否支持选中控制)
    color: '#444',                    // btn字体颜色
    selectedColor: '#444',            // btn选中状态字体颜色(不设置默认与非选中一致)
    iconFontSize: 48,                 // icon字号(单位px)
    textFontSize: 20,                 // text字号(单位px)
    textAlign: 'top',                 // text位置, 默认normal(支持normal, top, bottom)
    textZoom: 0.9,                    // text缩放
    textAutoChange: false,            // text自动增减,只支持number类型(受是否支持选中控制)
    emitName: ''                      // 点击触发事件名称
  };

  export default {
    name: 'WidgetIconBtn',
    props: {
      type: {
        type: String,
        default: 'fav'
      },
      text: String,
      option: {
        type: Object,
        default() {
          return defaultOption;
        }
      }
    },
    data() {
      return {
        btnSelected: false,
        actionClass: ''
      }
    },
    computed: {
      btnStyle() {
        let color = this.option.color || defaultOption.color;

        return `color: ${this.btnSelected ? (this.option.selectedColor || color) : color};`;
      },
      iconClass() {
        if (this.actionClass) {
          return this.actionClass;
        }

        if (!this.iconObj) {
          this._icon = classMap[this.type] || classMap.fav;
        }

        if (this.option.selected) {
          this.btnSelected = true;

          return this._icon.selected || this._icon.default;
        }

        return this._icon.default;
      },
      iconStyle() {
        return `font-size: ${pxToRem(this.option.iconFontSize || defaultOption.iconFontSize)};`;
      },
      textStyle() {
        let style = `font-size: ${pxToRem(this.option.textFontSize || defaultOption.textFontSize)};`;

        if (['top', 'bottom'].indexOf(this.option.textAlign) >= 0) {
          style += ` vertical-align: ${this.option.textAlign};`;
        }

        if (Number(this.option.textZoom) !== NaN) {
          style += `transform: scale(${this.option.textZoom}, ${this.option.textZoom});`
        }

        return style;
      }
    },
    methods: {
      onClick(evt) {
        if (this.option.canSelect) {
          this.btnSelected = !this.btnSelected;

          if (Number(this.text) !== NaN) {
            this.text = Number(this.text) + (this.btnSelected ? 1 : -1);
          }

          if (this._icon.selected) {
            this.actionClass = this.btnSelected ? this._icon.selected : this._icon.default;
          }
        }

        this.option.emitName && this.$emit(this.option.emitName, evt);
      }
    },
  };
</script>

<style type="scss">
  .icon-btn {
    display: inline-block;
    line-height: 1;
    vertical-align: middle;

    > * {
      display: inline-block;
      vertical-align: middle;
    }

    .icon-btn-text {
      line-height: 1.3;
    }
  }
</style>