阅读 132

Vue复习姿势系列之UI组件——按钮(Button)

介绍

最常见的操作按钮,button是浏览器自带的操作按钮,但为了统一样式,我们会抹平浏览器之间的样式差距,顺便增加点新的功能。

想要实现的功能

功能介绍
typeprimary(主色) / success(成功) / warning(警告) / danger(危险) / info(信息) / text(文本)
disabled禁止使用
size4种尺寸,large(超大),medium(常规),small(小),mini(迷你)
icon可设置图标
round是否圆角按钮
circle是否圆形按钮
loading加载中状态

功能实现

1. 基础功能

src/packages 目录下新建button文件夹,文件夹内创建button.vueindex.js
src/styles 目录下心新建button.scss,并在src/styles/index.scss中引入

// button.vue <template>   <button class="my-button my-button-primary">     <slot>按钮</slot>   </button> </template> <script> export default {   name: 'Button',   data () {     return {     }   }, } </script> 复制代码

// button/index.js import Button from './button.vue' export default Button 复制代码

// 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的时,背景色变浅     &:focus,     &:hover {       background-color: rgba($--color-primary, 0.7);     }     &:active {       // active时,背景色变浅,且与focus,hover做区分       background-color: rgba($--color-primary, 0.9);     }   } } 复制代码

// styles/index.scss @import "button"; 复制代码

image.png

2. 类型type

Button的类型区分主要是通过背景色区分的。因此只要根据type设置class即可。
总共设计了6种类型,primary(默认),info,success,warning,error,text

// button.vue <template>   <button class="my-button" :class="{[`my-button-${type}`]: true}">     <slot>按钮</slot>   </button> </template> <script> // 工具函数,用于判断传入的值是否符合条件 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> 复制代码

然后是不同type对应的样式

// 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);     }   } 复制代码

image.png

3. disabled 禁用

该功能实现逻辑比较简单,使用button标签的原生disabled属性即可实现。
主要是写disabled状态对应的样式

<template>   <button     class="my-button"     :disabled="disabled"     :class="{       [`my-button-${type}`]: true,       [`my-button-${type}-disabled`]: disabled,     }"     @click="handleClick"   >     <slot>按钮</slot>   </button> </template> <script> // 工具函数,用于判断传入的值是否符合条件 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('按钮被点击', event)       this.$emit('click', event)     },   }, } </script> 复制代码

// button.scss 省略部分代码   &-primary {     background-color: $--color-primary;     border-color: $--color-primary;     // focus,hover的时,背景色变浅     &:focus,     &:hover {       background-color: rgba($--color-primary, 0.7);       border-color: rgba($--color-primary, 0.7);     }     &:active {       // active时,背景色变浅,且与focus,hover做区分       background-color: rgba($--color-primary, 0.9);       border-color: rgba($--color-primary, 0.9);     }     // 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);       }     }   } 复制代码

根据type设置disabled样式,禁用状态下鼠标样式变为not-allowed,背景色增加50%的不透明度,上面样式代码是primary类型的,其他5个类型写法一样即可。

image.png

4. 尺寸size

设置了四个尺寸: large, medium(默认), small, mini
尺寸的切换同样由绑定class来完成。

// button.vue 省略部分代码 <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>按钮</slot>   </button> </template> <script> export default {    .......    props: {      size: {       validator(value) {         return oneOf(value, [           'large',           'medium',           'small',           'mini'         ])       },       type: String,       default: 'medium',     },    } } </script> 复制代码

// button.scss 省略部分代码 // 以下是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;     }   } 复制代码

image.png

5. 可设置图标 icon

图标的使用方法参考iconfontFont class引用方式,后续只要维护图标项目库即可做到图标更新。
从iconfont上选择图标添加至项目,然后下载到本地。

image.png

下载的文件解压到src/styles/font目录下,然后在styles/index.scss中引用。

// styles/index.scss @import "./font/iconfont.css"; 复制代码

这样就能在组件上使用了,使用方式是<i class="iconfont icon-xxx" />

// button.vue 省略部分代码 <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: {     type: String   }   ...... } </script> 复制代码

image.png

6. 圆角按钮

功能比较简单,设置border-radius即可。

// button.vue 省略部分代码 <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 {   ......   // 图标   round: {     type: Boolean,     default: false   }   ...... } </script> 复制代码

// button.scss 省略部分代码 &-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;       }     }   } 复制代码

image.png

7. 圆形按钮

实现思路与圆角按钮一样,设置border-radius为50%即可。
这里需调整min-widthpadding,使其能达到width=height的条件。

// button.vue 省略部分代码 <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 {   ......   // 图标   circle: {     type: Boolean,     default: false   }   ...... } </script> 复制代码

// button.scss 省略部分代码 ...... &-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%;       }     }   } 复制代码

image.png

8. 加载中 loading

  1. button内部新增一个loading图标,由用户传入的loading参数控制显示隐藏。注意与提供给用户的icon做下切换,使loading图标和icon参数的图标互斥。

  2. loading状态下,按钮被禁用,因此disabled属性由loadingdisabled共同决定。

  3. 用伪元素构造一个layer覆盖在button上面,同时buttonpointer-events设为none,这样能实现按钮无法点击的效果。

// 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> // 工具函数,用于判断传入的值是否符合条件 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: {       type: String     },     // 圆角按钮     round: {       type: Boolean,       default: false     },     // 圆形按钮     circle: {       type: Boolean,       default: false     },     loading: {       type: Boolean,       default: false     }   },   methods: {     handleClick(event) {       console.log('按钮被点击', event)       this.$emit('click', event)     },   }, } </script> 复制代码

// button.scss 省略部分代码 &-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);   } } 复制代码

结语

以上是vue知识复习之UI组件的第一篇,给大家介绍了最常见的组件Button的实现过程,运用到的Vue相关知识有父子组件通信,classstyle绑定,slot插槽等。都是基础知识,难度不大,更多的是对css的处理,比如覆盖样式时的css权重设计,loading功能中利用伪元素覆盖在上面使其无法点击等。


作者:狂野蜗牛
链接:https://juejin.cn/post/7018149193885679647


文章分类
后端
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐