05 - Vue3 UI Framework - Button 組件


官網基本做好了,接下來開始做核心組件

返回閱讀列表點擊 這里

目錄准備

在項目 src 目錄下創建 lib 文件夾,用來存放所有的核心組件吧。然后再在 lib 文件夾下創建 Button.vue 文件。

您也可以進行結構化設計,比如,這里就不進行了。

|-lib
  |-Button
  	|- Button.vue
  	|- Button.ts
  	|_ Button.scss

需求分析

慣例先行需求分析

  1. 多種類基礎 Button,包含警告、成功、危險等
  2. 允許設置 Button 為禁用狀態
  3. 不止有傳統 Button,還可以有文字或鏈接形式
  4. 當處於加載中,Button 應當顯示
  5. 有不同的尺寸可供選擇
  6. 應當允許更換顏色
  7. 當鼠標放置於 Button 上、鼠標按下未松開、處於加載中等狀態時,應當變更背景色
  8. 允許用戶自定義 Button 上顯示的文本

那么可以整理出以下參數表格

參數 含義 類型 可選值 默認值
level 默認類型 string default / plain / primary / success / info / warning / danger default
disabled 是否禁用 boolean false / true false
theme 式樣 string button / link / text button
loding 是否加載中 boolean false / true false
size 尺寸 string middle / small / large middle
color 顏色 string 任意合法顏色值 #f3678e

第 7 條,可以通過設置一個遮罩層來實現,只要遮罩層變色,背景色也等效變色

第 8 條,可以通過插槽實現,注意 vue3 不建議使用具名插槽

骨架

容易得到如下骨架

<template>
  <button
    class="jeremy-button"
    :theme="theme"
    :level="level"
    :size="size"
    :style="{ '--color': color }"
    :disabled="disabled"
    :loading="loading"
  >
    <div class="jeremy-button-mask"></div>
    <span class="jeremy-button-loadingIndicator" v-if="loading"></span>
    <slot></slot>
  </button>
</template>

首先,本質應當是一個 button 元素,在此基礎上,將參數列表中整理出來的每個參數,都使用 v-bind 綁定到 button

注意,此處綁定 color,必須是如上例一樣,綁定到 --color 屬性上,才可以在 css 中使用 css3 語法 var() 讀取,在 css 小節會再解釋,此處略

之后,在 button

  1. 放置一個遮罩層,用於變色
  2. 放置一個”加載中”的動畫,用於在加載中狀態下顯示
  3. 放置一個默認插槽,用於傳遞用戶自定義的文本

然后為上述元素配置各自的 class 名稱,骨架就完成了。

功能

顯然,參數列表中整理出來的內容,一定來自引用該組件的地方的傳入,先根據參數列表,寫好 ts 聲明:

declare const props: {
  theme?: "button" | "link" | "text";
  level?:
    | "default"
    | "plain"
    | "primary"
    | "success"
    | "info"
    | "warning"
    | "danger";
  size?: "middle" | "small" | "large";
  color: string;
  disabled: boolean;
  loading: boolean;
};

然后在 export default 中,寫入我們的參數

export default {
  install: function (Vue) {
    Vue.component(this.name, this);
  },
  name: "JeremyButton",
  props: {
    theme: {
      type: String,
      default: "button",
    },
    level: {
      type: String,
      default: "default",
    },
    size: {
      type: String,
      default: "middle",
    },
    color: {
      type: String,
      default: "#8c6fef",
    },
    disabled: {
      type: Boolean,
      default: false,
    },
    loading: {
      type: Boolean,
      default: false,
    },
  },
};

對於事件綁定,因為我們設計的組件只有一個唯一的根元素,所以對於外部傳遞過來的事件,會自動綁定到組件的根元素上面。

樣式表

注意 :UI 庫的樣式表一般不要加 scoped 修飾符,為了盡可能減少對用戶樣式表的影響,方便用戶 DIY

特別注意 : button 元素會有默認黑色外邊框,不屬於 border,必須通過 outline: none; 才能消除

然后,我們使用 css3var() 語法,取得我們通過 ts 綁定到 style 上的 --color 屬性

為什么是 --color 而不是 color ?因為 var() 語法要求這個參數必須是 -- 開頭,才可以正常訪問到

對於遮罩層,采用淡出到白色即可實現,原理此處不解釋了

最后,對於多種不同的 button,可以使用 scss 提供的 mixin / include 語法來實現,完整代碼如下:

$theme-color: var(--color);
$base-mask: fade-out(#fff, 0.7);
$active-mask: fade-out(#fff, 0.5);
$h: 32px;
$radius: 4px;

@keyframes jeremy-spin {
  0% {
    transform: rotate(0deg);
  }
  100% {
    transform: rotate(360deg);
  }
}
.jeremy-button {
  position: relative;
  display: inline-block;
  padding: 10px 16px;
  color: white;
  border-radius: $radius;
  border: none;
  font-size: 16px;
  cursor: pointer;
  white-space: nowrap;
  transition: background-color 250ms;
  outline: none;
  :focus {
    outline: none;
  }
  > .jeremy-button-mask {
    position: absolute;
    display: inline-block;
    height: 100%;
    width: 100%;
    left: 0;
    top: 0;
    border-radius: $radius;
    &:hover {
      background: $base-mask;
    }
  }
  &[loading="true"],
  &[disabled] {
    cursor: not-allowed;
    > .jeremy-button-mask {
      pointer-events: none;
    }
  }
  > .jeremy-button-loadingIndicator {
    width: 14px;
    height: 14px;
    display: inline-block;
    margin-right: 4px;
    border-radius: 8px;
    border-style: solid;
    border-width: 2px;
    animation: jeremy-spin 1s infinite linear;
  }
}

@mixin layout($color) {
  $loading-color: fade-out(black, 0.7);

  background: $color;

  &:active {
    > .jeremy-button-mask {
      background: $active-mask;
    }
  }
  > .jeremy-button-loadingIndicator {
    border-color: $loading-color $loading-color $loading-color transparent;
  }
  &[loading="true"],
  &[disabled] {
    > .jeremy-button-mask {
      background: $base-mask;
    }
  }
}
.jeremy-button[theme="button"] {
  $color: $theme-color;

  @include layout($color);
}
.jeremy-button:not([theme="button"]) {
  padding: 0;
  background: white;
  color: black;
  &:hover {
    color: $theme-color;
  }
}
.jeremy-button[theme="link"] {
  text-decoration: underline;
}
.jeremy-button[level="plain"] {
  $base-color: $theme-color;
  @include layout(white);
  color: black;
  > .jeremy-button-mask {
    border: 1px solid rgb(187, 187, 187);
  }

  &:not([loading="true"]):not([disabled]) {
    &:hover {
      > .jeremy-button-mask {
        border: 1px solid $base-color;
      }
      color: $base-color;
    }
  }
}
.jeremy-button[level="primary"] {
  $color: #29adfa;

  @include layout($color);
}
.jeremy-button[level="success"] {
  $color: rgb(103, 194, 58);

  @include layout($color);
}
.jeremy-button[level="info"] {
  $color: #808080;

  @include layout($color);
}
.jeremy-button[level="warning"] {
  $color: rgb(230, 162, 60);

  @include layout($color);
}
.jeremy-button[level="danger"] {
  $color: rgb(245, 108, 108);

  @include layout($color);
}
.jeremy-button[size="large"] {
  padding: 14px 24px;
}
.jeremy-button[size="small"] {
  padding: 6px 10px;
}

以上,button 組件就完成了! :happy:

測試一下

image-20211213131430347

項目地址 🎁

GitHub: https://github.com/JeremyWu917/jeremy-ui

官網地址 🌍

JeremyUI: https://ui.jeremywu.top

感謝閱讀 ☕


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM