CSS並不簡單--個性化輸入框的實踐
這次通過這個個性化的輸入框,給大家介紹一些容易忽略的知識點。(新手注意:本文的html採用的是jade,css採用的sass,js採用的vue)
一、效果
大家先看一下效果動態圖,思考一波,帶著你的思考來看接下來的內容,可能效果更好一點。
二、需求
當我們開始做一樣東西的時候一定要先分析它的需求:
* 當輸入框獲取焦點時,提示文字發生上移動畫,同時下面線條產生動畫;
* 當輸入框失去焦點時,並且未填寫內容時,提示文字和線條恢復之前的狀態。
* 當輸入框失去焦點時,填寫內容時,狀態不變。
三、結構
看了上面的效果圖,首先就是要確定html的結構:
div.item
input(type="text" name="card" id="card" placeholder="身份證" v-card="" maxlength="18")
label(for="card") Card
div.focusline
這裡唯一遺憾的是input不支援偽元素(::after、::before),所以不得不採用一個額外的div。
這裡額外提一下,maxlength 只能用於input的type為password和text的情況,所以不要再問為什麼maxlength不起作用了。
四、表現
其實對於上面所要實現的效果,我們完全可以通過JS來控制,但是一直在強調表現(CSS)與行為(JS)分離
其實需求1與需求2是同一個需求,通過偽類focus和過渡屬性就能搞定。
input:focus + label {
color: rgb(82,97,107);
transform: translate(10px, 0) scale(.9);
}
input:focus ~ div {
width: 100%;
}
對於第三個需求,我們就得用一些新玩意了,第一個就是偽元素placeholder(偽類採用: 而偽元素採用::
input {
&:placeholder {
opacity: 0;
}
}
我們知道當輸入文字後,placeholder就不再顯示了,所以這裡來了一個偽類placeholder-shown(可以通過can i use 查一下它的相容性):
input:not(:placeholder-shown) + label {
color: rgb(82,97,107);
transform: translate(10px, 0) scale(.9);
}
input:not(:placeholder-shown) ~ div {
width: 100%;
}
五、行為
這裡我還要嘮叨一下,從上面可以看出這是一個身份證輸入框,我們多知道身份證是由數字和字母,而且字母只出現在第18位,而且只能是字母x。所以我上面採用了text型別的輸入框,為了讓使用者很好的輸入,會出現這幾種問題:
* 切換為中文輸入法時存在的問題;
* 複製貼上的問題;
* 輸入其他非法字元的處理。
這裡我們主要通過input、compositionstart、compositionend、paste四個事件解決。
let legalContent, //開啟輸入法之前的輸入內容
LOCK = false; //是否開啟中文輸入法
el.addEventListener('compositionstart', (e) => {
/**
* --------------
* 開啟中文輸入法
* --------------
*/
legalContent = e.target.value; //儲存中文輸入法之前的內容
LOCK = true; //加上鎖
}, false);
el.addEventListener('compositionend', (e) => {
/**
* ---------------------
* 結束中文輸入法
* ---------------------
*/
e.target.value = legalContent;
LOCK = false; // 解鎖
}, false);
el.addEventListener('input', (e) => {
const len = e.target.value.length;
/**
* 在中文觸發時 不進行處理
* 當身份證號碼少於18位時只能輸入數字
* 當身份證號碼為18位時可以輸入數字和字母
*/
if (!LOCK) {
if (len <= 17) {
e.target.value = e.target.value.replace(/\D/,'');
} else {
e.target.value = e.target.value.replace(/[^0-9Xx]/,'');
}
}
}, false);
el.addEventListener('paste', (e) => {
/**
* ----------
* 貼上
* ----------
*/
e.preventDefault(); //阻止預設事件
}, false);