圖形編輯器開(kāi)發(fā):顏色 Hex 標(biāo)準(zhǔn)化
大家好,我是前端西瓜哥。
最近做圖形編輯器,有這么一個(gè)需求,在輸入框輸入顏色十六進(jìn)制值(hex),自動(dòng)轉(zhuǎn)為對(duì)應(yīng) 6 位長(zhǎng)度的 hex。
如果值不合法,回退為上次合法輸入。
我正在開(kāi)發(fā)的圖形設(shè)計(jì)工具:
https://github.com/F-star/suika
線上體驗(yàn):
https://blog.fstars.wang/app/suika/
顏色 hex 規(guī)則
顏色 hex 的通用規(guī)則是:
- 字符的范圍需要為 0~9,a~f,A~F。
- 長(zhǎng)度有要求,需要為 6 位字符串(ABCDEF);也可以為 3 位,比如 ABC,它等價(jià)于 6 位的 AABBCC。
處理用戶輸入
但是用戶的輸入你是無(wú)法預(yù)測(cè)的,大概率是不符合這兩個(gè)規(guī)則。
簡(jiǎn)單地判斷不符合規(guī)則讓用戶的輸入無(wú)效,然后回退,并不是很好的做法。
為了有更好的用戶體驗(yàn),我們要做一下優(yōu)化。
當(dāng)用戶輸入完內(nèi)容,回車,我們對(duì)輸入字符串進(jìn)行處理。
- 首先轉(zhuǎn)換大寫,這是為了統(tǒng)一格式和對(duì)比,其實(shí)和優(yōu)化無(wú)關(guān)。你也可以轉(zhuǎn)小寫。
- 取出字符串中從左開(kāi)始第一個(gè)匹配上面規(guī)則的子字符串,用正則表達(dá)式是最合適的,正則為:/[0-9A-F]{1,6}/,表示匹配第一個(gè)字符為 0~9 和 A~F 的長(zhǎng)度為 1 到 6 的字符串。
- 如果沒(méi)匹配到,返回一個(gè)空字符串表示沒(méi)找到合法值,輸入框的內(nèi)容會(huì)進(jìn)行回退到上一次輸入的合法值。
- 如果匹配到,就會(huì)根據(jù)子字符串的長(zhǎng)度執(zhí)行不同的邏輯
- 長(zhǎng)度為 6,剛好,直接返回它。
- 長(zhǎng)度為 4 和 5,屬于是 “高不成低不就”,我們將其截?cái)酁?3。(或者你可以給它末尾補(bǔ) 0 補(bǔ)滿到 6 位)
- 長(zhǎng)度為 3,我們應(yīng)用的規(guī)則是,從 ABC 轉(zhuǎn)換為 AABBCC,因?yàn)閷?duì)應(yīng)經(jīng)典規(guī)則,前者是后者的縮寫。
- 長(zhǎng)度為 2 或 1,則不斷地將自己添加到末尾,直到滿 6 位,比如:AB 會(huì)變成 AABBCC,A 會(huì)變成 AAAAAA。
這樣用戶輸入 #0,這個(gè)輸入本身不符合顏色 hex 規(guī)則,但我們理解用戶其實(shí)是想要一個(gè)純黑色。
通過(guò)上面的處理,我們會(huì)返回一個(gè) 000000,而不是簡(jiǎn)單地認(rèn)為用戶輸入不合法,將其丟掉。
代碼實(shí)現(xiàn)
const normalizeHex = (hex: string) => {
// (1)轉(zhuǎn)大寫
hex = hex.toUpperCase();
// (2)找出其中的符合顏色 hex 規(guī)則的子字符串
const match = hex.match(/[0-9A-F]{1,6}/);
if (!match) {
return '';
}
hex = match[0];
if (hex.length === 6) {
return hex;
}
if (hex.length === 4 || hex.length === 5) {
hex = hex.slice(0, 3);
}
// ABC -> AABBCC
if (hex.length === 3) {
return hex
.split('')
.map((c) => c + c)
.join('');
}
// AB -> ABABAB
// A -> AAAAAA
return hex.padEnd(6, hex);
};
符合經(jīng)典規(guī)則(AABBCC 和 ABC)的情況:
找不到 hex 字符串的情況,會(huì)回退到上次的合法值
其他情況: