第三集: 從零開始實現一套pc端vue的ui組件庫(button組件其一)

第三集: 從零開始實現(button組件1)

本集定位:
爲何要叫1那, 由於我感受這個組件細節比較多, 應該會講不少內容, 因此先把基礎功能在這一集實現, 下集去作拓展.
button組件
這是一個基本上每一個工程都會用到的組件, 傳統的button千篇一概的樣式, 彷彿按鈕不作的同樣就無法用似的, 我偏要加一些別人沒加過的樣式來玩, 作過項目的小夥伴都會遇到一個問題, 防抖與節流, 而這麼主要的功能居然沒有ui組件庫的按鈕來集成, 此次我就把這兩個功能集成到按鈕式搞一搞, 😁開始行動吧.
建立組件基本結構
繼續秉承bem的思想, button整體結構以下:
圖片描述css

index.js文件 仍是老套路, 組件的name屬性很重要.vue

import Button from './main/button.vue'

Button.install = function(Vue) {
  Vue.component(Button.name, Button);
};

export default Button

button.vuegit

<template>
  <button class="cc-button">
    <slot />
  </button>
</template>

載體選用button原生標籤, 不選擇div標籤去模擬, 由於button自己有不少原生屬性, 並且語義化也要好過div. slot標籤固然是爲了接到用戶在button中間輸入的信息.github

按鈕第一條, 固然是先分個類型開開胃數組

<template>
  <button class="cc-button"
          :class="[
            type ? 'cc-button--' + type : ''
          ]"
          :type="nativeType"
    <slot />
  </button>
</template>
<script>
export default {
  name: "ccButton",
  props: {
    type: String, // 類型
    nativeType: String, // 原生的類型仍是要給的
  }
};
</script>

1: vue的class屬性很強大的, 他能夠數組的形式, 字符串的形式, 對象的形式, 而我採用的是 數組套一切的形式, 接下來對象類型也會在這個class數組裏面使用.
2: 原生的type也要接受, 由於用戶會有這樣的需求的, 我把它命名爲nativeType,跟element同樣.
3: 定義幾種相應的type樣式, 這個type屬性沒作校驗, 由於就算用戶不按照我給出的範圍傳值, 無非就是樣式沒變化, 沒有其餘影響的, 接下來就是定義按鈕的type樣式了.sass

Button.scss框架

@import './common/var.scss';   // 引入定義的全部變量
@import './common/mixin.scss'; // 引入全部的函數
@import './common/extend.scss'; // 引入公共樣式
@include b(button) {
    cursor: pointer;           // 鼠標變小手
    align-items: center;       // 軸對齊
    display: inline-flex;    // 開啓flex模式, 因爲還要保持行的特性, 因此是inline-flex
    vertical-align: middle;    // 中對齊, 爲了之後的icon準備的
    justify-content: center;   // 居中
    background-color: white;   // 白色
    outline: 0;                 // 去掉聚焦時的輪廓
    border-radius: 6px;         // 感受圓角6仍是挺友好的, 沒有作成可配置
    transition: all 0.1s;       // 動畫固然要有, 交互體驗很重要
    &:active {             // 點擊的時候
        box-shadow: none;   // 嘿嘿這個是個人ui組件獨有的風格
        opacity: 0.7;        // 微微一暗, 以示點擊到了
        transform: translateX(2px) translateY(2px) scale(0.9); // 會有個小小的位移
    }
    &:hover { // 懸停變色
        background-color:rgba(0,0,0,0.06)
    }
    @include commonShadow($--color-black); // 這個下面會說👇
    @at-root { 
        @include commonType(cc-button--)  // 這個下面會說👇
    };
}

var.scss文件,本項目採用的基本配色, 畢竟不是專業的你們見諒😁函數

// 基本色
$--color-black:#000000 !default;
$--color-white:#FFFFFF !default;
// 基本色鮮豔
$--color-nomal:#409EFF !default;
$--color-success:#7CCD7C !default;
$--color-warning:#FFB90F !default;
$--color-danger: #FF0000 !default;
$--color-disabled: #bbbbbb !default;
$--color-difference: #F5F7FA !default;
// 字體
$--size-big: 16px;
$--size-nomal: 15px;
$--size-small: 14px;
// 輸入框
$--color-input-placeholder:#aaa

!default;這個東西的意思是優先級最低, 能夠被其餘的頂掉.字體

mixin.scssflex

@mixin commonShadow($color) {
  @if $color== 'success' {
    $color: $--color-success;
  }

  @if $color== 'warning' {
    $color: $--color-warning;
  }

  @if $color== 'danger' {
    $color: $--color-danger;
  }

  @if $color== 'disabled' {
    cursor: not-allowed;
    $color: $--color-disabled;
  }

  color: $color;
  border: 1px solid $color;
  box-shadow: 2px 2px $color;
}


@mixin commonType($name) {
  @each $type in (success, warning, danger) {
    .#{$name}#{$type} {
      @include commonShadow($type);
    }
  }
}

1: 先說commonShadow這個函數吧, 這個是本套ui框架的特點樣式(慘不忍睹) , 就是想作點樣子不同的, 這個函數很簡單, 會根據傳進來的不一樣$color值來進行樣式的返回, 只要使用這個函數就會爲元素加上陰影效果, 注意@if後面不要習慣性的協商小括號
2: 因爲樣式不止一個, commonType函數應運而生, 他把我定義的幾種樣式類型以數組的形式進行循環,@each後面接的是每次循環出來的item, in 後面的()裏面的是要被循環的量
3: .#{$name}#{$type}就是傳進來的量與item的拼接, #{}就能夠在sass裏面進行拼接, 並非id的意思, 我傳入的是 'cc-button--' 因此這個函數定義了 'cc-button--success', 'cc-button--warning','cc-button--danger' 三種樣式加上了對應顏色的陰影效果, 如圖

按鈕效果展現

點擊等更多效果能夠來個人博客查看 哈哈😁;

@at-root
這個關鍵詞沒有使用過的小夥伴注意了
1: 這個關鍵詞做用是, 使樣式跳出{}大括號範圍, 好比我在 cc-button這個class名下寫的樣式, 而後我用以下寫法:

.cc-button{
   .cc-button--success{}
}

以上寫法的意思是, .cc-button裏面有個class爲.cc-button--success的元素, 爲這個元素賦予相應屬性, 這顯然不是我想要的,

.cc-button{
  @at-root { 
   .cc-button--success{}
  }
}

至關於

.cc-button{
       
    } 
.cc-button--success{
}

因此我說他至關與跳出{}大括號.

點擊與disabled禁用屬性
我把這個屬性排在第二位來寫, 由於有點擊就有不可點擊與其相對, 這屬於的最基本的功能.

<button class="cc-button"
          @touchstart='touchstart($event)'
          :class="[
          type ? 'cc-button--' + type : '',
    {
      'is-disabled':disabled,
    }]"
          :type="nativeType"
          @click="$emit("click")">
    <slot />
  </button>
  1. touchstart莫名其妙出現個是否是很詫異, 由於我發現蘋果手機不加這個屬性的話, 按鈕是沒法點擊的, 保險起見仍是加上吧, 萬一運營人員在家改點東西, 結果發現手機上點不了, 就壞菜了.
  2. 在class屬性的數組裏面加入一個對象也是可使用的, vue的強大解析能力, 若是用戶傳了disabled, 就使用is-disabled這個class名
  3. @click事件要給用戶返回,由於這個是組件, 若是用戶想要觸發點擊事件, 須要本身寫.native修飾符, 避免用戶的多餘代碼, 這裏我來主動處理, 這個click事件接下來還要進行重構, 由於要配合節流與防抖
  4. 小技巧: disabled屬性我, 默認是布爾值, 這樣用戶若是隻是傳了個disabled 就是true了, 不用寫:disabled='true', 若是我不寫默認是布爾類型的話, 是undefined, 爲了用戶方便書寫的小技巧.
disabled: Boolean

禁用樣式的屬性Button.scss改裝

&:not(.is-disabled) {
        &:active {
            box-shadow: none;
            opacity: 0.7;
            transform: translateX(2px) translateY(2px) scale(0.9);
        }
        &:hover {
            background-color:rgba(0,0,0,0.06)
        }
    }
    @include when(disabled) {
        @include commonShadow(disabled);
    }

1: 只有在不是禁用狀態的時候, 纔有點擊效果, 懸停效果
2: 當disabled時, 才顯示disabled的專屬皮膚

when函數

@mixin when($state) {
  @at-root {
    &.#{$state-prefix + $state} {
      @content;
    }
  }
}

1: 見名知意, 當什麼什麼的時候, 用到了@at-root 屬性, 忘了的去上面看下, @content;表示的是類裏面的樣式內容,很神奇吧!

.box{
   color:red;
}

1: 上面的color:red; 就是@content;
2: 因此說這個函數就是一個命名函數, 能夠抽象出前綴, 並且是在{}外的平級樣式.
3: 禁用狀態有cursor: not-allowed;屬性, 讓鼠標呈現禁用狀態

左中右按鈕 (文章字數寫多了好卡)

  1. 按鈕常常被拿來組合着用, 好比整齊的一排 , 那麼我就第一想法就是給他個圓角
  2. 從用戶體驗的角度來講, 這個跟disabled屬性應該是平級的, 把關鍵詞寫在標籤裏面就能生效,也是布爾類型
  3. 命名與element同樣採用is-的形式, 分爲is-left is-right is-centre
<template>
  <button class="cc-button"
          @touchstart='touchstart($event)'
          :class="[
          type ? 'cc-button--' + type : '',
    {
      'is-left':left,
      'is-right':right,
      'is-centre':centre,
      'is-disabled':disabled,
    }]"
          :type="nativeType"
          @click="click">
    <slot />
  </button>
</template>
  1. 爲何要分着寫 ,由於若是靠一個變量來控制的話又會出現用戶 要寫 :xxx='xxx'這種寫法, 我是用戶我沒法接受

樣式:

@include when(left) {
        border-radius: 16px 0 0 16px;
    }
    ;
    @include when(right) {
        border-radius: 0 16px 16px 0;
    }
    ;
    @include when(centre) {
        border-radius: 0;
    }

無非是調了一下圓角, 可是特別好玩

效果以下⬇️

圖片描述
圖片描述

按鈕大小

這個不少ui庫都有時間, 那我也實現一下吧, 感受通常般.

:class="[ 
          sizeType, // 新加一個屬性
          type ? 'cc-button--' + type : '',
    {
      'is-left':left,
      'is-right':right,
      'is-centre':centre,
      'is-disabled':disabled,
    }]"
    
    props: {
         size: {
          typr: String,
          default: "normal"
        }
    }
   computed: {
    sizeType() {
      let sizeList = ["big", "small"];
      if (sizeList.includes(this.size)) return "size-" + this.size;
      return "size-normal";
    }
  }
  1. size分爲 big small normal ,對用戶的輸入進行驗證, 不經過就返回正常大小
  2. 這個沒啥技術含量
&.size-big {
        font-size: $--size-big;
        padding: 6px 11px;
    }
    &.size-normal {
        font-size: $--size-nomal;
        padding: 4px 8px;
    }
    &.size-small {
        font-size: $--size-small;
        padding: 2px 6px;
    }

未完待續

  1. 下一篇繼續玩按鈕組件, 主要有爲按鈕添加icon, 防抖與節流
  2. 文章字數多了, 電腦好卡

github:項目地址
我的博客:我的博客

相關文章
相關標籤/搜索