实现一个基于Vue的Button小组件

概述

原生HTML的button只能保证功能存在,样式都不怎么好看。当然也可以通过编写css样式来改变原生HTML中的button显示,但是现在各个UI框架都很流行,也很方便,很多时候都是直接引入框架就能获得非常好看、好用的样式组件。那么此篇文章使用Vue也来实现一个好看、使用的Button小组件。

实现

  1. button.vue
    首先需要在模板页面将基本button组件需要的元素进行组装
<template>
  <button
    :class="[
      'pm-button', `pm-button--${type}`, `pm-button--${size}`,
      {
        'pm-button--plain': plain,
        'pm-button--disabled': disabled
      },
      `pm-button--${shape}`
    ]"
    :disabled="disabled"
    @click="clickHandler"
  >
    <i v-else-if="icon" :class="['pm-button__icon pm-font', `pm-icon-${icon}`]"></i>
    <slot></slot>
  </button>
</template>

<script>
  const Constant = {
    typeMap: {
      default: "default",
      primary: "primary",
      success: "success",
      warning: "warning",
      danger: "danger"
    },
    buttonSizeMap: {
      large: "large",
      normal: "normal",
      small: "small",
      mini: "mini"
    },
    shapeMap: {
      default: "default",
      round: "round",
      circle: "circle"
    }
  }
  export default {
    name: "PmButton",
    props: {
      type: {
        default: Constant.typeMap.default,
        type: String
      },
      size: {
        default: Constant.buttonSizeMap.normal,
        type: String
      },
      plain: {
        default: false,
        type: Boolean
      },
      icon: String,
      loading: {
        default: false,
        type: Boolean
      },
      shape: {
        default: Constant.shapeMap.default,
        type: String
      },
      disabled: Boolean
    },
    methods: {
      clickHandler(event) {
        this.$emit("click", event);
      }
    }
  }
</script>

  1. button.less
    接下来需要为button添加不同种类的样式,适配使用的时候传入的值,而得到对应种类的button
// common/index.less文件
// button
@button-mini-height: 1.4rem;
@button-mini-min-width: 3.2rem;
@button-mini-font-size: .7rem;
@button-mini-line-height: 1.3rem;
@button-mini-padding: 0 .1rem;
@button-small-height: 1.9rem;
@button-small-font-size: .8rem;
@button-small-min-width: 3.8rem;
@button-small-line-height: 1.9rem;
@button-small-padding: 0 .5rem;
@button-normal-font-size: .9rem;
@button-normal-padding: 0 1rem;
@button-large-height: 3.2rem;
@button-large-line-height: 3.2rem;
@button-large-font-size: 1rem;
@button-large-padding: 0 1.2rem;

@button-default-height: 2.8rem;
@button-default-line-height: 2.8rem;
@button-default-font-size: 1rem;
@button-default-color: @text-color-default;
@button-default-background-color: @white;
@button-default-border-color: @border-color-default;
@button-success-color: @white;
@button-success-background-color: @green;
@button-success-border-color: @green;
@button-primary-color: @white;
@button-primary-background-color: @blue;
@button-primary-border-color: @blue;
@button-danger-color: @white;
@button-danger-background-color: @red;
@button-danger-border-color: @red;
@button-warning-color: @white;
@button-warning-background-color: @orange;
@button-warning-border-color: @orange;

@button-border-width: @button-border-width-default;
@button-border-radius: .15rem;
//@button-round-border-radius: 10em;
@button-plain-background-color: @white;
@button-disabled-opacity: .5;
@import "../common/index.less";    //上边提到的额外的基础变量

.pm-button {
  position: relative;
  display: inline-block;
  border-radius: @button-border-radius;
  margin: 0;
  padding: 0;
  text-align: center;
  border: @button-border-width solid;
  box-sizing: border-box;
  outline: none;

  &::before {
    position: absolute;
    top: 50%;
    left: 50%;
    width: 100%;
    height: 100%;
    background-color: @black;
    border: inherit;
    border-color: @black;
    border-radius: inherit;
    transform: translate(-50%, -50%);
    opacity: 0;
    content: ' ';
  }
  &:active::before {
    opacity: .1;
  }

  &--default {
    color: @button-default-color;
    background-color: @button-default-background-color;
    border-color: @button-default-border-color;
  }
  &--primary {
    color: @button-primary-color;
    background-color: @button-primary-background-color;
    border-color: @button-primary-border-color;
  }
  &--success {
    color: @button-success-color;
    background-color: @button-success-background-color;
    border-color: @button-success-border-color;
  }
  &--warning {
    color: @button-warning-color;
    background-color: @button-warning-background-color;
    border-color: @button-warning-border-color;
  }
  &--danger {
    color: @button-danger-color;
    background-color: @button-danger-background-color;
    border-color: @button-danger-border-color;
  }

  &--large {
    font-size: @button-large-font-size;
    height: @button-large-height;
    line-height: @button-large-line-height;
    padding: @button-large-padding;
  }
  &--normal {
    font-size: @button-normal-font-size;
    height: @button-default-height;
    line-height: @button-default-line-height;
    padding: @button-normal-padding;
  }
  &--small {
    font-size: @button-small-font-size;
    height: @button-small-height;
    line-height: @button-small-line-height;
    padding: @button-small-padding;
    min-width: @button-small-min-width;
  }
  &--mini {
    font-size: @button-mini-font-size;
    height: @button-mini-height;
    line-height: @button-mini-line-height;
    padding: @button-mini-padding;
    min-width: @button-mini-min-width;
  }

  &--plain {
    background-color: @button-plain-background-color;
    &.pm-button--primary {
      color: @button-primary-background-color;
    }
    &.pm-button--success {
      color: @button-success-background-color;
    }
    &.pm-button--warning {
      color: @button-warning-background-color;
    }
    &.pm-button--danger {
      color: @button-danger-background-color;
    }
  }

  &--round {
    &.pm-button--large {
      border-radius: @button-large-height;
    }
    &.pm-button--normal {
      border-radius: @button-default-height;
    }
    &.pm-button--small {
      border-radius: @button-small-height;
    }
    &.pm-button--mini {
      border-radius: @button-mini-height;
    }
  }
  &--circle {
    padding: 0;
    &.pm-button--large {
      width: @button-large-height;
      border-radius: @button-large-height;
    }
    &.pm-button--normal {
      width:@button-default-height;
      border-radius: @button-default-height;
    }
    &.pm-button--small {
      width:@button-mini-height;
      border-radius: @button-small-height;
    }
    &.pm-button--mini {
      width:@button-mini-height;
      border-radius: @button-mini-height;
    }
  }

  &--disabled {
    opacity: .5;
  }

  &__icon {
    position: relative;
    top: .11rem;
  }
}
  1. 测试Button小组件
<template>
  <div>
    <h3>按钮种类</h3>
    <div class="default">
      <pm-button type="default">默认按钮</pm-button>
      <pm-button type="primary">普通按钮</pm-button>
      <pm-button type="success">成功按钮</pm-button>
      <pm-button type="warning">警告按钮</pm-button>
      <pm-button type="danger">危险按钮</pm-button>
    </div>
    <h3>按钮大小</h3>
    <div class="size">
      <pm-button size="large" type="primary">大按钮</pm-button>
      <pm-button size="normal" type="primary">普通按钮</pm-button>
      <pm-button size="small" type="primary">小按钮</pm-button>
      <pm-button size="mini" type="primary">Mini按钮</pm-button>
    </div>
    <h3>镂空按钮</h3>
    <div class="default">
      <pm-button type="primary" plain>普通按钮</pm-button>
      <pm-button type="success" plain>成功按钮</pm-button>
      <pm-button type="warning" plain>警告按钮</pm-button>
      <pm-button type="danger" plain>危险按钮</pm-button>
    </div>
    <h3>圆形按钮</h3>
    <div class="default">
      <pm-button type="primary" shape="round">普通按钮</pm-button>
      <pm-button icon="like-o" shape="circle"></pm-button>
    </div>
    <h3>图标按钮</h3>
    <div class="size">
      <pm-button type="success" icon="like-o"></pm-button>
      <pm-button type="primary" icon="search">搜索按钮</pm-button>
    </div>
    <h3>按钮点击</h3>
    <div class="size">
      <pm-button @click="btnClick" type="success">支付成功</pm-button>
      <pm-button @click="btnClick2">点击我</pm-button>
      <pm-button type="danger" disabled>被禁用</pm-button>
    </div>
  </div>
</template>

<script>
  export default {
    name: "ButtonTest",

    methods: {
      btnClick() {
        this.$toast.success("支付成功");
      },
      btnClick2(e) {
        console.log(e)
      }
    }
  }
</script>

<style scoped>
  .default, .size {
    display: flex;
    flex-direction: row;
    justify-content: flex-start;
    flex-wrap: wrap;
  }
  button {
    margin: .2rem .6rem;
  }
  button:last-child {
    margin: .2rem 0 .2rem .6rem;
  }
</style>

效果展示

简单几个文件,就完成了组件化的button,当需要使用时,直接引入使用即可,简单方便,可复用。运行测试页面后,会得到这样的效果图。


效果展示
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,056评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,842评论 2 378
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,938评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,296评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,292评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,413评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,824评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,493评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,686评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,502评论 2 318
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,553评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,281评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,820评论 3 305
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,873评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,109评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,699评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,257评论 2 341

推荐阅读更多精彩内容

  • 本文为2016年11月9日,『前端之巅』微信群在线分享活动总结整理而成,转载请在文章开头处注明来自『前端之巅』公众...
    尾尾阅读 10,505评论 3 32
  • 第一部分 HTML&CSS整理答案 1. 什么是HTML5? 答:HTML5是最新的HTML标准。 注意:讲述HT...
    kismetajun阅读 27,386评论 1 45
  • UI组件 element- 饿了么出品的Vue2的web UI工具套件 Vux- 基于Vue和WeUI的组件库 m...
    小姜先森o0O阅读 9,389评论 0 72
  • 我家老大从小打的国产免费疫苗,进口的收费的几乎没打过,记得三岁多有一针疫苗,可以选国产免费和进口收费,进口的也不贵...
    冰月清秋阅读 200评论 0 0
  • 我妈有时候脾气特别坏。 比如我三年级的一个英语单词没有学会。结果同步上一个题就得使那个单词,我妈教了我几遍,还...
    下雨的星期天_5f24阅读 308评论 0 1