vue组件 - 多级互斥按钮的实现

多级互斥按钮的实现

本案例自定义了一个按钮组件, 按钮主要提供了多级点击效果, 按钮组间的按钮是互斥关系.

实现功能:

  1. 按钮互斥效果, 只有一个按钮处于激活状态
  2. 当功能按钮处于未选中时, 默认选中按钮(default-checked)处于激活状态
  3. 按钮可以设置多级点击, 并派发出 1, 2, 3...
  4. 可以设置快捷键,本例为 ESC, f1...
  5. 本文的按钮样式也可参考, 渐变圆角边框以及斜切实现

按钮组件采用 typescript 编写

按钮组件

<template>
  <div class="grade-button-component" :class="{'active-class': curGrade !== 0}" :style="{width,height}" @click="onClick">
    <div class="content">
      <div class="text">
        <slot>按钮</slot>
        <span>
          &nbsp;{{ shortcut.toUpperCase() }}
        </span>
      </div>
      <div v-if="gradeNum > 1" class="grade">
        <div v-for="n in gradeNum" :key="n" :style="{background: curGrade >= n ? backGroundArr[(n-1)%backGroundArr.length]: null}" class="grade-item" />
      </div>
    </div>

  </div>
</template>
<script lang="ts">
import { Vue, Component, Prop } from 'vue-property-decorator'
/* eslint-disable*/ 
enum KeyMap {
  esc = 27,
  f1 = 112,
  f2 = 113,
  f3 = 114,
  f4 = 115,
  f5 = 116,
  f6 = 117,
  f7 = 118,
  f8 = 119,
  f9 = 120,
}
/* eslint-enable */
@Component
export default class GradeButtonComponent extends Vue {
  @Prop({ default: '120px' }) readonly width: string
  @Prop({ default: '40px' }) readonly height: string
  @Prop({ default: 1 }) readonly gradeNum: number
  @Prop() readonly shortcut:string
  private backGroundArr = ['#f3aa35', '#ff5507', '#e62242']
  private curGrade = 0
  onClick() {
    this.curGrade++
    if (this.curGrade > this.gradeNum) this.curGrade = 0
    this.$emit('clickEvent', this.curGrade)
    this.$parent.$children.forEach(cur => {
      if (cur instanceof GradeButtonComponent) { // instanceof 类型保护
        cur !== this && cur.reset()
        if (this.curGrade === 0 && 'default-checked' in cur.$attrs) cur.curGrade = 1
      }
    })
  }
  reset() {
    this.curGrade = 0
  }
  keyUpHandle(e) {
    if (KeyMap[e.keyCode] === this.shortcut) {
      e.preventDefault()
      this.onClick()
      return false
    }
  }
  created() {
    if ('default-checked' in this.$attrs) this.curGrade = 1
  }
  mounted() {
    document.addEventListener('keydown', this.keyUpHandle, true)
  }
  beforeDestroy() {
    document.removeEventListener('keydown', this.keyUpHandle)
  }
}

</script>
<style lang="scss">
.grade-button-component {
  display: flex;
  align-items: center;
  justify-content: center;
  // border: 2px solid #DCDFE6;
  background: linear-gradient(to right, #0d90c3, #0358ad);
  border-radius: 5px;
  overflow: hidden;
  cursor: pointer;
  transform: skew(-20deg);
  .content {
    display: flex;
    width: calc(100% - 4px);
    height: calc(100% - 4px);
    background: #0E1829;
    border-radius: 8px;
    box-shadow: 0 0 25px rgba(7,117,188,0.8) inset;
    // overflow: hidden;
    .text {
      transform: skew(20deg);
      width: 100%;
      height: 100%;
      display: flex;
      justify-content: center;
      align-items: center;
      color: #ffffff;
      font-size: 14px;
      letter-spacing: 1px;
      text-align: center;
      span {
        color: #28e3ff;
        letter-spacing: 0;
      }
    }
    .grade {
      width: 8%;
      height: 100%;
      display: flex;
      flex-direction: column-reverse;
      &-item {
        height: 100%;
        border-left: 1px solid #0d92cb;
        border-top: 1px solid #0d92cb;
        &:first-of-type() {
          border-bottom: none
        }
        &:last-of-type {
          border-top: none
        }
      }
    }
  }
}

.active-class {
  // border: 1px solid rgb(37, 64, 132);
  // background: rgba(37, 64, 132, 0.2);
  background: linear-gradient(to right, #ffbb38, #713b0c);
  .content {
    box-shadow: 0 0 20px rgba(255,187,56,.7) inset;
    .text {
      span {
        color: #ffb849;
      }
    }
    .grade {
      &-item {
        border-left: 1px solid #eeac34;
        border-top: 1px solid #eeac34;
      }
    }
  }

}
</style>

应用

在按钮组中,即按钮的父组件中

代码中省略了组件引入的相关代码

// 当然这里可以定义一个数组,使用v-for循环, 可以更加方便的配置快捷键
 <div class="filter-nav">
    <gardeButton default-checked :grade-num="1" shortcut="esc" @clickEvent="filterHandle('esc',$event)">重置</gardeButton>
    <gardeButton :grade-num="3" shortcut="f1" @clickEvent="filterHandle('f1',$event)">边缘增强</gardeButton>
    <gardeButton :grade-num="1" shortcut="f2" @clickEvent="filterHandle('f2',$event)">平滑处理</gardeButton>
    <gardeButton :grade-num="1" shortcut="f3" @clickEvent="filterHandle('f3',$event)">有机物剔除</gardeButton>
    <gardeButton :grade-num="1" shortcut="f4" @clickEvent="filterHandle('f4',$event)">无机物剔除</gardeButton>
    <gardeButton :grade-num="1" shortcut="f5" @clickEvent="filterHandle('f5',$event)">黑白</gardeButton>
    <gardeButton :grade-num="1" shortcut="f6" @clickEvent="filterHandle('f6',$event)">反色</gardeButton>
    <gardeButton :grade-num="3" shortcut="f7" @clickEvent="filterHandle('f7',$event)">超级增强</gardeButton>
    <gardeButton :grade-num="2" shortcut="f8" @clickEvent="filterHandle('f8',$event)">高能穿透</gardeButton>
    <gardeButton :grade-num="1" shortcut="f9" @clickEvent="filterHandle('f9',$event)">低能穿透</gardeButton>
</div>

以上几个按钮是互斥关系, 并且实现了多级点击效果

效果如下:

grade_button.gif

阅读 477

推荐阅读