button/button.vue

<template>
    <button class="ion-button"
            :active="active"
            :icon-only="iconOnly"
            :icon-left="iconLeft"
            :icon-right="iconRight"
            :class="[modeClass, styleClass, shapeClass, displayClass, sizeClass, decoratorClass, colorClass,
              {'disable-hover':disableHover},
              {'item-button':isInItemComponent}]"
            @click="$_clickHandler($event)">
        <span class="button-inner"><slot></slot></span>
    </button>
</template>
<style lang="scss" src="./style.scss"></style>
<script type="text/javascript">
  /**
   * @component Button
   * @description
   *
   * ## 其他 / Button按钮组件
   *
   * 基础的按钮组件, 可以设置大小, 形状等, 包括和Icon组件的组合.
   *
   * ### 如何引入
   * ```
   * // 引入
   * import { Button } from 'vimo
   * // 安装
   * Vue.component(Button.name, Button)
   * // 或者
   * export default{
   *   components: {
   *    Button
   *  }
   * }
   * ```
   *
   * @props {String} [color='default'] - 颜色
   * @props {String} [mode='ios'] - 模式
   *
   * @props {Boolean} [small]       - 尺寸
   * @props {Boolean} [default]     - 尺寸
   * @props {Boolean} [large]       - 尺寸
   *
   * @props {Boolean} [active]      - 是否激活(按下时的效果)
   *
   * @props {Boolean} [round]       - round(宽度auto有圆角)
   * @props {Boolean} [full]        - full(宽度100%无圆角)
   * @props {Boolean} [block]       - block(宽度100%有圆角)
   * @props {Boolean} [menutoggle]  - menutoggle类型
   *
   * @props {Boolean} [outline]     - outline只有边框
   * @props {Boolean} [clear]       - clear空心
   * @props {Boolean} [solid]       - solid实心
   *
   * @props {Boolean} [role='button']       - role 按钮具体角色 例如 action-sheet-button/bar-button
   *
   * @props {Boolean} [strong]      - 样式加强
   *
   * @demo #/button
   * @usage
   * <Button full>full</Button>
   * <Button outline full color="secondary">outline + full</Button>
   * <Button color="dark">
   *    <Icon class="icon" name="star"></Icon>
   *    <span>Left Icon</span>
   * </Button>
   * */
  import disableHover from '../../util/disable-hover'

  export default {
    name: 'Button',
    inject: {
      itemComponent: {
        from: 'itemComponent',
        default: null
      }
    },
    props: {
      /**
       * 按钮color:primary、secondary、danger、light、dark
       * */
      color: {
        type: String,
        default () {
          return 'default'
        }
      },
      /**
       * mode 按钮风格 ios/window/android/we/alipay
       * */
      mode: {
        type: String,
        default () { return this.$config && this.$config.get('mode', 'ios') || 'ios' }
      },

      small: Boolean,
      'default': Boolean,
      large: Boolean,

      /**
       * 激活模式, 按下时的效果
       * */
      active: Boolean,

      /**
       * 形状:round(宽度auto有圆角)
       * round/fab
       * */
      round: Boolean,

      /**
       * 形状:full(宽度100%无圆角)/block(宽度100%有圆角)/menutoggle
       * */
      full: Boolean,
      block: Boolean,
      menutoggle: Boolean,

      /**
       * 按钮类型: solid实心/outline只有边框/clear空心
       * */
      outline: Boolean,
      clear: Boolean,
      solid: Boolean,

      /**
       * role 按钮具体角色 例如 action-sheet-button/bar-button
       * */
      role: {
        type: String,
        default () {
          return 'button'
        }
      },

      /**
       * 样式加强
       * */
      strong: Boolean
    },
    data () {
      return {
        disableHover: disableHover,

        style: 'default',        // outline/clear/solid
        shape: null,        // round/fab
        display: null,      // block/full
        size: null,         // large/small/default
        decorator: null,     // strong

        styleClass: null,
        shapeClass: null,
        displayClass: null,
        sizeClass: null,
        decoratorClass: null,
        colorClass: null,

        iconOnly: false,
        iconLeft: false,
        iconRight: false

      }
    },
    computed: {
      // 环境样式
      modeClass () {
        return this.mode ? (`${this.role} ${this.role}-${this.mode}`) : this.role
      },
      isInItemComponent () {
        return !!this.itemComponent
      }
    },
    methods: {
      /**
       * @private
       * @param {Object} $event - $event
       */
      $_clickHandler ($event) {
        this.$emit('click', $event)
      },

      /**
       * @private
       */
      $_assignCss () {
        let role = this.role
        if (role) {
          this.styleClass = this.$_setClass(this.style) // button-clear
          this.shapeClass = this.$_setClass(this.shape) // button-round
          this.displayClass = this.$_setClass(this.display) // button-full
          this.sizeClass = this.$_setClass(this.size) // button-small
          this.decoratorClass = this.$_setClass(this.decorator) // button-strong
        }
        this.colorClass = this.$_setColor(this.color) // button-secondary, bar-button-secondary
      },

      /**
       * @param {String} type
       * @private
       */
      $_setClass (type) {
        if (type) {
          type = type.toLocaleLowerCase()
          return `${this.role}-${type} ${this.role}-${type}-${this.mode}`
        }
      },

      /**
       * @param {String} color
       * @private
       */
      $_setColor (color) {
        if (color) {
          // The class should begin with the button role
          // button, bar-button
          let className = this.role

          // If the role is not a bar-button, don't apply the solid style
          let style = this.style
          style = (this.role !== 'bar-button' && style === 'solid' ? 'default' : style)

          className += (style !== null && style !== '' && style !== 'default' ? '-' + style.toLowerCase() : '')

          if (color !== null && color !== '') {
            return `${className}-${this.mode}-${color}`
          }
        }

        return ''
      },

      /**
       * 设置icon button的左右位置
       * @private
       */
      $_addIconBtnPosition () {
        let firstSlot = null
        let lastSlot = null
        let length = this.$_getSlotLength(this.$slots)
        if (length > 0) {
          firstSlot = this.$slots.default[0]
          lastSlot = this.$slots.default[length - 1]
          if (length === 1 && this.$_isIconComponent(firstSlot)) {
            this.iconOnly = 'icon-only'
          }

          if (length > 1) {
            if (this.$_isIconComponent(firstSlot)) {
              this.iconLeft = 'icon-left'
            }
            if (this.$_isIconComponent(lastSlot)) {
              this.iconRight = 'icon-right'
            }
          }
        }
      },

      /**
       * 判断slot是icon组件
       * @private
       * */
      $_isIconComponent (slot) {
        return !!slot.componentOptions && !!slot.componentOptions.tag && slot.componentOptions.tag.toLowerCase() === 'icon'
      },

      /**
       * 获取slot的数量
       * @private
       * */
      $_getSlotLength (slots) {
        return (slots && slots.default) ? slots.default.length : 0
      },

      /**
       * @private
       * */
      $_classify () {
        if (this.small) this.size = 'small'
        if (this.default) this.size = 'default'
        if (this.large) this.size = 'large'

        if (this.outline) this.style = 'outline'
        if (this.clear) this.style = 'clear'
        if (this.solid) this.style = 'solid'

        if (this.round) this.shape = 'round'

        if (this.full) this.display = 'full'
        if (this.block) this.display = 'block'
        if (this.menutoggle) this.display = 'menutoggle'

        if (this.strong) this.decorator = 'strong'
      }
    },
    created () {
      this.$_classify()
      this.$_assignCss()
      this.$_addIconBtnPosition()
    }
  }

</script>