利用Axure中繼器實現多選樹組件
編輯導語:多選樹組件也是我們常見的組件之一,那么,我們如何利用Axure中繼器來實現多選樹組件?本篇文章里,作者就如何利用Axure來實現多選樹組件一事做了流程梳理,一起來看一下。
一、效果預覽
二、名詞定義
1. 節點
- 節點:每層內容被看作為一個節點;
- 父節點:該級以上內容被視為該級內容的父節點;
- 子節點:該級以下內容被視為該級內容的子節點;
- 分支節點:有下級內容的節點;
- 葉子節點:無下級內容的節點。
舉例說明:
以閩侯縣為例,閩侯縣為一個節點,福州市、福建省為閩侯縣的父節點,上街鎮、南嶼鎮為閩侯縣的子節點。在該圖中,福建省、福州市、閩侯縣均為分支節點,上街鎮、南嶼鎮均為葉子節點。
2. 多選樹
具備2個功能:
- 展開/收起:可展開或收起其子節點(本文實現的是只能展開一級,且無記憶功能);
- 選擇:通過復選框進行復選。
當選中某節點時,其子節點均被選中;反之均不被選中。
當某節點所在層級均被選中時,其上級自動選中;當某節點所在層級均不被選中時,其上級自動取消勾選;當某節點所在層級選中情況不等時,其上級呈待選中狀態。
以上說明恐非標準說法,但為了讀者便于理解本文可先代入,有錯誤也歡迎大家指正!
三、整體思路
以中繼器包裹節點,通過更新中繼器中的一些列來改變節點形態(如位置、展開/收起按鈕展示、多選框狀態),根據中繼器中的列“id”可知道其父節點、子節點有哪些。
- 展開/收起實現:點擊時獲取節點id,通過判斷id能夠獲取其子節點有哪些,通過更新行操作展示或收起其所有子節點。
- 選擇實現:中繼器中記錄節點的子節點總數和選中的子節點數量。點擊時獲取節點id,通過判斷id能夠獲取其父節點、子節點有哪些。當該節點選中時,其子節點均被選中;其父節點選中的子節點數量增加,當父節點的子節點總數和選中的子節點數量相同時,父節點即被選中。當該節點取消選中時,其子節點均取消選中;其父節點選中的子節點數量減少,當父節點選中的子節點數量為0時,父節點即取消選中。
四、基礎元件
1. 主體元件
- 文本標簽“層級名稱”:用于展示你要展示的內容。
- 圖標“triangle”:一個箭頭造型的iconfont(也可以是個圖片),作為展開/收起的狀態展示。
- 復選框:一個動態面板,有“未勾選”、“部分選中”、“已勾選”3種狀態。當該節點的子節點均選中時,復選框狀態為“已勾選”;當該節點的子節點部分選中時,復選框狀態為“部分選中”;當該節點的子節點均未被選中時,復選框狀態為“未勾選”。葉子節點則沒有“部分選中”的狀態。(復選框狀態切換規則:未勾選、部分勾選的點擊后變為已勾選,已勾選的點擊后變為未勾選。實現方式見第5章第3節“向下全選”)
- 動態面板“主體”:用于包裹上述元件,便于觸發triangle的交互。
- 中繼器:用于包裹動態面板“主體”。
2. 輔助元件
二級按鈕、三級按鈕、四級按鈕、五級按鈕均為輔助按鈕(最終隱藏起來即可),點擊某層級的復選框時會觸發對應層級的輔助元件,這是為了讓交互看起來更加清晰。
五、具體實現
1. 中繼器初始化工作
1)中繼器字段定義
- id:節點編號。1級節點2位、2級節點4位…n級節點2n位。從01開始編號,前2*(n-1)位為上級節點編號,如上圖閩侯縣的編號為010101,其下級節點上街鎮、南嶼鎮的編號分別為01010101、01010102。
- grade:節點層級。1級節點為1,2級節點為2…n級節點為n。
- children:節點的葉子節點總數。如上圖閩侯縣、福州市、福建省的children均為2(上街鎮、南嶼鎮)。
節點的children為其下級節點的children之和。
- content:節點內容。
- visible:節點是否可見。1為可見,0為不可見。
- triangle:箭頭是否可見。1為可見,0為不可見。
- point:箭頭方向。1為展開(向下),0為收起(向右)。
- select:節點是否被選中。2為其子節點選中,1為其子節點部分被選中,0為未被選中。
- childrenSelect:節點的葉子節點中被選中的數量。
2)中繼器交互
① 每項加載時,設置“層級名稱”為中繼器的列“content”。
根據“grade”的值判斷“主體”的位置(此處僅5級,讀者可自行拓展)。
根據“triangle”的值判斷是否展示箭頭。
根據“point”的值判斷箭頭方向。
根據“select”的值判斷選中狀態。
每個判斷類型的第一個條件為if,這是因為每個判斷類型都需被執行。
2)載入時,將“visible”為1的行添加篩選。
2. 展開收起
1)思路:點擊箭頭時判斷箭頭方向,方向在展開、收起間切換,若要展開就將其子節點的visible設為1,反之設為0。
- 子節點如何界定:當前行子節點的id是在當前行id的基礎上繼續編號的,故獲取當前行的id位數即可得知其他節點id的前幾位需要和該行id相同,即TargetItem.id.substr(0,grade*2)==id。
- 上述界定方式同樣適用于當前行本身,所以還需剔除當前行,即TargetItem.grade!=grade。
- 要遍歷所有行必須用TargetItem而非Item。
2)具體實現:單擊箭頭時:
① 獲取該行的id、grade分別存于全局變量id、grade(本文所有全局變量的設置均是為了便于調試)。
② 判斷該行的point的值:
- 若為1:更新當前行的point=0,更新當前行子節點[[TargetItem.id.substr(0,grade*2)==id && TargetItem.grade!=grade]]的visible==0
- 若為0:更新當前行的point=1,更新當前行下一級的visible==1(若想要其子節點全部展開即和為1時的規則一樣即可)
3)設置動態面板“主體”單擊時觸發箭頭的單擊交互。
3. 向下全選
1)思路:點擊復選框時判斷選中狀態,若需要取消勾選則將當前行和其子節點的select設為2,反之設為0。
2)具體實現:單擊復選框時:
① 獲取該行的id、grade分別存于全局變量id、grade。
② 判斷面板狀態:
- 若非已勾選(即需要取消勾選):更新當前行及其子節點[[TargetItem.id.substr(0,grade*2)==id]]的select==2、childrenSelect==TargetItem.children(向上選中時使用)
- 若為已勾選(即需要勾選):更新當前行及其子節點[[TargetItem.id.substr(0,grade*2)==id]]的select==0、childrenSelect==0(向上選中時使用)
4. 向上選中
1)思路
點擊復選框時判斷選中狀態,若需要選中則將其父節點的“childrenSelect”的值加上多出來的葉子節點數量(當前行“children”的值-當前行“childrenSelect”的值),反之將其父節點的“childrenSelect”的值減去當前行“children”的值。
每次執行完以上時判斷“childrenSelect”的值,若與其“children”相等,就說明這個節點的子節點都被選中了;若=0,就說明這個節點的子節點均未被選中;否則即其子節點部分被選中。
① 為了提高易讀性,把除設置變量以外的交互都寫在了輔助元件中。
② 由于葉子節點的children==0且無子節點,故點擊葉子節點的復選框時,其父節點“childrenSelect”的值直接加/減1即可。
③ 父節點如何界定:當前行的id是在其父節點id的基礎上繼續編號的,故獲取檢索行的id位數即可得知當前行id的前幾位需要和檢索行id相同,即TargetItem.id==id.substr(0,grade*2)。
由于暫未找到Axure自動輪詢的方法,故須對每級節點單獨寫交互。
若當前行為3級節點,僅1級節點、2級節點均為其父節點,即TargetItem.id==id.substr(0,2) ||?TargetItem.id==id.substr(0,4)。
若當前行為4級節點,僅1級節點、2級節點、3級節點均為其父節點,即TargetItem.id==id.substr(0,2) ||?TargetItem.id==id.substr(0,4) ||?TargetItem.id==id.substr(0,6)…
2)具體實現
① 單擊復選框時獲取該行的select、children、childrenSelect分別存于全局變量select、children、childrenSelect,觸發4個輔助元件的單擊事件。
② 二級按鈕交互
若為分支節點,且非選中狀態(即需要勾選。判斷條件:select!=2 并且 grade==2 并且 children!=0):
更新當前行父節點[[TargetItem.id==id.substr(0,2)]]的select==1、childrenSelect==TargetItem.childrenSelect+children-childrenSelect;
更新“children==childrenSelect”的非葉子節點所在行[[TargetItem.children==TargetItem.childrenSelect && TargetItem.children!=0]]的select==2。
若為葉子節點,且非選中狀態(即需要勾選)。區別僅在于判斷條件的children==0,更新當前行父節點的childrenSelect==TargetItem.childrenSelect+1。
實際上,葉子節點的select只有0、2兩種狀態。
若為分支節點,且為選中狀態,即需要取消勾選。
判斷條件:select==2 并且 grade==2 并且 children!=0):
更新當前行父節點[[TargetItem.id==id.substr(0,2)]]的select==1、childrenSelect==TargetItem.childrenSelect-children。
更新“childrenSelect==0”的非葉子節點所在行[[TargetItem.children!=0 && TargetItem.childrenSelect==0]]的select==0。
若為葉子節點,且為選中狀態(即需要取消勾選)。區別僅在于判斷條件的children==0,更新當前行父節點的childrenSelect==TargetItem.childrenSelect-1
③ 三級按鈕交互:與二級按鈕交互的區別在于單擊時的判斷條件上(grade==3)和當前行父節點的判斷條件上,三級按鈕的當前行父節點為[[TargetItem.xuhao==id.substr(0,2) || TargetItem.xuhao==id.substr(0,4)]]
其他級按鈕以此類推。
六、寫在后面的話
1. 不足之處/可優化的點
由于該設計為工具類,應盡量減少使用者的使用成本。中繼器中可不填寫grade,grade可通過id位數來確定。
僅支持5層的樹,若想要更高層級需讀者自行寫交互(但在理解的基礎上復制修改即可,在箭頭的交互上已經實現了無層級差異的)。
每層僅支持99個節點,若需更多節點要修改id編號及交互。
還未實現選擇后的回填效果,如“送貨地區”欄選擇了多個省、市后點擊確認把選擇的省、市回填到輸入框中。
2. 遇到的坑
輔助元件的單擊交互中,一開始是直接判斷復選框的狀態變化,但永遠獲取到的狀態都是“!=選中”(即使區分為“==未選中”或“==部分選中”也都是“!=選中”),故改成了判斷全局變量“select”的值。
復選框的交互中,一開始想通過以下方式實現遍歷,但無法觸發狀態變化時的交互,故改成了在單擊時的交互中做處理(如此更麻煩的,且無法實現無層級差異的處理)。
- 中繼器中不是記錄葉子節點的數量,而是記錄直接下級的總數(這樣既好計算,后期也好維護)。
- 單擊時設置一些全局變量并修改當前行“select”的值,狀態變化時根據狀態修改當前行直接上級的已選中直接下級數量,當已選中直接下級數量==直接下級總數時,勾選當前行。
3. 鳴謝
本人在設計過程中部分思路參考了《Axure教程:Axure中繼器實現動態樹結構控件詳解》(作者:Pershing)、《Axure教程:可增刪改的樹型結構》(作者:梓賢vigo),感謝大佬們!
歡迎大家指正問題或提議!萬分感謝!
本文由 @Air 原創發布于人人都是產品經理,未經許可,禁止轉載
題圖來自 Pexels,基于 CC0 協議
有源文件可供下載嗎?
抱歉啊,源文件不分享,但是有問題可以加私人號交流(但我不懂咋私聊你)
點擊復選框時判斷選中狀態,若需要選中則將其父節點的“childrenSelect”的值加上多出來的葉子節點數量(當前行“children”的值-當前行“childrenSelect”的值),反之將其父節點的“childrenSelect”的值減去當前行“children”的值。
這里不會父節點的childrenselect不會變成負數嗎?是不是應該減掉變量childrenSelect
不會為負數,因為我設置了復選框只有在已勾選的狀態下才會變成未勾選,所以復選框能變成未勾選就說明該節點的所有子節點都已經計算進該節點的父節點的“childrenSelect”中了