用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

若是本文有錯漏的地方,請各位看官指正。若是決定本文對你有那麼一點點幫助,請點贊哦!

若是要轉載請註明出處

相關文章
相關標籤/搜索