用Vue模仿antd的样式造UI组件之button

1、环境的配置

1.新建一个文件夹javascript

mkdir eassyuicss

2.使用npm做为包管理工具html

npm init -yvue

3.使用parcel实现模块化导出与导入文件java

npm i -D parcelnode

4.下载vue的包npm

npm i vuejson

如今目录以下数组

.
├── LICENSE
├── node_modules
├── package-lock.json
└── package.json

复制代码

5.在根目录下新建一个src文件夹与一个index.html浏览器

6.在src文件夹下新建一个app.js文件,做为入口文件

7.在index.html引入app.js

<script src="./src/app.js"></script>

8.app.js中建立 vue 实例

import Vue from 'vue'
 new Vue({
     el:'#app'
 })
复制代码

2、肯定基本样式

使用css全局变量和:root伪类来设定全局基本样式

//index.html
<style> :root{ --primary-color: #1890ff; // 全局主色 --link-color: #1890ff; // 连接色 --success-color: #52c41a; // 成功色 --warning-color: #faad14; // 警告色 --error-color: #f5222d; // 错误色 --font-size-base: 14px; // 主字号 --heading-color: rgba(0, 0, 0, .85); // 标题色 --text-color: rgba(0, 0, 0, .65); // 主文本色 --text-color-secondary : rgba(0, 0, 0, .45); // 次文本色 --disabled-color : rgba(0, 0, 0, .25); // 失效色 --border-radius-base: 4px; // 组件/浮层圆角 --border-color-base: #d9d9d9; // 边框色 --box-shadow-base: 0 2px 8px rgba(0, 0, 0, .15); // 浮层阴影 --button-height:32px; } </style>
复制代码

css变量的使用

body{
    color:var(--primary-color)
}
复制代码

关于css伪元素:root和变量名的使用,具体能够看下面的链接 https://developer.mozilla.org/zh-CN/docs/Web/CSS/var ---var https://developer.mozilla.org/zh-CN/docs/Web/CSS/:root ---root

3、使用插槽和props来实现四种基本按钮

image-20190929213504887
文字内容在button组件的内部,可使用slot来实现,type决定了按钮的背景颜色,字体颜色,边框样式,可使用props来接收传入的参数

在src目录下新建button.vue文件

<template>
	<button class='h-button'>
    <slot></slot>
  </button>
</template>
<script>
 export default {
    props:{
      type:{
        type:String,
      	dafault:'defult',
        validator:(value)=>{
          //若是传入的参数不是如下四种则在控制台报错
          return ['primay','dashed','danger','link'].indexOf(value)!=-1
        }
      }
    }
  }
</script>
<style lang='scss'></style>
复制代码

为四种button写四种类名的样式,将传进来的type赋值给类名

<template>
  <button class="h-button" :class="{[`h-button-${type}`]:true}">
    <slot></slot>
  </button>
</template>
<style>
  .h-button{
    &.h-button-primary{}
    ...
  }
</style>
复制代码

在app.js中将button注册为全局组件

import Vue from 'vue'
import Button from './src/button'
Vue.component('h-button',Button)
复制代码

在index.html中去使用

<div id='app'>
  <h-button>按钮</h-button>
</div>
复制代码

在终端跳转至项目文件夹下,执行npx parcel --no-cache index.html.便会将相关的依赖下载。

屏幕快照 2019-09-29 下午10.47.09

而后在浏览器里打开locahost:1234,若是出现下面的错误信息

image-20190929223245302

则在package.json中增长下面的内容

"alias": {
  "vue": "./node_modules/vue/dist/vue.common.js"
},
复制代码

4、button-group的实现

屏幕快照 2019-09-30 下午9.21.41

在外层套一层div来实现对内部组件的排序约束

src文件夹下新建一个button-group.vue的文件

<template>
    <div class="h-button-group">
        <slot></slot>
    </div>
</template>
复制代码

按钮组中只有两边的按钮的边框是有角度的

.h-button-group{
        display: inline-flex;
        >.h-button{
            border-radius:0;
            &:first-child{
                border-top-left-radius:var(--border-radius-base);
                border-bottom-left-radius:var(--border-radius-base);
            }
            &:last-child{
                border-top-right-radius:var(--border-radius-base);
            }
        }
    }
复制代码

而后会有一个问题,button之间的border连在了一块儿

屏幕快照 2019-09-30 下午9.46.40

//将不是第一个子元素的button左移一像素
.h-button-group{
  >.h-button{
    &:not(:first-child){
      margin-left:-1px
    }
  }
}
复制代码

可是这样子,当咱们的鼠标移到第一个button上时,他右边的border就会被左移的button所覆盖,只能看到三边border

image-20190930220116938

咱们能够给hover状态的button加一个相对定位,并让其层级上升

.h-button{
  &:hover{
    position:relative;
    z-index:1;
  }
}
复制代码

接着咱们要考虑一个问题,若是用户没有按要求进行嵌套button的话,可能会出现一些样式上的问题,因此咱们能够在vue进行渲染前,加一个判断

// button-group组件
<script>
  export default{
    mounted(){
  		//遍历该组件的子元素
      for(let node of this.$el.children){
        let name = node.nodeNmae.toLowerCase();
        if(name!=='button'){
          console.warn(`h-button-group的子元素应该是button,而你却写了${name}`)
        }
      }
    }
  }
</script>
复制代码

如此,只要用户使用button-group时,内部不是嵌套button的话,就会在控制台出现警告

一样最后要在app.js中去注册该button-group的全局组件

import Vue from 'vue'
import ButtonGroup from './src/button-group'
Vue.component('h-button-group',ButtonGrouop)
复制代码

5、添加icon组件

1.使用iconfront.cn

咱们能够在阿里的开源的icon的网站 iconfont.cn里找咱们喜欢的icon

image-20190930221842545

输入关键词找到咱们须要的icon,将其添加至购物车

屏幕快照 2019-09-30 下午10.21.13

添加完后,点击右上角的购物车,

屏幕快照 2019-09-30 下午10.23.45

添加至项目,没有项目的,则新建一个

屏幕快照 2019-09-30 下午10.24.33

而后点击个人项目

屏幕快照 2019-09-30 下午10.25.54

选择symbol

屏幕快照 2019-09-30 下午10.27.28

点击icon,你能够对icon进行命名,也能够调整icon的大小

屏幕快照 2019-09-30 下午10.28.52

屏幕快照 2019-09-30 下午10.29.20

选择编辑项目,能够编写icon名的前缀,和font-family

复制这段代码

image-20190930223222384

在index.html文件中导入

<script src="//at.alicdn.com/t/font_1434472_h9r3sjw6fdn.js"></script>

关于symbol的怎么使用,请看官方文档

https://www.iconfont.cn/help/detail?spm=a313x.7781069.1998910419.16&helptype=code

建立icon组件

src文件夹下,新建一个icon.vue 的文件,

<template>
    <svg class="h-icon" aria-hidden="true">
        <use xlink:href="#icon-xxx"></use>
    </svg>
</template>
复制代码

icon 应该是动态的,使用props来动态改变

<template>
    <svg class="h-icon" aria-hidden="true">
        <use :xlink:href="`#i-${name}`"></use>
    </svg>
</template>
<script>
    export default {
        props:{
            name:{
                type:String,
                default:'',
              //对icon 进行过滤,不在数组里的icon,则会提示错误
                validator(value){
                    return ['loading','right','down','setting','thumbs-up','left','download'].indexOf(value)!=-1
                }
            }
        }
    }
</script>
复制代码

将icon的大小设置为全局的基本字体大小

.h-icon{
  height:var(--font-size-base);
  width:var(--font-size-base)
}
复制代码

在app.js中去注册全局的icon组件

import Icon from './icon'
import Vue from 'vue'
Vue.component('h-icon',Icon)
复制代码

6、icon和button组合

button中咱们能够经过icon这个属性来决定button内部使用什么icon

<template>
    <button>
    	<h-icon class='icon' :name='icon'></h-icon>
    </button>
</template>
<script>
  export default{
    props:{
      icon:{
        type:String
      }
    }
  }
</script>
复制代码

icon可能在左右两边,咱们能够在button组件设置一个iconPosition的prop来决定icon的位置

屏幕快照 2019-09-30 下午11.11.20

<template>
    <button :class='["h-button",{[`icon-${iconPosition}`]:true}]'>
      <h-icon class='icon' :name='icon'></h-icon>
      <div class='content'>
        <slot></slot>
      </div>
    </button>
</template>
<script>
 export default{
    props:{
      iconPosition{
      	type:String,
      	default:'left',
      	validator(value){
    			return ['left','right'].indexOf(value)!=-1
  		}
      }
    }
  }
</script>
<style>
  .h-button{
    display:inline-flex;
    &.icon-left{
      .icon{
        order:1;
        margin-right:.2em
      }
      .content{
        order:2
      }
    }
    &.icon-right{
      .icon{
        order:2;
        margin:0;
        margin-left:.2em
      }
      .content{
        order:1;
      }
    }
  }
</style>
复制代码

7、点击button会出现icon会切换loading

在button组件中添加loading的icon,而且loading和原有的icon是互斥关系

<template>
...
<h-icon name="loading" class="icon" v-if="loading"></h-icon>
<h-icon :name="icon" class="icon" v-if="icon&&!loading"></h-icon>
...
</template>
<script>
...
loading:{
 type:Boolean,
 default:false
}
</script>

复制代码

若是咱们这样添加事件,vue并不会响应

<h-button :loading="loading" icon="down" icon-position="right" @click='loading=!loading'>down</h-button>
复制代码

由于h-button是一个自定义组件,vue并不知的你点击的是自定组件中个哪一个html标签

因此咱们要在自定义组件内部本身触发click事件

<template>
	<button @click='$emit('click')'>
  </button>
</template>
复制代码

结语

做者:胡志武

时间:2019/09/30

若是本文有错漏的地方,请各位看官指正。若是决定本文对你有那么一点点帮助,请点赞哦!

若是要转载请注明出处

相关文章
相关标签/搜索