細說UI組件庫中的“開關”

目前,流行的UI組件庫無非cube-ui、elementUI、iview…
一款優秀的組件庫其實現必包含:性能、兼容、適應性等一系列指標。
今天筆者就給各位分析一下項目中常見的一個組件 —— 開關!及其實現。

fg

筆者曾做過一個vue項目,其中用到cube-ui組件庫,在裏面,開關是這樣實現的:

<cube-switch v-model="swich" class="abc" @input="inputHandle">
</cube-switch>

input事件是其內置事件:默認傳參true/false —— 當前開關按鈕的狀態。
如圖:
kg1

其實事後想想,在項目中一味的用現成組件庫不是一個明智的選擇——組件庫良莠不齊,而且大多都有自己的限制條件,比如上面所說cube-ui就是在vue中使用的組件庫。

這也是後來筆者寫自己的UI庫的原因 —— 下面實現的開關就截自那裏:

fg

開關的實現

上面我們可以知道需要實現的樣式。這樣的話,筆者認爲最直接的方法莫過於:用兩個元素分別充當開關的背景和開關的圓形按鈕,再通過用不同的 class 來控制開關不同狀態下的樣式,甚至可以和菜單中的單選和多選功能一樣:在開關裏再隱藏一個 input 元素來記錄開關的狀態值。

這樣的思路無論從效果上還是功能上來說都是可行的。但是不是筆者想要的 —— 否則的話也就不必寫這篇文章了。。。


讓我們再來分析一下組件庫中的開關:點擊滑動、需記錄值、考慮性能。
結合這三點來看,我們完全可以只用一個 input 標籤來實現:點擊滑動可以用CSS3的@frames實現、記錄值這件事 input 本身就可以,至於第三點“考慮性能”…筆者在下面再爲各位揭曉:

<div class="mxc-menu">
	<a class="mxc-menu-item">
		<p class="mxc-menu-name">這一行是文字說明,下面一行是重點</p>
		<input class="mxc-switch" type="checkbox">
	</a>
</div>

如上我們沒有給任何樣式,此時應該是這樣的:
mmm

沒錯,默認的 input 元素就是個選擇框,我們如果想把它改造成一個開關的樣式,就要去掉它“默認”的樣式:

/**取消webkit內核中選擇框的默認樣式**/

/* 去掉webkit內核裏默認的樣式 */
-webkit-appearance: none;
/* 去掉webkit內核裏默認的點擊效果 */
-webkit-tap-highlight-color: rgba(0,0,0,0);

之後,這個 input 元素就變成了一個標準(普通)的盒子了。並且可以通過這個 input 是不是 checked 狀態來區分盒子的(點擊與否)樣式:

.mxc-menu > .mxc-menu-item > .mxc-switch{
	position: relative;
	box-sizing: content-box;
	width: 2.6rem;
	height: 1.4rem;
	border: 1px solid #ccc;
	outline: 0;
	border-radius: .75rem;
	background-color: rgba(0,0,0,.1);
	/* 去掉webkit內核裏默認的樣式 */
	-webkit-appearance: none;
	/* 去掉webkit內核裏默認的點擊效果 */
	-webkit-tap-highlight-color: rgba(0,0,0,0);
}
.mxc-menu > .mxc-menu-item > .mxc-switch:checked{
	border-color: #07C160;
	background-color: #07C160;
}

在這段代碼裏,我們先是把 .mxc-switch 這個 input 元素當成容器來用 —— 雖然這種用法不是很常規,但 input 確實是可以這樣使用的。
然後這裏要注意下 checkbox 類型的 input 元素在有些瀏覽器裏默認會是怪異盒模型,所以這裏要【指定】成爲標準盒模型,以便計算圓形按鈕的大小和位置。

不管用戶初始時是否選中了checkbox,都需要這樣做 —— 反正沒有壞處,你說呢

最後我們使用了 :checked 選擇器來區分按鈕的背景和邊框。此時我們已經完成了1/3了。


接下來似乎就是重要的一步了:點擊後元素上的小圓點來回移動!
因爲筆者選擇了“只用一個 input 標籤”的方式實現,所以這裏很自然能想到:CSS中的僞類選擇器
事實上,只要給 ::after 元素加上屬性“content:" ";”,就可以把它也當做一般的div來用了

.mxc-menu > .mxc-menu-item > .mxc-switch::after{
	content:" ";
	position: absolute;
	top: 0;
	left: 0;
	width: 1.4rem;
	height: 1.4rem;
	border-radius: .7rem;
	background-color: #FFFFFF;
	box-shadow: 0 0 2px #999;
}
.mxc-menu > .mxc-menu-item > .mxc-switch:checked::after{
	left: 1.2rem;
}

這段代碼中需要注意的是:我們使用了 box-shadow 代替 border 來區分元素邊界 —— 爲了達到“立體”的效果。

box-shadow 屬性是 CSS3 中規定的屬性,是用來給盒子的邊框添加陰影效果的。這個屬性的語法是“box-shadow: px1 px2 px3 color;”,這個屬性中幾個值的作用如下:
px1 的值用來指定陰影的水平位移,可以是負值。
px2 用來指定陰影的豎直位移,也可以是負值。
px3 用來指定陰影的模糊半徑,也就是陰影的模糊程度。
color 就是用來指定陰影的顏色。
在使用這個屬性的時候有三點要注意:box-shadow 只是盒模型的一種顯示效果,不會影響盒子的尺寸和位置;效果可疊加,中間用逗號隔開;屬性消耗比較大,不建議大批量的使用。

此時我們已經完成了2/3。

現在點擊這個開關,通過控制 checkbox 的選擇情況就能直接控制開關的樣式,不需要再手動的在元素上加什麼 class。但是點擊的時候就會發現,這個開關的效果非常生硬,所以我們需要給它加一些過渡效果。首先我們先來介紹下 CSS3 中的 transition 屬性:

transition 屬性也是 CSS3 中的屬性,是用來指定元素的過渡效果的。比如某元素從樣式1變成了樣式2,如果沒有過渡就是直接改變;如果使用了過渡效果的話,瀏覽器會計算這兩個狀態之間的所有狀態,然後顯示出變化過程。 transition 屬性其實是四個屬性的縮寫,它們依次是:
transition-property,這個屬性用來指定對哪個樣式屬性添加過渡效果。這個屬性可以指定的通常是有數值的屬性,比如 height、width、top、bottom、left、right、color等。如果希望對所有屬性都添加過渡效果,那這個屬性還可以使用“all”這個屬性值,但不建議這麼用。
transition-duration,這個屬性用來指定完成過渡效果的時間。這個屬性值的形式是“數字+s”,比如 .5s 就是 0.5 秒完成過渡效果。
transition-timing-function,這個屬性用來指定過渡效果的變化速度的,它的取值可以是 linear、ease、ease-in、ease-out 和 ease-in-out 這幾個具體的名稱,也可以使用“cubic-bezier(n,n,n,n)”這種三階貝塞爾函數。這裏幾種具體名稱的取值實際上就是對幾種固定參數的貝塞爾函數做了個別名,如果對貝塞爾函數感興趣的話,可以自己去了解一下。
transition-delay,這個屬性用來指定過渡效果的延時時間的,有了這個屬性就可以允許過渡效果過一段時間後再開始。這個屬性的取值也是一個時間格式的值,同 transition-duration 用法相同。

這樣,我們給元素加上過渡效果即可。讓我們改造一下上面的幾段代碼:

.mxc-menu > .mxc-menu-item > .mxc-switch{
    position: relative;
    box-sizing: content-box;
    width: 2.6rem;
    height: 1.4rem;
    border: 1px solid #ccc;
    outline: 0;
    border-radius: .75rem;
    background-color: rgba(0, 0, 0, 0.1);
   transition: background-color .3s, border .3s;
    /* 去掉webkit內核裏默認的樣式 */
   -webkit-appearance: none;
    /* 去掉webkit內核裏默認的點擊效果 */
   -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
/* 使用::after僞元素實現圓形按鈕的樣式 */
.tt-menu > .tt-menu-item > .tt-switch::after{
    content: " ";
    position: absolute;
    top: 0;
    left: 0;
    width: 1.4rem;
    height: 1.4rem;
    border-radius: .7rem;
    background-color: #FFFFFF;
    box-shadow: 0 0 2px #999;
    transition: left .3s;
}

事實上,CSS中還有一個“有趣的事”:當你在初始樣式上設置了transition,也就相當於設置了此元素的CSS動態效果【1】上的過渡特效!

最終效果:
hj


【1】:即在當前元素的css上設置比如:checked:hover等使元素髮生陽世上的改變的僞元素。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章