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

第四集: 從零開始實現(button組件2)

本集定位:
以前一直在忙別的事情, 如今終於閒下來, 好好把這個庫的文章寫一下
本篇目的是承接上文, 把button組件的功能所有實現css

1: 爲button添加icon
按鈕的icon很重要, 如今通常的按鈕都帶個圖案,由於這樣符合人腦的快捷思惟, 方便理解與記憶.vue

<button class="cc-button"
          @touchstart='touchstart($event)'
          :class="[ 
          sizeType,
          type ? 'cc-button--' + type : '',
    {
      'is-left':left,
      'is-right':right,
      'is-centre':centre,
      'is-disabled':disabled,
    }]"
          :type="nativeType"
          @click="click">
    <!-- 圖標按鈕 -->
    <ccIcon v-if="icon"  // 有沒有
            :name='icon' // 有什麼樣的
            :color="realyIconColor"  // 什麼顏色的
            style="margin-right:2px" />  // 與文字有點距離
    <slot />
  </button>

計算realyIconColor
icon有默認的顏色, 可是若是按鈕式禁用狀態, 那麼icon也要相應的置灰node

computed: {
    realyIconColor() {
      if (this.disabled) return "#bbbbbb";
      else return this.iconColor;
    }
  }

圖片描述

2: icon的位置
不多遇到須要上下左右佈局的icon, 若是須要的話.
方案一: 移動<slot>標籤, 或是具名slot標籤
方案二: 多寫幾個icon組件, 經過判斷決定顯示誰git

3: hover效果
方案一:github

  1. hover的時候出現灰色蒙層效果
  2. 被點下時, 按鈕縮小動畫
&: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.1)
         }
    }

效果圖
圖片描述
方案二:web

  1. hover出現金屬光澤, bulingbuling的,金屬光澤.
  2. 被點下時, 按鈕縮小動畫

綜上分析, 金屬光澤流過可能成爲一個公用屬性, 那麼我直接寫一個公共的樣式吧 "cc-bling"
個人思路:算法

  1. 嘗試使用漸變的背景顏色, 而後用 ackground-position-x 控制背景的右移
    此方案實踐起來不舒服, 並且並無作到'解耦合'的設計原則, 因此不用了
  2. 僞元素, 用一個僞元素加上背景色, 而後把這個元素從左至右劃過, 同時用動畫把它作得傾斜30度
    這樣雖然多了個元素, 可是跟父級解耦了, 值得說的一點是, 傾斜以後高度不夠盛滿了, 簡單粗暴的
    方式就是把高度定位多一些的, 這樣旋轉也不會致使高度不夠的狀態了.

let'go瀏覽器

<button class="cc-button"
  :class="[
    {
      'is-bling':bling, // 加了一個接受 是否金屬光澤的屬性
      'is-left':left,
      'is-right':right,
      'is-centre':centre,
      'is-disabled':disabled,
    }]"
  </button>
 bling:Boolean, // 條紋

在button.scss;裏面添加服務器

@at-root {
        @include commonType(cc-button--);
        .is-bling {
        //此屬性名在hover的時候才進行bling操做
            &:hover {
                @extend .cc-bling;
            }
        }
    };

animation.scss
定義一個從左至右的動畫dom

@keyframes bling{
    0% {
      left: 0;
    }
    100% {
      left: 300%;
    }
  }

extend.scss
定義具體的樣式把

.cc-bling {
    &:after {
        content: '';
        position: absolute;
        background-image: linear-gradient(to right, rgb(232, 229, 229), white);
        left: 0;
        top: -20px; // 避免傾斜的時候頭部漏出尖角
        width: 15px;
        height: calc(100% + 30px); // 避免旋轉時候出現高度不夠的狀況
        transform: rotate(-30deg);
        animation-name: bling;
        animation-duration: 1s; // 總用時
        animation-iteration-count: infinite; // 無限循環
        animation-timing-function: linear; // 勻速
    }
}

效果圖, 是動態的, 從左至右劃過.
圖片描述
4: 防抖與節流
介紹: 這種節流與防抖都是用戶本身作的, 至少按鈕這種東西本套組件庫就是要組件來作.
使用場景:

  1. 有一次,我寫註冊登陸頁面, 若是用戶在註冊的時候, 快速的點擊了兩下, 雖然跳到登陸成功頁面, 可是會彈出彈框, "該手機已被註冊", 原來是因爲第一個請求把手機註冊了, 因此接下來的點擊事件的請求後臺固然返回的是已註冊, 因此這裏就須要這樣的處理, 每次點擊有效以後的點擊n秒內無效, 防止連點, (防止變速齒輪, 想起了流星蝴蝶劍);
  2. 咱們公司19年搞了個搶購活動, 可能發生這樣的場景, 用戶守着搶購按鈕, 不斷地點擊, 咱們web端須要在每次用戶點擊的時候詢問後臺'活動開始了麼?', 沒開始就給用戶彈tosat(下一章就作這個組件了),開始了才進入活動也或是訂單頁, 可是, 用戶若是是個金手指, 瘋狂把玩搶購鍵, 那就會發出大量的請求了,

我來講一下:
第一: 爲何不使用後臺返回的活動開始時間與本地的事件進行比對??

緣由是用戶的本地時間並非一個值得信賴的量, 平時能夠做爲一個參考, 可是像搶購這種分秒必爭的事情, 就要讓用戶與服務器時間同步起來了.

第二: 爲何不在第一次請求以後把時間戳記錄下來, 本地用計時器模擬計時??

緣由是某些瀏覽器環境下, 用戶切出程序之類的一些操做, 他會殺掉計時器, 致使計時不許, 而這種問題暫時沒法解決, 也監控不到, 因此爲了分秒必爭保險起見.

最後只能是每次都請求一下, 那就須要, 好比說 每600毫秒內, 只讓用戶的點擊有效一次.

咱們就不能單純的寫click事件了,要抽離出來進行蹂躪☺️.
dom

<button class="cc-button"
     @click="click">
  </button>

接值

props: {
    ...,
    shake: Number, // 防抖的秒數
    throttle: Number, // 節流, 請輸入秒數
    clickId: [String, Number], // 相同id的組件走一套計時.
}

事件

click() {
    // 根據用戶的輸入, 來決定怎麼計時.
    // 值得一提的是, clickId 相同的話咱們是統一計時的, 
    // 好比說: 三個按鈕, 點了其中一個, 其餘的幾個在規定時間內,都會不可點擊
      let clickType, num;
      if (this.throttle) {
        clickType = 1;
        num = this.throttle;
      } else if (this.shake && this.shake > 0) {
        clickType = 2;
        num = this.shake;
      } else if (this.shake && this.shake < 0) {
        clickType = 3;
        num = this.shake * -1;
      }
      prevent(
        this.clickId,
        () => {
          this.$emit("click");
        },
        num,
        clickType
      );
    },

在以前的工做中本身寫過一個防抖與節流的函數, 此次就直接拿來用了

let preventList = {}
const prevent = function(id, obj, time, model = 1) {
  switch (model) {
    case 1:
      model1(id, obj, time)
      break;
    case 2:
      model2(id, obj, time)
      break;
    case 3:
      model3(id, obj, time)
      break;
    default:
  }
}

// 模式1 無論點多少下每隔time秒,觸發一次
function model1(id, obj, time) {
  if (preventList['can' + id]) return
  obj()
  preventList['can' + id] = true
  preventList['time' + id] = setTimeout(() => {
    preventList['can' + id] = false
  }, time)
}

// 模式2 每次動做都有time的延時再執行,也就是全部點擊完事的時候執行一個
function model2(id, obj, time) {
  clearTimeout(preventList['time' + id])
  preventList['time' + id] = setTimeout(() => {
    obj()
  }, time)
}

// 默認的模式, 模式3, 第一下點擊觸發, 以後時間內不觸發
function model3(id, obj, time) {
  if (preventList['can' + id]) {
    clearTimeout(preventList['time' + id])
  } else {
    obj()
    preventList['can' + id] = true
  }
  preventList['time' + id] = setTimeout(() => {
    preventList['can' + id] = false
  }, time)

}

export default prevent

具體的使用

圖片描述

//後續涉及到防抖與節流的事件也都是走的這套程序;

下一篇

  1. toast的封裝, 經過封裝toast讓我鞏固了好多'芝士'
  2. 組件的另外一種寫法

end
這段時間做者辭職, 專心學源碼, 練習算法, 重學js, 重學node,重作本身的打包工具, 反正挺忙的,接下來的時間與精力主要放到這套組件上 同時也會出一些算法啊, 心得之類的文章, 歡迎同窗們一塊兒交流, 一塊兒變得更優秀.

github:連接描述
我的網站: 連接描述

相關文章
相關標籤/搜索