EasyUi TreeGrid封裝
http://www.cnblogs.com/Leo_wl/p/4319470.html
禮物一:樹型實體的抽象與封裝
所謂樹型實體,就是具有樹型結構關系的實體,比如省、市、區。對於初學者,可能會創建三張表進行存儲,有經驗的開發者通過引入ParentId將設計簡化為一張表,但是基於ParentId的設計也不夠完美,主要問題是查找某個節點的所有上級或所有下級時,都需要進行遞歸,這是一個低效而復雜的操作。
更有經驗的開發者會引入物化路徑Path,物化路徑是對節點關系的記錄,一般格式為:當前節點Path = 父節點Path + 當前節點Id + “,”,註意物化路徑的最後一定是某個符號,一般為逗號。
一旦物化路徑設置完成,查找所有上級和下級就非常簡單,查找所有上級只需要從當前節點的Path中,用逗號分隔出Id即可,查找所有下級,通過StartsWith查詢Path列,也就是Sql中的Like ‘xxx%’。
雖然物化路徑在查詢節點關系方面非常高效,但也不是沒有成本的,主要成本在於修改節點關系之後,該節點的所有下級節點的物化路徑都需要更新。比如某個節點修改了父節點,那麽除了當前節點的Path需要更新外,它的所有下級節點也需要更新,這是一個代價高昂的操作。想像一下,當一個節點下面有數千個,甚至數萬個節點,修改一下節點關系將帶來多麽嚴重的後果。不過一般樹型結構的數據量都不會很大,所以這個問題也不用太多考慮,你只需要了解用這種設計方案有什麽弊端即可。
當使用了EasyUi的TreeGrid這種控件以後,可以在表格上隨意編輯和修改,甚至可以通過拖拽的方式修改父節點,僅在最後一刻進行保存,而保存的時候使用工作單元DbContext進行操作,這時候你會發現物化路徑的更新將是一個非常棘手的問題。
樹型結構也有規律可循,甚至TreeGrid上的操作都可以進行抽象,我在領域層定義了ITreeEntity、TreeEntityBase、ITreeEntityQuery、TreeEntityQuery等幾個類和接口,應用層定義ITreeBatchService、TreeBatchService,表現層定義基控制器TreeGridControllerBase。通過這幾個類進行抽象,樹型結構的基本操作都內置到框架中,業務類通過繼承基類就完成了大部分工作。
值得一提的是, TreeGridControllerBase提供了一個加載模式LoadMode,默認為異步加載模式,每次只查詢一級節點。具體控制器通過重寫加載模式,可以切換為同步加載,即一次加載全部節點,另外還提供了一種根節點異步加載模式,即根節點異步加載,下級節點同步加載,通俗的說就是第一次只加載根節點,點擊根節點查詢出全部子節點。當然,這些功能都不需要你手寫代碼,全部內置。
由於本篇只是簡介,後續文章再詳細介紹。
禮物二:EasyUi TreeGrid抽象與封裝
對於樹型實體的編輯操作,一般可以使用Tree控件,再配合一個表單或表格進行,但TreeGrid是更好的選擇。
Easyui treegrid 有很多小bug,比如getChanges方法獲取的結果不正確,分頁總行數錯誤等,這些問題都需要自己解決。
我對treegrid的封裝,除了修復一些bug外,另外對樹型表格上的操作進行了抽象,將基本操作都內置到框架中。
大體功能如下:
- 表格編輯
- 添加根節點
- 添加下級節點
- 插入同級節點(上方)、
- 插入同級節點(下方)
- 自動創建連續的排序號(服務端+客戶端配合完成)
- 上移
- 下移
- 拖拽排序
- 修正排序號
- 拖拽修改父節點
- 限制可拖拽的層級
- 批量修改,一次保存
- 凍結節點
- 啟用節點
- 支持不同加載模式
- 同步加載模式
- 異步加載模式
- 根節點異步加載模式
17. 支持對根節點(第一級節點)分頁
18. 支持查詢時顯示所有上級節點
19. 支持右鍵菜單
先來幾個截圖。
對於表格上的編輯操作,我是用官方提供的edatagrid擴展,復制了一份來改造的,拖拽使用的是官方提供的treegrid.dnd擴展,也簡單改了下 。
關於easyui的性能,如果使用datagrid控件很慢,一般是因為沒有設置列寬,這是必須設置的,不然奇慢。Treegrid雖然從datagrid控件派生,但行為上很多不同,datagrid操作行索引index,而treegrid操作的是id。
我在封裝treegrid的時候發現,40個節點左右,treegrid提供的所有操作id的方法都非常慢,斷點調試能明顯感覺卡一下。由於沒有源碼,無法調優,所以你在使用我提供的拖拽排序和修正排序號這些功能時,發現性能很差不要驚訝,為何純客戶端操作會如此之慢,那是easyui底層的問題,因為需要調用它的相關方法。
至於你擔心我封裝的服務端控件解析可能存在性能問題,一般不需要太緊張,我目前沒有考慮性能,一旦服務端控件解析成為性能瓶頸,我會優化它。
另外一點,由於是一次性保存,可能會批量更新很多節點,對此我沒有進行性能優化,使用的是EF的對象一個個的更新,可能會比較慢,不過考慮到這些操作一般是管理員幹的,慢一點就讓他忍忍好了。
封裝以後,業務代碼就非常簡單了,控制器代碼如下。
視圖還是那麽幹凈,一行js都沒有,代碼如下。
可以看到,雖然treegrid與datagrid顯著不同,但封裝之後,基本沒啥區別,大量降低了學習成本(關於過度封裝的危害,我後續文章再述)。
禮物三:EasyUi ComboTree控件的抽象與封裝
效果如下圖所示。
調用代碼如下。
禮物四: EasyUi ComboBox 控件的抽象與封裝
支持了N級聯動,這在省市區這類場景非常有用,使用非常簡單,設置父控件的Child方法即可。
另外支持了值的延遲加載,easyui默認提供的value並不好用,當控件加載完成之前,會在文本框中顯示出來,很難看,我提供了一個LazyValue來設置值,僅當控件加載完畢才開始設置值。
禮物五:通用業務模塊之字典管理
字典是業務系統中一個重要的模塊,而且也是一個通用模塊,我將這個模塊開放出來供大家參考和使用。
由於字典是一個樹型結構,所以直接繼承樹型實體相關基類即可,采用treegrid進行編輯,註意字典控制器重寫了加載模式為根節點異步加載,當你點擊根節點時,會展示全部下級節點。
同時,我還提供了一個思維導圖供大家參考,我一般采用思維導圖來整理需求。這個文件在Document項目中。
字典管理采用treegrid,這只是進行編輯,那麽如何使用它呢?
我們可以采用combotree控件來展示,如下圖所示。
該如何調用方便呢?可以直接調用combotree控件,然後設置服務端url。
但這是最簡單的調用方式嗎?不是,上面的調用需要記住url和其它一些參數,所以還是容易出錯,我們再進行一層封裝。
你只需要傳遞一個code,即字典編碼,這才是最簡單的調用方式。通過本示例,你會發現封裝是分層次的,必須層層封裝才能讓工作更簡單,當你的業務UI組件大量封裝以後,不僅整個系統簡單優雅,開發難度將顯著降低,而且學習成本也大幅下降。
禮物6:通用業務模塊之地區管理
地區管理也是一個重要的通用模塊,並且也是基於樹型結構,所以這次順便開放出來。
封裝很簡單,主要依賴combox的N級聯動和延遲設置值。
調用代碼如下。
由於EasyUi坑很多,沒有一個照應將會走不少彎路,所以特開一個EasyUi專群(157809322),本群僅限EasyUi開發者,以後碰到問題,大家互相幫助。
下一篇將繼續介紹表現層和MVC——MVC的封裝和抽象。
這回下載提供了兩個數據庫,請下載後還原,就可以看到效果了,無法還原的使用PD導出腳本。
同誌們記得推薦哦,下載地址:
http://files.cnblogs.com/files/xiadao521/Applications.2015.3.5.1.rar
http://files.cnblogs.com/files/xiadao521/Framework.2015.3.5.1.rar
http://files.cnblogs.com/files/xiadao521/Data.2015.3.5.1.rar
最後,祝各位新年快樂,元宵快樂,吉祥如意。
.Net應用程序框架交流QQ群: 386092459,歡迎有興趣的朋友加入討論。
.Net Easyui開發交流QQ群(本群僅限Easyui開發者,非Easyui開發者勿進):157809322
謝謝大家的持續關註,我的博客地址:http://www.cnblogs.com/xiadao521/
EasyUi TreeGrid封裝