introduce

The most common action button, Button is the browser’s own action button, but in order to unify the style, we will smooth out the browser style gap, incidentally add some new functions.

The functionality you want to implement

function introduce
type Primary/success/warning/danger/info/text
disabled It is prohibited to use
size 4 sizes, Large, medium, Small, mini
icon Settable icon
round Rounded button or not
circle Circular button or not
loading Loading state

Function implementation

1. Basic functions

Create a new “button. SCSS” folder under “button.vue” and “index.js” SRC /styles/ “SRC /styles/index.scss”

// button.vue
<template>
  <button class="my-button my-button-primary">
    <slot>button</slot>
  </button>
</template>

<script>

export default {
  name: 'Button',
  data () {
    return{}}},</script>
Copy the code
// button/index.js
import Button from './button.vue'
export default Button
Copy the code
// styles/button.scss
@charset "UTF-8";
@import "common/var";
@import "mixins/mixins";

@include b(button) {
  height: 36px;
  font-size: $--font-size-medium;
  color: #fff;
  border-radius: 4px;
  outline: none;
  border: 1px solid transparent;
  padding: 0 10px;
  cursor: pointer;
  &-primary {
    background-color: $--color-primary;
    // focus,hover, background color becomes lighter
    &:focus,
    &:hover {
      background-color: rgba($--color-primary, 0.7);
    }
    &:active {
      // When active, the background color becomes lighter and is distinguished from focus and hover
      background-color: rgba($--color-primary, 0.9); }}}Copy the code
// styles/index.scss
@import "button";
Copy the code

2. Type type

Button types are distinguished mainly by background color. So just set class according to type. A total of six types is designed, the primary (default), the info, success, warning, error, and the text.

// button.vue
<template>
  <button class="my-button" :class="{[`my-button-${type}`]: true}">
    <slot>button</slot>
  </button>
</template>

<script>
// the utility function is used to determine whether the value passed meets the criteria
import { oneOf } from '.. /.. /utils/assist'

export default {
  name: 'Button',
  data () {
    return{}},props: {
    type: {
      validator(value) {
        return oneOf(value, [
          'primary'.'info'.'success'.'warning'.'text'.'error',}]),type: String.default: 'primary',,}}}</script>
Copy the code

Then there are the styles for the different types

// button.scss --
&-info {
    background-color: $--color-info;
    border-color: #ddd;
    color: $--font-color-main;
    &:focus,
    &:hover {
      color: rgba($--font-color-main, 0.7);
    }
    &:active {
      color: rgba($--font-color-main, 0.9);
    }
  }
  &-success {
    background-color: $--color-success;
    border-color: $--color-success;
    &:focus,
    &:hover {
      background-color: rgba($--color-success, 0.7);
    }
    &:active {
      background-color: rgba($--color-success, 0.9);
    }
  }
  &-warning {
    background-color: $--color-warning;
    border-color: $--color-warning;
    &:focus,
    &:hover {
      background-color: rgba($--color-warning, 0.7);
    }
    &:active {
      background-color: rgba($--color-warning, 0.9);
    }
  }
  &-text {
    background-color: $--color-text;
    border-color: $--color-text;
    color: $--color-primary;
    &:focus,
    &:hover {
      color: rgba($--color-primary, 0.7);
    }
    &:active {
      color: rgba($--color-primary, 0.9);
    }
  }
  &-error {
    background-color: $--color-error;
    border-color: $--color-error;
    &:focus,
    &:hover {
      background-color: rgba($--color-error, 0.7);
    }
    &:active {
      background-color: rgba($--color-error, 0.9); }}Copy the code

3. The disabled are prohibited

The logic is simple, using the button tag’s native Disabled property. Basically write the style corresponding to the disabled state

<template>
  <button
    class="my-button"
    :disabled="disabled"
    :class="{ [`my-button-${type}`]: true, [`my-button-${type}-disabled`]: disabled, }"
    @click="handleClick"
  >
    <slot>button</slot>
  </button>
</template>
<script>
// the utility function is used to determine whether the value passed meets the criteria
import { oneOf } from '.. /.. /utils/assist'

export default {
  name: 'Button'.data() {
    return{}},props: {
    type: {
      validator(value) {
        return oneOf(value, [
          'primary'.'info'.'success'.'warning'.'text'.'error',}]),type: String.default: 'primary',},disabled: {
      type: Boolean.default: false,}},methods: {
    handleClick(event) {
      console.log('Button clicked', event)
      this.$emit('click', event)
    },
  },
}
</script>
Copy the code
// button.scss omits some code
  &-primary {
    background-color: $--color-primary;
    border-color: $--color-primary;
    // focus,hover, background color becomes lighter
    &:focus,
    &:hover {
      background-color: rgba($--color-primary, 0.7);
      border-color: rgba($--color-primary, 0.7);
    }
    &:active {
      // When active, the background color becomes lighter and is distinguished from focus and hover
      background-color: rgba($--color-primary, 0.9);
      border-color: rgba($--color-primary, 0.9);
    }
    // When disabled, it is disabled
    &-disabled {
      cursor: not-allowed;
      background-color: rgba($--color-primary, 0.5);
      border-color: rgba($--color-primary, 0.5);
      &:focus,
      &:hover,
      &:active {
        background-color: rgba($--color-primary, 0.5);
        border-color: rgba($--color-primary, 0.5); }}}Copy the code

Set the disabled style according to type. In the disabled state, the mouse style changes to not-allowed, and the background color increases opacity by 50%. The above style code is primary, and the other five types are the same.

4. The size of the size

Four sizes are set: Large, Medium (default), small, and mini. Sizing is also done by binding class.

// button.vue omits some code
<template>
  <button
    class="my-button"
    :disabled="disabled"
    :class="{ [`my-button-${type}`]: true, [`my-button-${type}-disabled`]: disabled, [`my-button-size-${size}`]: true }"
    @click="handleClick"
  >
    <slot>button</slot>
  </button>
</template>
<script>
export default{...props: {
     size: {
      validator(value) {
        return oneOf(value, [
          'large'.'medium'.'small'.'mini'])},type: String.default: 'medium',}}}</script>
Copy the code
// button.scss omits some code
// Here are the styles related to size. &-size { &-large {height: 40px;
      line-height: 40px;
    }
    &-medium {
      height: 36px;
      line-height: 36px;
    }
    &-small {
      height: 32px;
      line-height: 32px;
      font-size: $--font-size-small;
    }
    &-mini {
      height: 28px; line-height: 28px; font-size: $--font-size-small; }}Copy the code

5. Set the icon icon

The use of ICONS refer to the Font class reference method of IconFONT, and ICONS can be updated as long as the icon project library is maintained. Select the icon from iconfont to add to the project, then download it locally.

Unzip the downloaded file to the SRC /styles/font directory and reference it in styles/index.scss.

// styles/index.scss
@import "./font/iconfont.css";
Copy the code

< I class=”iconfont icon-xxx” />

// button.vue omits some code
<template>
  <button
    class="my-button"
    :disabled="disabled"
    :class="{ [`my-button-${type}`]: true, [`my-button-${type}-disabled`]: disabled, [`my-button-size-${size}`]: true }"
    @click="handleClick"
  >
    <i :class="['iconfont', `${icon}`]"></i>
    <slot></slot>
  </button>
</template>
<script>
export default{.../ / icon
  icon: {
    type: String}... }</script>
Copy the code

6. Rounded button

The function is simple. Set border-radius.

// button.vue omits some code
<template>
  <button
    class="my-button"
    :disabled="disabled"
    :class="{ [`my-button-${type}`]: true, [`my-button-${type}-disabled`]: disabled, [`my-button-size-${size}`]: true, [`my-button-size-${size}-round`]: round }"
    @click="handleClick"
  >
    <i :class="['iconfont', `${icon}`]"></i>
    <slot></slot>
  </button>
</template>
<script>
export default{.../ / icon
  round: {
    type: Boolean.default: false}... }</script>
Copy the code
// button.scss omits some code
&-size {
    &-large {
      height: 40px;
      line-height: 40px;
      &-round {
        border-radius: 20px;
      }
    }
    &-medium {
      height: 36px;
      line-height: 36px;
      &-round {
        border-radius: 18px;
      }
    }
    &-small {
      height: 32px;
      line-height: 32px;
      font-size: $--font-size-small;
      &-round {
        border-radius: 16px;
      }
    }
    &-mini {
      height: 28px; line-height: 28px; font-size: $--font-size-small; &-round { border-radius: 14px; }}}Copy the code

7. Circular button

The implementation roadmap is the same as that for the rounded corner button. Set the border-radius to 50%. Here we need to adjust the min-width and padding so that width is equal to height.

// button.vue omits some code
<template>
  <button
    class="my-button"
    :disabled="disabled"
    :class="{ [`my-button-${type}`]: true, [`my-button-${type}-disabled`]: disabled, [`my-button-size-${size}`]: true, [`my-button-size-${size}-round`]: round, [`my-button-size-${size}-circle`]: circle }"
    @click="handleClick"
  >
    <i :class="['iconfont', `${icon}`]"></i>
    <slot></slot>
  </button>
</template>
<script>
export default{.../ / icon
  circle: {
    type: Boolean.default: false}... }</script>
Copy the code
// button.scss omits some code. &-size { &-large {height: 40px;
      line-height: 40px;
      &-round {
        border-radius: 20px;
      }
      &-circle {
        min-width: 40px;
        border-radius: 50%;
      }
    }
    &-medium {
      height: 36px;
      line-height: 36px;
      &-round {
        border-radius: 18px;
      }
      &-circle {
        min-width: 36px;
        border-radius: 50%;
      }
    }
    &-small {
      height: 32px;
      line-height: 32px;
      font-size: $--font-size-small;
      &-round {
        border-radius: 16px;
      }
      &-circle {
        padding: 0 5px;
        min-width: 32px;
        border-radius: 50%;
      }
    }
    &-mini {
      height: 28px;
      line-height: 28px;
      font-size: $--font-size-small;
      &-round {
        border-radius: 14px;
      }
      &-circle {
        padding: 0 5px;
        min-width: 28px;
        border-radius: 50%; }}}Copy the code

8. Loading

  1. buttonAdd an internal oneloadingIcon, passed in by the userloadingParameter control display hide. Note and provide to the usericonMake a toggle and makeloadingIcon andiconThe ICONS of parameters are mutually exclusive.

  2. loadingState, the button is disabled, thereforedisabledProperties byloadinganddisabledMake joint decisions.

  3. Construct one out of pseudo-elementslayerCovering thebuttonAbove, at the same timebuttonthepointer-eventsSet tonone“, so that the button can not be clicked.
// button.vue
<template>
  <button
    class="my-button"
    :disabled="disabled || loading"
    :class="{ [`my-button-${type}`]: true, [`my-button-${type}-disabled`]: disabled, [`my-button-size-${size}`]: true, [`my-button-size-${size}-round`]: round, [`my-button-size-${size}-circle`]: circle, [`my-button-loading-layer`]: loading }"
    @click="handleClick"
  >
    <i
      class="iconfont icon-loading"
      :class="{ [`my-button-loading`]: true }"
      v-if="loading"
    />
    <i :class="['iconfont', `${icon}`]" v-if=! "" loading"></i>
    <slot></slot>
  </button>
</template>

<script>
// the utility function is used to determine whether the value passed meets the criteria
import { oneOf } from '.. /.. /utils/assist'

export default {
  name: 'Button'.data() {
    return{}},props: {
    type: {
      validator(value) {
        return oneOf(value, [
          'primary'.'info'.'success'.'warning'.'text'.'error',}]),type: String.default: 'primary',},disabled: {
      type: Boolean.default: false,},size: {
      validator(value) {
        return oneOf(value, [
          'large'.'medium'.'small'.'mini'])},type: String.default: 'medium',},/ / icon
    icon: {
      type: String
    },
    // Round button
    round: {
      type: Boolean.default: false
    },
    // Round button
    circle: {
      type: Boolean.default: false
    },
    loading: {
      type: Boolean.default: false}},methods: {
    handleClick(event) {
      console.log('Button clicked', event)
      this.$emit('click', event)
    },
  },
}
</script>
Copy the code
// button.scss omits some code
&-loading-layer {
  pointer-events: none;
  &::before {
    pointer-events: none;
    content: ' ';
    position: absolute;
    left: -1px;
    top: -1px;
    right: -1px;
    bottom: -1px;
    border-radius: inherit;
    background-color: rgba(255.255.255.0.4); }}Copy the code

conclusion

The above is the first vUE knowledge review UI components, to introduce the most common component Button implementation process, the use of VUE related knowledge has parent-child component communication, class and style binding, slot slot and so on. These are the basic knowledge, not difficult, but more about the processing of CSS, such as the weight design of CSS when overwriting styles, and the use of false elements to overwrite the loading function so that it cannot be clicked, etc.

Scaffolding please refer to the first: juejin.cn/post/701798… Oversnail.github. IO/over-snail-… Git address: github.com/overSnail/o…

Involve knowledge points and reference articles

1. (Vue) : class and style binding 2. (Vue) : prop parent component parameter transfer 3. (Vue) : slot slot 4