官網基本做好了,接下來開始做核心元件
返回閱讀列表點選 這裡
目錄準備
在專案 src
目錄下建立 lib
資料夾,用來存放所有的核心元件吧。然後再在 lib
資料夾下建立 Button.vue
檔案。
您也可以進行結構化設計,比如,這裡就不進行了。
|-lib
|-Button
|- Button.vue
|- Button.ts
|_ Button.scss
需求分析
慣例先行需求分析
- 多種類基礎
Button
,包含警告、成功、危險等 - 允許設定
Button
為禁用狀態 - 不止有傳統
Button
,還可以有文字或連結形式 - 當處於載入中,
Button
應當顯示 - 有不同的尺寸可供選擇
- 應當允許更換顏色
- 當滑鼠放置於
Button
上、滑鼠按下未鬆開、處於載入中等狀態時,應當變更背景色 - 允許使用者自定義
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
內
- 放置一個遮罩層,用於變色
- 放置一個”載入中”的動畫,用於在載入中狀態下顯示
- 放置一個預設插槽,用於傳遞使用者自定義的文字
然後為上述元素配置各自的 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;
才能消除
然後,我們使用 css3
的 var()
語法,取得我們通過 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:
測試一下
感謝閱讀 ☕