网站首页 » 前端开发 » Vue » Vue Element 模仿秀-按钮篇(Button)
上一篇:
下一篇:

Vue Element 模仿秀-按钮篇(Button)

前言

Element UI 做得还是不错的,我第一次看到时都被征服了。所以我觉得有必需把官方的示例尽可能的自己撸一遍。从中一定可以学到不少东西。

这篇文章是 Vue Element 模仿秀的第一篇:按钮组件。

Vue Element 模仿秀-按钮篇(Button)

文件结构
├── index.html
├── assets
│  ├── fonts
│  │  ├── yunkus-icons.ttf 
│  │  └── yunkus-icons.woff
│  └── icon.css
├── main.js
├── router
│  └── index.js      # 路由配置文件
└── components      
   ├── Home.vue          # 大的框架结构组件
   ├── ButtonGroup.vue      
   └── Button.vue
Button.vue
<template>
  <button
  @click="handleClick"
  :autofocus = "autofocus" // 自动获得焦点
  :disabled = "disabled"
  class="yk-button"
  :class="[
      type ? 'yk-button-'+ type : '',
      size ? 'yk-button-'+ size :'',
      {
        'is-disabled': disabled,// 禁用按钮
        'is-round': round,// 圆形按钮
        'is-loading':loading,// 加载状态
        'is-plain':plain // 淡色按钮
      }
    ]"
  >
    <i v-if="loading" class="yk-icon-loading"></i>
    <i :class="icon" v-if="icon && !loading"></i>
    <span v-if="$slots.default"><slot></slot></span>
  </button>
</template>

<script>
export default {
  name: "YkButton",
  props: {
    type: {
      type: String,
      default: "default"
    },
    size: String,
    icon: String,
    disabled: Boolean,
    round: Boolean,
    loading: Boolean,
    plain: Boolean,
    autofocus: Boolean
  },
  methods: {
    handleClick(evt) {
      this.$emit("click", evt); // 广播事件,让父组件捕获并执行相关函数
    }
  }
};
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
button {
  text-rendering: auto;
  color: initial;
  letter-spacing: normal;
  word-spacing: normal;
  text-transform: none;
  text-indent: 0px;
  text-shadow: none;
  display: inline-block;
  text-align: start;
  margin: 0em;
  font: 400 13.3333px Arial;
}
.yk-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;
  -webkit-box-sizing: border-box;
  box-sizing: border-box;
  outline: 0;
  margin: 0;
  -webkit-transition: 0.1s;
  transition: 0.1s;
  font-weight: 500;
  padding: 12px 20px;
  font-size: 14px;
  border-radius: 4px;
}
.yk-button:active {
  outline: none;
}
.yk-button.is-disabled,
.yk-button.is-disabled:focus,
.yk-button.is-disabled:hover {
  color: #c0c4cc;
  cursor: not-allowed;
  background-image: none;
  background-color: #fff;
  border-color: #ebeef5;
}
.yk-button-mini,
.yk-button-small {
  font-size: 12px;
  border-radius: 3px;
}
.yk-button-mini {
  padding: 7px 15px;
}
.yk-button-small {
  padding: 9px 15px;
}
.yk-button-medium {
  padding: 10px 20px;
  font-size: 14px;
  border-radius: 4px;
}
.yk-button-primary {
  color: #fff;
  background-color: #409eff;
  border-color: #409eff;
}
.yk-button-primary:focus,
.yk-button-primary:hover {
  background: #66b1ff;
  border-color: #66b1ff;
  color: #fff;
}
.yk-button-primary.is-active,
.yk-button-primary:active {
  background: #3a8ee6;
  border-color: #3a8ee6;
  color: #fff;
}
.yk-button-primary.is-disabled,
.yk-button-primary.is-disabled:active,
.yk-button-primary.is-disabled:focus,
.yk-button-primary.is-disabled:hover {
  color: #fff;
  background-color: #a0cfff;
  border-color: #a0cfff;
}
.yk-button-primary.is-plain {
  color: #409eff;
  background-color: #ecf5ff;
  border-color: #b3d8ff;
}
.yk-button-primary.is-plain:focus,
.yk-button-primary.is-plain:hover {
  background: #409eff;
  border-color: #409eff;
  color: #fff;
}
.yk-button-primary.is-plain:active {
  background: #3a8ee6;
  border-color: #3a8ee6;
  color: #fff;
  outline: none;
}
.yk-button-primary.is-plain.is-disabled,
.yk-button-primary.is-plain.is-disabled:active,
.yk-button-primary.is-plain.is-disabled:focus,
.yk-button-primary.is-plain.is-disabled:hover {
  color: #8cc5ff;
  background-color: #ecf5ff;
  border-color: #d9ecff;
}
.yk-button-success {
  color: #fff;
  background-color: #67c23a;
  border-color: #67c23a;
}
.yk-button-success:focus,
.yk-button-success:hover {
  background: #85ce61;
  border-color: #85ce61;
  color: #fff;
}
.yk-button-success.is-active,
.yk-button-success:active {
  background: #5daf34;
  border-color: #5daf34;
  color: #fff;
}
.yk-button-success.is-disabled,
.yk-button-success.is-disabled:active,
.yk-button-success.is-disabled:focus,
.yk-button-success.is-disabled:hover {
  color: #fff;
  background-color: #b3e19d;
  border-color: #b3e19d;
}
.yk-button-success.is-plain {
  color: #67c23a;
  background: #f0f9eb;
  border-color: #c2e7b0;
}
.yk-button-success.is-plain.is-disabled,
.yk-button-success.is-plain.is-disabled:active,
.yk-button-success.is-plain.is-disabled:focus,
.yk-button-success.is-plain.is-disabled:hover {
  color: #a4da89;
  background-color: #f0f9eb;
  border-color: #e1f3d8;
}
.yk-button-success.is-plain:active {
  background: #5daf34;
  border-color: #5daf34;
  color: #fff;
  outline: none;
}
.yk-button-success.is-plain:focus,
.yk-button-success.is-plain:hover {
  background: #67c23a;
  border-color: #67c23a;
  color: #fff;
}
.yk-button-info {
  color: #fff;
  background-color: #909399;
  border-color: #909399;
}
.yk-button-info.is-disabled,
.yk-button-info.is-disabled:active,
.yk-button-info.is-disabled:focus,
.yk-button-info.is-disabled:hover {
  color: #fff;
  background-color: #c8c9cc;
  border-color: #c8c9cc;
}
.yk-button-info:focus,
.yk-button-info:hover {
  background: #a6a9ad;
  border-color: #a6a9ad;
  color: #fff;
}
.yk-button-info.is-active,
.yk-button-info:active {
  background: #82848a;
  border-color: #82848a;
  color: #fff;
}
.yk-button-info.is-plain {
  color: #909399;
  background: #f4f4f5;
  border-color: #d3d4d6;
}
.yk-button-info.is-plain:focus,
.yk-button-info.is-plain:hover {
  background: #909399;
  border-color: #909399;
  color: #fff;
}
.yk-button-info.is-plain:active {
  background: #82848a;
  border-color: #82848a;
  color: #fff;
  outline: none;
}
.yk-button-warning {
  color: #fff;
  background-color: #e6a23c;
  border-color: #e6a23c;
}
.yk-button-warning:focus,
.yk-button-warning:hover {
  background: #ebb563;
  border-color: #ebb563;
  color: #fff;
}
.yk-button--warning.is-active,
.yk-button--warning:active {
  background: #cf9236;
  border-color: #cf9236;
  color: #fff;
}
.yk-button-warning.is-disabled,
.yk-button-warning.is-disabled:active,
.yk-button-warning.is-disabled:focus,
.yk-button-warning.is-disabled:hover {
  color: #fff;
  background-color: #f3d19e;
  border-color: #f3d19e;
}
.yk-button-warning.is-plain {
  color: #e6a23c;
  background: #fdf6ec;
  border-color: #f5dab1;
}
.yk-button-warning.is-plain:focus,
.yk-button-warning.is-plain:hover {
  background: #e6a23c;
  border-color: #e6a23c;
  color: #fff;
}
.yk-button-warning.is-plain:active {
  background: #cf9236;
  border-color: #cf9236;
  color: #fff;
  outline: none;
}
.yk-button-danger {
  color: #fff;
  background-color: #f56c6c;
  border-color: #f56c6c;
}
.yk-button-danger:focus,
.yk-button-danger:hover {
  background: #f78989;
  border-color: #f78989;
  color: #fff;
}
.yk-button-danger.is-active,
.yk-button-danger:active {
  background: #dd6161;
  border-color: #dd6161;
  color: #fff;
}
.yk-button-danger.is-disabled,
.yk-button-danger.is-disabled:active,
.yk-button-danger.is-disabled:focus,
.yk-button-danger.is-disabled:hover {
  color: #fff;
  background-color: #fab6b6;
  border-color: #fab6b6;
}
.yk-button-danger.is-plain {
  color: #f56c6c;
  background: #fef0f0;
  border-color: #fbc4c4;
}
.yk-button-danger.is-plain:focus,
.yk-button-danger.is-plain:hover {
  background: #f56c6c;
  border-color: #f56c6c;
  color: #fff;
}
.yk-button-danger.is-plain:active {
  background: #dd6161;
  border-color: #dd6161;
  color: #fff;
}

.yk-button-danger.is-plain.is-disabled,
.yk-button-danger.is-plain.is-disabled:active,
.yk-button-danger.is-plain.is-disabled:focus,
.yk-button-danger.is-plain.is-disabled:hover {
  color: #f9a7a7;
  background-color: #fef0f0;
  border-color: #fde2e2;
}

.yk-button + .yk-button {
  margin-left: 10px;
}

.yk-button.is-round {
  border-radius: 20px;
  padding: 12px 23px;
}

.yk-button.is-loading {
  position: relative;
  pointer-events: none;
}
.yk-button.is-loading: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.35);
}
</style>

上面的 :class=”[]”,我们可以看到非常地灵活,可以传入字符串或者对象。

如果子组件元素中有插件东西 $slots.default 就会有值,所以我们可以通过它来判断子组件元素中有没有传参。

props: {
  type: {
    type: String,
    default: "default"
  },
  size: String,
  ......
},

props 的对象形式接收参数,可以同时限制了要传入的参数的类型,并且可以设置默认值,这种写法更加灵活。用props 的数组形式的话,就不能限制参数的类型和设置默认值了。一般情况下,我们都需要对参数类型作一定的限制,所以不管怎么样,我们最好还是用 props 的对象形式来接收参数会好很多。

ButtonGroup.vue
<template>
  <div class="yk-button-group">
    <slot></slot>
  </div>
</template>
<script>
export default {
  name: "YkButtonGroup"
};
</script>
<style scoped>
.yk-button-group {
  overflow: hidden;
}
.yk-button-group .yk-button {
  float: left;
  position: relative;
}
.yk-button-group .yk-button + .yk-button {
  margin-left: 0;
}
.yk-button-group .yk-button:not(:last-child) {
  border-right-color: rgba(255, 255, 255, 0.5);
}
/* 找到即不是第一个也不是最后一个的按钮 */
.yk-button-group .yk-button:not(:first-child):not(:last-child) {
  border-radius: 0;
}
.yk-button-group .yk-button:first-child {
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
}
.yk-button-group .yk-button:last-child {
  border-top-left-radius: 0;
  border-bottom-left-radius: 0;
}
</style>

在其它组件中可以像下面这样用:

Home.vue
<template>
 <div>
  <div>
   <p>默认按钮</p>
   <p>
      <yk-button type="default" @click="dealingFn">默认按钮</yk-button>
      <yk-button type="primary" @click="dealingFn">主要按钮</yk-button>
      <yk-button type="success" @click="dealingFn">成功按钮</yk-button>
      <yk-button type="info" @click="dealingFn">信息按钮</yk-button>
      <yk-button type="warning" @click="dealingFn">警告按钮</yk-button>
      <yk-button type="danger" @click="dealingFn">危险按钮</yk-button>
   </p>
  </div>   
  <div>
    <p>朴素按钮</p>
    <p>
      <yk-button plain type="default" @click="dealingFn">默认按钮</yk-button>
      <yk-button plain type="primary" @click="dealingFn">主要按钮</yk-button>
      <yk-button plain type="success" @click="dealingFn">成功按钮</yk-button>
      <yk-button plain type="info" @click="dealingFn">信息按钮</yk-button>
      <yk-button plain type="warning" @click="dealingFn">警告按钮</yk-button>
      <yk-button plain type="danger" @click="dealingFn">危险按钮</yk-button>
    </p>
  </div>
  <div>
    <p>圆角按钮</p>
    <p>
      <yk-button round type="default" @click="dealingFn">默认按钮</yk-button>
      <yk-button round type="primary" @click="dealingFn">主要按钮</yk-button>
      <yk-button round type="success" @click="dealingFn">成功按钮</yk-button>
      <yk-button round type="info" @click="dealingFn">信息按钮</yk-button>
      <yk-button round type="warning" @click="dealingFn">警告按钮</yk-button>
      <yk-button round type="danger" @click="dealingFn">危险按钮</yk-button>
    </p>
  </div>
  <div>
    <p>禁用状态</p>
    <p>
      <yk-button disabled type="default">默认按钮</yk-button>
      <yk-button disabled type="primary">主要按钮</yk-button>
      <yk-button disabled type="success">成功按钮</yk-button>
      <yk-button disabled type="info">信息按钮</yk-button>
      <yk-button disabled type="warning">警告按钮</yk-button>
      <yk-button disabled type="danger">危险按钮</yk-button>
    </p>
    <p>
      <yk-button round disabled type="default">默认按钮</yk-button>
      <yk-button round disabled type="primary">主要按钮</yk-button>
      <yk-button round disabled type="success">成功按钮</yk-button>
      <yk-button round disabled type="info">信息按钮</yk-button>
      <yk-button round disabled type="warning">警告按钮</yk-button>
      <yk-button round disabled type="danger">危险按钮</yk-button>
    </p>
  </div>
  <div>
    <p>图标按钮</p>
    <p>
      <yk-button icon="yk-icon-d-arrow-left" type="default">上一页</yk-button>
      <yk-button type="primary">下一页<i class="yk-icon-d-arrow-right yk-icon-right"></i></yk-button>
      <yk-button type="success"><i class="yk-icon-star-off yk-icon-left"></i>取消收藏</yk-button>
      <yk-button type="info">收藏<i class="yk-icon-star-on yk-icon-right"></i></yk-button>
      <yk-button icon="yk-icon-upload" type="warning"></yk-button>
      <yk-button type="danger"> <i class="yk-icon-delete"></i> </yk-button>
    </p>
  </div>
    <div>
    <p>按钮组</p>
    <yk-button-group>
      <yk-button icon="yk-icon-d-arrow-left" type="success">上一页</yk-button>
      <yk-button type="success"><i class="yk-icon-star-off yk-icon-left"></i>取消收藏</yk-button>
      <yk-button type="success">收藏<i class="yk-icon-star-on yk-icon-right"></i></yk-button>
      <yk-button icon="yk-icon-upload" type="success"></yk-button>
      <yk-button type="success"> <i class="yk-icon-delete"></i> </yk-button>
      <yk-button type="success">下一页<i class="yk-icon-d-arrow-right yk-icon-right"></i></yk-button>
    </yk-button-group>
  </div>
 </div>
</template>

<script>
// 引入组件
import YkButtonGroup from "@/components/ButtonGroup";
import YkButton from "@/components/Button";
// 引入图标样式文件
import "@/assets/icon.css";
export default {
  name: "Home",
  components: { YkButtonGroup, YkButton },
  methods: {
    dealingFn(evt) {
      console.log("你点击了" + evt.target.innerText);
    }
  }
};
</script>

我直接在Home.vue 中引入这两个组件(Button 和 ButtonGroup)以及 icon.css 图标样式。图标的类名前缀我也作了修改。所以调用的时候类名是不一样的。

送温暖

在子组件中广播 click 后,我们在父组件中获取并使用这个事件时的正确写法应该是像示例中的那样:@click=”dealingFn” ,不需要带括号,也不需要传参数,你只需要在定义这个函数时传个形参,然后使用这个形参就可以了,这个参数就是你广播事件传递的参数。

在这里,@click=”dealingFn” 使用了广播的方式来实现响应父组件的点击事件,除此之外,如果我们不想在子组合中广播点击事件,我们可以改成这样 @click.native=”dealingFn”。子组件就不需要再通过 handleClick 方法来作为中转站了。这样看起来貌似更好,但在实践应用时,我们不可能让用户给这个按钮设置点击处理函数时要多加一个 .native 修饰符。我们要让用户用起来没有什么成功,这就是组件封装的真正意义所在。

<slot></slot> 具名的用法如果只有一个的话 Vue 会自动把组件标签中的内容全部放到这个 <solt> 标签中,但还有一种情况,就是有多个 <slot></slot>。在这种情况下我们就要像下面这样写:

在父组件中给元素添加相应的具名就可以了, Vue 会很智能的对号入座 ,比如:

请看
<!-- 在父组件中: -->
<child>
  <section>这里是没有主的内容,会被分配到默认的 slot 中</section>
  <header slot="header"><h3>头部</h3></header>
  <main slot="main"><p>主体内容</p></main>
  <footer slot="footer"><div>底部</div></footer>
<child>
<!-- 在子组件中: -->
<div>
  <slot></slot>
  <slot name="header"></slot>
  <slot name="main"></slot>
  <slot name="footer"></slot>
</div>

其实这个也没什么好说的,只是记录下,增强自己对 slot 的理解而已。不过如果在有两个 slot  具名的情况下,最好都给元素添加一个 slot 属性和对应的 name 属性,不然你会看到 $slot.default 中有四个项,但只有第一个项是有值的:

Vue slot 用法示例

上面的示例中我们使用了 H5 的一些新元素,<section></secion>、<header></header>、<main></main>、<footer></footer>,这些元素就像其它元素一样使用就可以了,我们只是在这些元素中添加了 slot 属性并设置了它的值,告诉  Vue 它要放到哪一个具名容器(对应<slot></slot> name 属性)中。

示例中的图标如果觉得还不能满足你,那么你可以到这个网站:https://icomoon.io/上挑选自己喜欢的图标,下载文件,用法跟上面的差不多。

  • 微信扫一扫,赏我

  • 支付宝扫一扫,赏我

声明

原创文章,不经本站同意,不得以任何形式转载,如有不便,请多多包涵!

本文永久链接:http://yunkus.com/vue-element-parody-button/

Leave a Reply

Your email address will not be published. Required fields are marked *

评论 END