|
在很多系(xi)統中都(dou)有選(xuan)擇聯系(xi)人的(de)需求,市面上(shang)也沒什么好的(de)參照(zhao),產(chan)品(pin)經理看(kan)企業微信的(de)選(xuan)人挺好用的(de),就說參照(zhao)這個(ge)(ge)做一個(ge)(ge)吧。。。
算了(le),還是試著做吧,企業微信的選人的確做的挺好,不得不佩(pei)服。 先看看效果(guo)圖吧,多層級無規律的嵌(qian)套都能(neng)搞定
一、設計解讀
整個界面分為三部分:
為(wei)什么加一(yi)個返(fan)回上一(yi)層(ceng)按(an)鈕呢(ni)? 我也覺得比較丑,但小程(cheng)序無法直接控制左(zuo)(zuo)上角返回鍵(jian)(自定義(yi) Title 貌似可以,沒(mei)試過),點左(zuo)(zuo)上角的返回箭頭(tou)的話就(jiu)退(tui)出選(xuan)人控件(jian)到上個頁面了。 我們的(de)需(xu)求是(shi)點(dian)擊一個(ge)文件夾,通過刷新當前列表(biao)進入下(xia)一級目(mu)錄,感(gan)覺像是(shi)又(you)進了一個(ge)頁面,但其實并沒有,只(zhi)是(shi)列表(biao)的(de)數據變化了。由(you)此實現不定層級、無規律的(de)部門(men)和人員(yuan)嵌套的(de)支(zhi)持。 比如先點擊了首屏數(shu)據的(de)第二個(ge) item,它的(de) index 是 1 ,就將 1 存入 indexList ;返回(hui)上一層(ceng)時將最后一個(ge)元(yuan)素刪除。 當(dang)(dang)勾選(xuan)了某個人或部(bu)門(men)時(shi),會在底部(bu)的(de)框中顯示所(suo)有已選(xuan)人員或部(bu)門(men)的(de)名字(zi),當(dang)(dang)文字(zi)超過屏幕(mu)寬度時(shi)可(ke)以向(xiang)右無限滑動,底部(bu) footer 始終保持(chi)一(yi)行。 最(zui)終選擇的(de)人(ren)以底部 footer 里顯示的(de)為準,點擊確定時根(gen)據業務(wu)需要(yao)將(jiang)已選人(ren)員數(shu)據發(fa)送給(gei)需要(yao)的(de)界面(mian)。 二、功能邏輯分析先看(kan)看(kan)數據格式
所(suo)有(you)的數據(ju)組成一個數據(ju)樹,子節點嵌(qian)套在父節點下。 id, name 不說了,parentId 指明它(ta)的父節點,children 包含它(ta)的所有子節點,checked 用(yong)來判斷(duan)勾選狀態,isPeople 判斷(duan)是(shi)部(bu)門還(huan)是(shi)人(ren)員,因為兩者(zhe)的圖(tu)標(biao)不一樣。 注意: 本控件采用了數(shu)(shu)據(ju)分(fen)步加(jia)載(zai)(zai)(zai)的(de)(de)(de)模式,除了最上層固定的(de)(de)(de)幾個(ge)分(fen)類,其他的(de)(de)(de)每層數(shu)(shu)據(ju)都是點擊具體(ti)的(de)(de)(de)部門后才去(qu)請求服務器加(jia)載(zai)(zai)(zai)本部門下(xia)的(de)(de)(de)數(shu)(shu)據(ju)的(de)(de)(de),然后再(zai)拼接(jie)到原始數(shu)(shu)據(ju)樹上。這(zhe)樣可以提高加(jia)載(zai)(zai)(zai)速(su)度,提升用戶(hu)體(ti)驗。 我(wo)也試了一次性把所(suo)有(you)數據都拉下(xia)來,一是(shi)太(tai)慢,得三五秒,二(er)是(shi)數據量太(tai)大的話(我(wo)這里應該(gai)是(shi)超過1000,閾值多少沒測過),setData() 的時(shi)候(hou)就會報(bao)錯(cuo):
超過最大長度了。。。所以只(zhi)能分步加載數(shu)據。 當然如果你(ni)的數據量小,幾(ji)十人或(huo)幾(ji)百人,也可以選(xuan)擇一次性加載。 這個控件邏輯(ji)上還是比較復雜(za)的,要(yao)(yao)考慮(lv)的細節太(tai)多……下(xia)面梳(shu)理一(yi)下(xia)主要(yao)(yao)的邏輯(ji)點 主要邏輯點1. 需要一個數組存儲所有被點擊的部門在當前列表的索引 index ,這里用 indexList 表示點擊(ji)某個(ge)(ge)部門進入下一(yi)層目錄時,將被點擊(ji)部門的 index 索引 push 進 indexList 中。點擊(ji)返回上(shang)一(yi)層按鈕時,刪除 indexList 中最后一(yi)個(ge)(ge)元(yuan)素(su)。 2. 要動態的更新當前列表 currentList每進(jin)入新的(de)一(yi)層(ceng),或(huo)返回上一(yi)層(ceng),都(dou)需要刷新 currentList 來實現頁面的(de)更新。知道下(xia)一(yi)層(ceng)數據很容易(yi),直接取被點擊 item 的(de) children 賦值給 currentList 即可。 但如何(he)還原上一層的(de)數據呢? 第一點記錄的(de) indexList 就發揮作(zuo)用了(le),原始數據樹為 originalList,循環遍歷 indexList ,根據索引依(yi)次取(qu)出(chu)每層(ceng)的(de) currentList 直(zhi)到 indexList 的(de)最后一個元素,就得到了(le)返(fan)回(hui)上一層(ceng)需要顯示的(de)數據。 3. 每一次勾選或取消選中都要更新原始的數據樹 originalList頁面是根(gen)據每個(ge) item 的(de)(de) checked 屬性判斷是否選中的(de)(de),所以(yi)每次改變勾選狀態都要設置被(bei)改變的(de)(de) item 的(de)(de) checked 屬性,然后更(geng)新(xin)(xin) originalList。這樣即使返回上一層了,再進到當前層級選中狀態還會(hui)被(bei)保(bao)留(liu),否則(ze)刷新(xin)(xin) currentList 后已選狀態將(jiang)丟失。 4. 列表中選擇狀態的改變與底部 footer 的雙聯動我們期望的(de)效果是,選中(zhong)currentList 列表的(de)某一項,底部 footer 會(hui)自動添加被選人的(de)名字(zi)。取消選中(zhong),底部 footer 也會(hui)自動刪除。 也可(ke)以通過 footer 來刪(shan)除已選人,點擊 footer 中(zhong)人名(ming),會將此(ci)人從(cong)已選列(lie)表中(zhong)刪(shan)除,currentList 列(lie)表中(zhong)也會自動取(qu)消勾選狀態。 嗯,這個功能(neng)比較(jiao)耗性(xing)能(neng),每(mei)一次都需(xu)要大量的計算。考(kao)慮到性(xing)能(neng)和速度因素,本(ben)次只做了從 footer 刪除只更新 currentList 的勾選(xuan)狀態(tai)。 什(shen)么(me)意思呢?假如有(you)兩(liang)層(ceng),A 和 B,B 是(shi)(shi) A 的(de)下一層(ceng)數據,即 A 是(shi)(shi) B 的(de)父節點(dian)。在 A 中(zhong)(zhong)選中(zhong)(zhong)了(le)一個(ge)部(bu)門 校(xiao)長(chang)室(shi),點(dian)擊下一層(ceng)到 B,在 B 中(zhong)(zhong)又選了(le)兩(liang)個(ge)人 張(zhang)三(san)(san) 和 李(li)四,這(zhe)時(shi)(shi)底部(bu) footer 里顯示的(de)應該(gai)是(shi)(shi)三(san)(san)個(ge): 校(xiao)長(chang)室(shi)、 張(zhang)三(san)(san) 、 李(li)四。此時(shi)(shi)點(dian)擊 footer 的(de) 張(zhang)三(san)(san) , footer 會(hui)把(ba)(ba) 張(zhang)三(san)(san) 刪除(chu),中(zhong)(zhong)間列表中(zhong)(zhong) 張(zhang)三(san)(san) 會(hui)被置為(wei)未(wei)選中(zhong)(zhong)狀態,這(zhe)沒問題。但點(dian)擊 footer 的(de) 校(xiao)長(chang)室(shi) , 在 footer 中(zhong)(zhong)是(shi)(shi)把(ba)(ba) 校(xiao)長(chang)室(shi) 刪除(chu)了(le),但再(zai)返(fan)回到上一層(ceng)時(shi)(shi),中(zhong)(zhong)間列表中(zhong)(zhong)的(de) 校(xiao)長(chang)室(shi) 依然是(shi)(shi)勾(gou)選狀態,因為(wei)此時(shi)(shi)沒有(you)更新原始數據樹(shu) originalList。如果(guo)覺得這(zhe)是(shi)(shi)個(ge) bug, 可(ke)以加個(ge)更新 originalList 的(de)操(cao)作。這(zhe)樣(yang)就要(yao)遍歷 originalList 的(de)每個(ge)元(yuan)素判斷與(yu)本次刪除(chu)的(de) id 是(shi)(shi)否相等,然后(hou)改變(bian) checked 值,如果(guo)數據量很大,會(hui)非常慢。我(wo)做了(le)妥協…… 關鍵的邏(luo)輯就這四塊了(le),當(dang)然還有(you)很多小細節,直接看代(dai)碼吧(ba),注釋寫的也比較詳細。 三、代碼目(mu)錄結(jie)構:
footer 文(wen)件夾下(xia)是抽離出的 footer 組件,userSelect 是選人控件的主要(yao)邏輯。把這幾個文(wen)件復制過去就可以用(yong)了。 把 userSelect.js 里網絡請(qing)求(qiu)的(de)代碼替換為你的(de)請(qing)求(qiu)代碼,注意數據的(de)字段名是(shi)否一致。 userSelect 的代碼
footer 的代碼
再補一(yi)個用到的 ArrayUtils 的代碼
由于時間(jian)緊張,還(huan)沒有把(ba)這(zhe)個控件單獨從項目(mu)中抽出來寫個 Demo,有時間(jian)了會給 github 地址的。 代碼(ma)還(huan)有很多可以(yi)優化的(de)地方,比(bi)如有幾個方法太長(chang)了(le),不符合單一(yi)職責(ze)原則等等,不想改(gai)了(le),以(yi)后再優化吧。。 水(shui)平(ping)有限,各(ge)位(wei)大俠請輕噴~ 有問(wen)題或(huo)發(fa)現 Bug 請(qing)在評論區留言(yan),畢竟剛寫完就(jiu)分享(xiang)出(chu)來了,還沒經過(guo)嚴格(ge)的測試(shi)。不過(guo)應該沒什么大的問(wen)題。。。有些細節可能沒注意到。 |

