摘要:但是如果一剎那我不想選江疏影了,我想選張雨綺因?yàn)樾卮螅紫任乙獜幕羲佳鄵Q到高圓圓,然后轉(zhuǎn)到張雨綺,選中展示出來,這時(shí)候就要先刪除霍思燕,然后把高圓圓和張雨綺進(jìn)來。
QingUI是一個(gè)UI組件庫寫在前面
目前擁有的組件:DatePicker, TimePicker, Paginator, Tree, Cascader, Checkbox, Radio, Switch, InputNumber, Input
ES6語法編寫,無依賴
原生模塊化,Chrome63以上支持,請(qǐng)開啟靜態(tài)服務(wù)器預(yù)覽效果,靜態(tài)服務(wù)器傳送門
采用CSS變量配置樣式
辛苦造輪子,歡迎來github倉庫star:QingUI
去年年底項(xiàng)目中嘗試著寫過一個(gè)分頁的Angular組件,然后就有了寫QingUI的想法
過程還是非常有意思的
接下來我會(huì)用幾篇文章分別介紹每個(gè)組件的大概思路,請(qǐng)大家耐心等待
這一篇介紹Cascader級(jí)聯(lián)選擇器
點(diǎn)個(gè)star就是對(duì)我最好的支持
repo: QingUI少廢話,先上圖 數(shù)據(jù)
既然是級(jí)聯(lián)選擇器,數(shù)據(jù)肯定是樹形結(jié)構(gòu),像這樣
const data = [ { label: "霍思燕", sub: [ { label: "江疏影", }, { label: "倪妮", }, ], }, { label: "高圓圓", sub: [ { label: "張雨綺", }, { label: "宋佳", }, ], }, ];
你猜我最喜歡哪位女明星 :)
而且用戶點(diǎn)到哪一個(gè)label上,就呼出下一級(jí)列表
那么問題來了,我怎么知道我當(dāng)前在哪一級(jí),又在哪一個(gè)分支?
所以我需要給每一個(gè)分支做標(biāo)記,點(diǎn)到哪一個(gè)label上,就取出標(biāo)記,該標(biāo)記能指引我找到對(duì)應(yīng)的數(shù)據(jù)分支
我的方法是這樣的,新建一個(gè)字段queue,字段值是一個(gè)字符串形式的數(shù)字,位數(shù)表示當(dāng)前是第幾級(jí),數(shù)字表示當(dāng)前是第幾個(gè)分支
比如說queue = 131;,表示當(dāng)前在第一個(gè)分支下面的第三個(gè)分支下面的第一個(gè)分支
buildQueue(data, queue = "") { for (let i = 0; i < data.length; i++) { const item = data[i]; const sub = item.sub; const newQueue = `${queue}${i}`; item[this.queue] = newQueue; if (sub) { this.buildQueue(sub, newQueue); } } }
字段名其實(shí)我并沒有用queue,因?yàn)橛锌赡芤呀?jīng)被占用,我用的是時(shí)間戳組成的hash值,所以賦值的時(shí)候要寫成item[this.queue] = newQueue;
渲染的時(shí)候給DOM元素加一個(gè)data-v="${item[this.queue]}就行了
那么怎么讀呢?
這些數(shù)字其實(shí)就是數(shù)組的索引,加一個(gè)遞歸搞定
findSubByQueue(data, queue) { const n = Number.parseInt(queue.charAt(0)); for (let i = 0; i < data.length; i++) { if (i === n) { if (queue.length > 1) { return this.findSubByQueue(data[i].sub, queue.slice(1)); } else { return data[i].sub; } } } }事件
級(jí)聯(lián)肯定要支持點(diǎn)擊和懸浮兩種事件觸發(fā)機(jī)制
所以我用this.eventType來保存事件類型,其實(shí)兩種事件大部分代碼是可以復(fù)用的
for (let i = 0; i < $trunks.length; i++) { const $trunk = $trunks[i]; const v = $trunk.dataset.v; const label = $trunk.querySelector(".label").innerHTML; const CL = $trunk.classList; $trunk.addEventListener(this.eventType, function(event) { event.stopPropagation(); // 遍歷清除trunk的active self.removeTrunkActive($trunks); // 當(dāng)前trunk變成active CL.add("active"); // 構(gòu)建路徑 self.buildPath(v.length, label, false); // 找到子數(shù)據(jù) const sub = self.findSubByQueue(self.data, v); // 填充子board $subBoard.innerHTML = self.renderCascade(sub); // 添加事件 self.$rowEvent($subBoard); }); }
注釋也寫的很清楚,首先是一個(gè)高亮的處理,然后要把當(dāng)前路徑保存下來,通過queue找到子數(shù)據(jù),然后渲染出來,最后給子節(jié)點(diǎn)添加事件
要知道,分支可以分為兩種,一種是下面還有分支,我把它稱作trunk,另一種是末梢,下面沒有分支了,我把它稱作leaf
點(diǎn)擊很容易,只給trunk添加事件就可以了
但是懸浮,leaf也要有事件,就是把之前的高亮和子數(shù)據(jù)清空
if (this.trigger === "hover") { for (let i = 0; i < $leafs.length; i++) { $leafs[i].addEventListener("mouseenter", function() { self.removeTrunkActive($trunks); $subBoard.innerHTML = ""; }); } // 離開curtain this.$curtain.addEventListener("mouseleave", function() { self.removeTrunkActive(self.$trunks); self.$subBoard.innerHTML = ""; }); }
那么怎么選中呢?
到leaf才是一個(gè)完整的路徑,所以leaf特殊處理,無論是什么事件,點(diǎn)擊leaf選中,把路徑渲染出來
路徑保存路徑是一個(gè)動(dòng)態(tài)的過程
因?yàn)槲铱赡懿榭戳四骋粋€(gè)分支,然后又查看另一個(gè)分支,最終選中了別的分支
所以保存路徑要根據(jù)路徑的長(zhǎng)度和當(dāng)前級(jí)別來確定是添加還是刪除
比如我現(xiàn)在在江疏影這里,還沒有選中,那么當(dāng)前是第二級(jí),路徑里只保存了霍思燕,如果我選中,那么簡(jiǎn)單,直接把江疏影push到數(shù)組里,展示出來。但是如果一剎那我不想選江疏影了,我想選張雨綺(因?yàn)樾卮螅紫任乙獜幕羲佳鄵Q到高圓圓,然后轉(zhuǎn)到張雨綺,選中展示出來,這時(shí)候就要先刪除霍思燕,然后把高圓圓和張雨綺push進(jìn)來。
buildPath(level, label, render) { if (this.path.length < level) { // 往下選擇,直接push this.path.push(label); } else { // 退回選擇,根據(jù)退回長(zhǎng)度刪除path元素,再push this.path = [...this.path.slice(0, level - 1), label]; } if (render) { this.renderPath(); } }搜索
突發(fā)奇想,我又想加一個(gè)搜索功能
比如說我現(xiàn)在搜集了好幾千個(gè)女明星,打亂格式化成樹形數(shù)據(jù),那我選擇起來可就困難了,難道每一個(gè)分支都查看一遍嗎?如果有搜索,我只要搜張雨綺,所有包含張雨綺的級(jí)聯(lián)都展示出來,是不是方便很多!
看起來很復(fù)雜的樣子
其實(shí),換一個(gè)思路,初始化的時(shí)候就把所有的路徑都遍歷出來,緩存在一個(gè)數(shù)組里,搜索的時(shí)候只要檢索這些字符串有沒有張雨綺,是不是回到我們熟悉的字符串操作上來了?
遍歷所有路徑
iterateAllPath() { const self = this; let temp = []; const data = pathPush([...this.data]); function pathPush(data, arr = []) { for (const item of data) { item.path = []; // 將路徑存入item中的數(shù)組 item.path.push(...arr, item.label); } return data; } function recursive(data) { for (const item of data) { const sub = item.sub; if (sub) { // 將下一層放入temp temp.push(...pathPush(sub, item.path)); } else { // 沒有下一層則路徑結(jié)束 self.pathPool.push(item.path.join(self.seperator)); } } if (temp.length) { // 重新初始化 data = temp; temp = []; recursive(data); } } recursive(data); }
for (const item of this.pathPool) { const match = item.match(reg); if (!match) { continue; } result.push(item); }
別急,還有需求,我想把關(guān)鍵詞高亮
比如說我搜張雨綺,所有結(jié)果中張雨綺都要高亮
我搜張雨,所有結(jié)果中張雨都要高亮
這個(gè)也不復(fù)雜,用關(guān)鍵詞把路徑截成三段,如果關(guān)鍵詞在首尾那就截成兩段
這里有一個(gè)小問題,如果分隔符與關(guān)鍵詞之間有空格,展示結(jié)果總是不符合預(yù)期
后來才發(fā)現(xiàn),如果標(biāo)簽內(nèi)第一個(gè)字符是空格,空格會(huì)被忽略
所以還需要小小的處理一下
const reg = new RegExp(value, "i"); for (const item of this.pathPool) { const match = item.match(reg); if (!match) { continue; } result.push(item); const index = match.index; let [left, center, right] = [item.slice(0, index), match[0], item.slice(index + value.length)]; // 如果標(biāo)簽內(nèi)第一個(gè)字符是空格,空格會(huì)被忽略 if (right && right.startsWith(" ")) { right = ` ${right.trimLeft()}`; } tpl += `寫在后面${left ? `${left}` : ""} ${center} ${right ? `${right}` : ""}`; } if (!tpl) { tpl = "No Result"; }
Cascader比較核心的邏輯就在這里了
相較前幾篇文檔,隔的時(shí)間有點(diǎn)長(zhǎng),不過Cascader不會(huì)讓你失望的
如果覺得QingUI還不錯(cuò),點(diǎn)個(gè)star激勵(lì)一下老夫
repo: QingUI
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/95316.html
摘要:是一個(gè)組件庫目前擁有的組件語法編寫,無依賴原生模塊化,以上支持,請(qǐng)開啟靜態(tài)服務(wù)器預(yù)覽效果,靜態(tài)服務(wù)器傳送門采用變量配置樣式辛苦造輪子,歡迎來倉庫四月份找工作,求內(nèi)推,坐標(biāo)深圳寫在前面去年年底項(xiàng)目中嘗試著寫過一個(gè)分頁的組件,然后就有了寫的想法 QingUI是一個(gè)UI組件庫目前擁有的組件:DatePicker, TimePicker, Paginator, Tree, Cascader, ...
摘要:是一個(gè)組件庫目前擁有的組件語法編寫,無依賴原生模塊化,以上支持,請(qǐng)開啟靜態(tài)服務(wù)器預(yù)覽效果,靜態(tài)服務(wù)器傳送門采用變量配置樣式辛苦造輪子,歡迎來倉庫四月份找工作,求內(nèi)推,坐標(biāo)深圳寫在前面去年年底項(xiàng)目中嘗試著寫過一個(gè)分頁的組件,然后就有了寫的想法 QingUI是一個(gè)UI組件庫目前擁有的組件:DatePicker, TimePicker, Paginator, Tree, Cascader, ...
摘要:是一個(gè)組件庫目前擁有的組件語法編寫,無依賴原生模塊化,以上支持,請(qǐng)開啟靜態(tài)服務(wù)器預(yù)覽效果,靜態(tài)服務(wù)器傳送門采用變量配置樣式辛苦造輪子,歡迎來倉庫四月份找工作,求內(nèi)推,坐標(biāo)深圳寫在前面去年年底項(xiàng)目中嘗試著寫過一個(gè)分頁的組件,然后就有了寫的想法 QingUI是一個(gè)UI組件庫目前擁有的組件:DatePicker, TimePicker, Paginator, Tree, Cascader, ...
摘要:是一個(gè)組件庫目前擁有的組件語法編寫,無依賴原生模塊化,以上支持,請(qǐng)開啟靜態(tài)服務(wù)器預(yù)覽效果,靜態(tài)服務(wù)器傳送門采用變量配置樣式辛苦造輪子,歡迎來倉庫四月份找工作,求內(nèi)推,坐標(biāo)深圳寫在前面去年年底項(xiàng)目中嘗試著寫過一個(gè)分頁的組件,然后就有了寫的想法 QingUI是一個(gè)UI組件庫目前擁有的組件:DatePicker, TimePicker, Paginator, Tree, Cascader, ...
摘要:我們就可以將這些請(qǐng)求合并,達(dá)到一定數(shù)量我們統(tǒng)一提交??偨Y(jié)一個(gè)比較生動(dòng)的例子給大家講解了一些多線程的具體運(yùn)用。學(xué)習(xí)多線程應(yīng)該多思考多動(dòng)手,才會(huì)有比較好的效果。地址徒手?jǐn)]框架系列文章地址徒手?jǐn)]框架實(shí)現(xiàn)徒手?jǐn)]框架實(shí)現(xiàn) 原文地址:https://www.xilidou.com/2018/01/22/merge-request/ 在高并發(fā)系統(tǒng)中,我們經(jīng)常遇到這樣的需求:系統(tǒng)產(chǎn)生大量的請(qǐng)求,但是這...
閱讀 2332·2023-04-26 01:50
閱讀 765·2021-09-22 15:20
閱讀 2669·2019-08-30 15:53
閱讀 1661·2019-08-30 12:49
閱讀 1766·2019-08-26 14:05
閱讀 2783·2019-08-26 11:42
閱讀 2397·2019-08-26 10:40
閱讀 2668·2019-08-26 10:38