仿Element-UI组件封装系列2-button按钮组件

知识点(传参,这里对传参的其他方式进行了使用,也可以使用父子传参实现,可以看我之前的博客进行学习)

  • $attrs(接收非prop的属性;如disabled属性)

  • $listeners(接收事件监听)

目标及要求说明

按钮组件

Element-button

属性:

参数说明类型可选值默认值
type按钮类型stringprimary/success/warning/danger/info-
disabled是否禁用boolean-false

事件:

事件名说明事件参数
click点击事件原生事件参数

插槽:

插槽名说明
default文本区域

基本结构:

<template>
  <button type="button" class="my-button my-button--primary is-disabled">
    <span>默认按钮</span>
  </button>
</template>

<script>
export default {}
</script>

<style lang="less">
.my-button {
  display: inline-block;
  line-height: 1;
  white-space: nowrap;
  cursor: pointer;
  background: #fff;
  border: 1px solid #dcdfe6;
  color: #606266;
  -webkit-appearance: none;
  text-align: center;
  box-sizing: border-box;
  outline: none;
  margin: 0;
  transition: 0.1s;
  font-weight: 500;
  -moz-user-select: none;
  -webkit-user-select: none;
  -ms-user-select: none;
  padding: 12px 20px;
  font-size: 14px;
  border-radius: 4px;

  &:focus,
  &:hover {
    color: #409eff;
    border-color: #c6e2ff;
    background-color: #ecf5ff;
  }
  // 禁用状态
  &.is-disabled,
  :hover.is-disabled {
    color: #c0c4cc;
    cursor: not-allowed;
    background-image: none;
    background-color: #fff;
    border-color: #ebeef5;
  }
  // 朴素按钮的状态
  &.is-plain:hover {
    background: #fff;
    border-color: #409eff;
    color: #409eff;
    &.is-disabled {
      color: #c0c4cc;
      cursor: not-allowed;
      background-image: none;
      background-color: #fff;
      border-color: #ebeef5;
    }
  }
  // 主要按钮的样式
  &.my-button--primary {
    color: #fff;
    background-color: #409eff;
    border-color: #409eff;
    // hover状态
    &:hover {
      background: #66b1ff;
      border-color: #66b1ff;
      color: #fff;
    }
    // 禁用状态
    &.is-disabled {
      color: #fff;
      background-color: #a0cfff;
      border-color: #a0cfff;
    }
    // 朴素状态
    &.is-plain {
      color: #409eff;
      background: #ecf5ff;
      border-color: #b3d8ff;
      &:hover {
        background: #409eff;
        border-color: #409eff;
        color: #fff;
      }
      &.is-disabled {
        color: #8cc5ff;
        background-color: #ecf5ff;
        border-color: #d9ecff;
      }
    }
  }
  // 成功按钮的样式
  &.my-button--success {
    color: #fff;
    background-color: #67c23a;
    border-color: #67c23a;
    // hover状态
    &:hover {
      background: #85ce61;
      border-color: #85ce61;
      color: #fff;
    }
    &.is-disabled {
      color: #fff;
      background-color: #b3e19d;
      border-color: #b3e19d;
    }
    // 朴素状态
    &.is-plain {
      color: #67c23a;
      background: #f0f9eb;
      border-color: #c2e7b0;
      &:hover {
        background: #67c23a;
        border-color: #67c23a;
        color: #fff;
      }
      &.is-disabled {
        color: #a4da89;
        background-color: #f0f9eb;
        border-color: #e1f3d8;
      }
    }
  }
  // 信息按钮的样式
  &.my-button--info {
    color: #fff;
    background-color: #909399;
    border-color: #909399;
    &:hover {
      background: #a6a9ad;
      border-color: #a6a9ad;
      color: #fff;
    }
    &.is-disabled {
      color: #fff;
      background-color: #c8c9cc;
      border-color: #c8c9cc;
    }
    // 朴素状态
    &.is-plain {
      color: #909399;
      background: #f4f4f5;
      border-color: #d3d4d6;
      &:hover {
        background: #909399;
        border-color: #909399;
        color: #fff;
      }
      &.is-disabled {
        color: #bcbec2;
        background-color: #f4f4f5;
        border-color: #e9e9eb;
      }
    }
  }
  // 警告按钮的样式
  &.my-button--warning {
    color: #fff;
    background-color: #e6a23c;
    border-color: #e6a23c;
    &:hover {
      background: #ebb563;
      border-color: #ebb563;
      color: #fff;
    }
    &.is-disabled {
      color: #fff;
      background-color: #f3d19e;
      border-color: #f3d19e;
    }
    // 朴素状态
    &.is-plain {
      color: #e6a23c;
      background: #fdf6ec;
      border-color: #f5dab1;
      &:hover {
        color: #e6a23c;
        background: #fdf6ec;
        border-color: #f5dab1;
      }
      &.is-disabled {
        color: #f0c78a;
        background-color: #fdf6ec;
        border-color: #faecd8;
      }
    }
  }
  // 危险按钮的样式
  &.my-button--danger {
    color: #fff;
    background-color: #f56c6c;
    border-color: #f56c6c;
    &:hover {
      background: #f78989;
      border-color: #f78989;
      color: #fff;
    }
    &.is-disabled {
      color: #fff;
      background-color: #fab6b6;
      border-color: #fab6b6;
    }
    // 朴素状态
    &.is-plain {
      color: #f56c6c;
      background: #fef0f0;
      border-color: #fbc4c4;
      &:hover {
        background: #f56c6c;
        border-color: #f56c6c;
        color: #fff;
      }
      &.is-disabled {
        color: #f9a7a7;
        background-color: #fef0f0;
        border-color: #fde2e2;
      }
    }
  }

  // 圆角按钮
  &.is-round {
    border-radius: 20px;
    padding: 12px 23px;
  }

  // 兄弟的间隙
  & + .my-button {
    margin-left: 10px;
  }
}
</style>

修改examples中的组件及路由,方便做测试

在这里插入图片描述

实现 - 按钮 - 插槽(用户可以自定义按钮内容)

默认插槽:实现用户输入操作。

组件代码 : packages/button/button.vue

<template>
  <button type="button" class="my-button my-button--primary is-disabled">
    <span><slot>默认按钮</slot></span>
  </button>
</template>

测试代码:

<template>
  <div class="home">
    <my-button>普通按钮</my-button>
    <my-button>成功按钮</my-button>
  </div>
</template>

效果:
在这里插入图片描述

实现disabled(用户可以设置按钮禁用)

disabled是原生属性,建议直接从外部传入,不需要props

在组件内部通过$attrs来获取。

在父组件中使用子组件时,如果所传入的属性在子组件并没有定义相应的prop去接收,则它们会自动收集到$attrs中。

<template>
<!-- 如果希望按钮不可用,则加一个  类 -->
  <!--  -->
  <button type="button" class="my-button my-button--primary"
  :class="cClass"
  >
    <span><slot>默认按钮</slot></span>
  </button>
</template>

<script>
export default {
  name: 'MyButton',
  created () {
    console.log(this.$attrs)
  },
  computed: {
    cClass () {
      if ('disabled' in this.$attrs) {
        return 'is-disabled'
      } else {
        return ''
      }
      // {'is-disabled': $attrs.disabled===''}
    }
  },
  props: {
    // disabled: {
    //   type: Boolean,
    //   default: false
    // }
  }
}
</script>

测试代码:

<template>
  <div class="home">
    <!-- <button disabled /> -->
    <my-button disabled>普通的-不可用的按钮</my-button>
    <my-button a="1" b="2">成功按钮</my-button>
  </div>
</template>

实现type(用户可以设置按钮的颜色状态)

按钮的5种类型

props: {
    // 类型
    type: {
      type: String,
      validator (value) {
        const arr = ['primary', 'success', 'warning', 'danger', 'info']
        return arr.indexOf(value) !== -1
      }
    }
  }

组件代码:

computed: {
    cClass () {
      const arr = ['my-button--' + this.type]

      if ('disabled' in this.$attrs) {
        arr.push('is-disabled')
      }
      // console.log('arr', arr)
      return arr
    }
  },
  props: {
    // 类型
    type: {
      type: String,
      default: 'primary',
      validator (value) {
        const arr = ['primary', 'success', 'warning', 'danger', 'info']
        // return arr.indexOf(value) !== -1
        return arr.includes(value)
      }
    }
    // disabled: {
    //   type: Boolean,
    //   default: false
    // }
  }

测试代码:

<template>
  <div class="home">
    <!-- <button disabled /> -->
    <my-button disabled type="info">普通的-不可用的按钮</my-button>
    <my-button type="success">成功的按钮</my-button>
    <my-button type="danger">失败的按钮</my-button>
  </div>
</template>

实现click事件(用户可以添加按钮点击方法)

  1. 在自定义组件是不会自动监听click的,需要手动去处理。
// vue对于标准的html标签是支持click,mouseenter.... 原生dom事件的。
<button @click="hClick">原生的按钮</button>

// 下面的click不会有效果
<my-button type="danger" @click="hClick">失败的按钮</my-button> 

在子组件内部,可以通过this.$listeners获取父组件中在子组件上添加的事件监听

示例:

<my-button type="danger" @abc="hClick" @event1="hClick" @click="hClick">失败的按钮</my-button>

在子组件my-button内部,可以通过this.$listeners来获取这三个事件监听。
在这里插入图片描述

两种方案:

  • this.$emit(‘click’)
  • this.$listeners.click()

参考

<template>

  <!--
    @click="$emit('click')"
  -->
  <button type="button" class="my-button"
  :class="cClass"
  @click="onClick"
  >
    <span><slot>默认按钮</slot></span>
  </button>
</template>

<script>
export default {
  name: 'MyButton',
  created () {
    // console.log(this.$attrs)
    console.log(this.$listeners)
  },
  methods: {
    onClick () {
      if (this.$listeners.click) {
        this.$listeners.click()
      }
    }
  },
  computed: {
    cClass () {
      const arr = ['my-button--' + this.type]

      if ('disabled' in this.$attrs) {
        arr.push('is-disabled')
      }
      // console.log('arr', arr)
      return arr
    }
  },
  props: {
    // 类型
    type: {
      type: String,
      default: 'primary',
      validator (value) {
        const arr = ['primary', 'success', 'warning', 'danger', 'info']
        // return arr.indexOf(value) !== -1
        return arr.includes(value)
      }
    }
    // disabled: {
    //   type: Boolean,
    //   default: false
    // }
  }
}
</script>

<style lang="less">
.my-button {
  display: inline-block;
  line-height: 1;
  white-space: nowrap;
  cursor: pointer;
  background: #fff;
  border: 1px solid #dcdfe6;
  color: #606266;
  -webkit-appearance: none;
  text-align: center;
  box-sizing: border-box;
  outline: none;
  margin: 0;
  transition: 0.1s;
  font-weight: 500;
  -moz-user-select: none;
  -webkit-user-select: none;
  -ms-user-select: none;
  padding: 12px 20px;
  font-size: 14px;
  border-radius: 4px;

  &:focus,
  &:hover {
    color: #409eff;
    border-color: #c6e2ff;
    background-color: #ecf5ff;
  }
  // 禁用状态
  &.is-disabled,
  :hover.is-disabled {
    color: #c0c4cc;
    cursor: not-allowed;
    background-image: none;
    background-color: #fff;
    border-color: #ebeef5;
  }
  // 朴素按钮的状态
  &.is-plain:hover {
    background: #fff;
    border-color: #409eff;
    color: #409eff;
    &.is-disabled {
      color: #c0c4cc;
      cursor: not-allowed;
      background-image: none;
      background-color: #fff;
      border-color: #ebeef5;
    }
  }
  // 主要按钮的样式
  &.my-button--primary {
    color: #fff;
    background-color: #409eff;
    border-color: #409eff;
    // hover状态
    &:hover {
      background: #66b1ff;
      border-color: #66b1ff;
      color: #fff;
    }
    // 禁用状态
    &.is-disabled {
      color: #fff;
      background-color: #a0cfff;
      border-color: #a0cfff;
    }
    // 朴素状态
    &.is-plain {
      color: #409eff;
      background: #ecf5ff;
      border-color: #b3d8ff;
      &:hover {
        background: #409eff;
        border-color: #409eff;
        color: #fff;
      }
      &.is-disabled {
        color: #8cc5ff;
        background-color: #ecf5ff;
        border-color: #d9ecff;
      }
    }
  }
  // 成功按钮的样式
  &.my-button--success {
    color: #fff;
    background-color: #67c23a;
    border-color: #67c23a;
    // hover状态
    &:hover {
      background: #85ce61;
      border-color: #85ce61;
      color: #fff;
    }
    &.is-disabled {
      color: #fff;
      background-color: #b3e19d;
      border-color: #b3e19d;
    }
    // 朴素状态
    &.is-plain {
      color: #67c23a;
      background: #f0f9eb;
      border-color: #c2e7b0;
      &:hover {
        background: #67c23a;
        border-color: #67c23a;
        color: #fff;
      }
      &.is-disabled {
        color: #a4da89;
        background-color: #f0f9eb;
        border-color: #e1f3d8;
      }
    }
  }
  // 信息按钮的样式
  &.my-button--info {
    color: #fff;
    background-color: #909399;
    border-color: #909399;
    &:hover {
      background: #a6a9ad;
      border-color: #a6a9ad;
      color: #fff;
    }
    &.is-disabled {
      color: #fff;
      background-color: #c8c9cc;
      border-color: #c8c9cc;
    }
    // 朴素状态
    &.is-plain {
      color: #909399;
      background: #f4f4f5;
      border-color: #d3d4d6;
      &:hover {
        background: #909399;
        border-color: #909399;
        color: #fff;
      }
      &.is-disabled {
        color: #bcbec2;
        background-color: #f4f4f5;
        border-color: #e9e9eb;
      }
    }
  }
  // 警告按钮的样式
  &.my-button--warning {
    color: #fff;
    background-color: #e6a23c;
    border-color: #e6a23c;
    &:hover {
      background: #ebb563;
      border-color: #ebb563;
      color: #fff;
    }
    &.is-disabled {
      color: #fff;
      background-color: #f3d19e;
      border-color: #f3d19e;
    }
    // 朴素状态
    &.is-plain {
      color: #e6a23c;
      background: #fdf6ec;
      border-color: #f5dab1;
      &:hover {
        color: #e6a23c;
        background: #fdf6ec;
        border-color: #f5dab1;
      }
      &.is-disabled {
        color: #f0c78a;
        background-color: #fdf6ec;
        border-color: #faecd8;
      }
    }
  }
  // 危险按钮的样式
  &.my-button--danger {
    color: #fff;
    background-color: #f56c6c;
    border-color: #f56c6c;
    &:hover {
      background: #f78989;
      border-color: #f78989;
      color: #fff;
    }
    &.is-disabled {
      color: #fff;
      background-color: #fab6b6;
      border-color: #fab6b6;
    }
    // 朴素状态
    &.is-plain {
      color: #f56c6c;
      background: #fef0f0;
      border-color: #fbc4c4;
      &:hover {
        background: #f56c6c;
        border-color: #f56c6c;
        color: #fff;
      }
      &.is-disabled {
        color: #f9a7a7;
        background-color: #fef0f0;
        border-color: #fde2e2;
      }
    }
  }

  // 圆角按钮
  &.is-round {
    border-radius: 20px;
    padding: 12px 23px;
  }

  // 兄弟的间隙
  & + .my-button {
    margin-left: 10px;
  }
}
</style>

©️2020 CSDN 皮肤主题: 数字20 设计师:CSDN官方博客 返回首页