這幾夜心里頗不平靜, 奈何 JS水平有限,前臺效果耗時四天,后臺傳值一天,直至昨夜丑時測試初步完成,其實就是一個給tree來授權,網上開源的插件很多,如treeview、treejs、easyui 等等,只是這里授權稍有不同,在新增角色的時候,可以同時對所有功能進行授權, 如下圖,只能放在Table中去實現。一行一行的寫js,最后寫的差不多有個200多行。
項目原界面不方便截圖,這里隨手寫個原生態的 Demo ,當然比較丑
如圖所示,首先這是一個Table,無論枝節點還是葉節點都作為一行(tr),功能菜單列表中葉節點(無分支) 后對應新增、修改等六個功能(復選框)
先來說說前臺需要實現的效果:
①點擊枝節點,其下所有的節點(枝/葉)收縮/展開
②點擊枝節點前的復選框,其下所有節點(枝/葉)、葉節點所在行的新增、修改等復選框勾選/取消
eg: 點擊藍圈中的復選框,則紅框內所有的復選框都被勾選/取消
針對JQ,只要能給每個標簽一個值,name、id之類的用以區別,就能使用Jquery選擇器來確定該元素
給所有枝節點嵌套一個 id 為 spid 的標簽<span>用來標識
<tr id="11000"> <td colspan="7"><input name="c0" id="1-0000c" type="checkbox"/><span id="spid" >1-0000</span></td> </tr> <tr id="11-000" style="text-indent: 10px"> <td><input name="c1" id="11-000c" type="checkbox"/><span>11-000</span></td> <td><input name="A" id="11-000cA" type="checkbox"/></td> <td><input name="B" id="11-000cB" type="checkbox"/></td> <td><input name="C" id="11-000cC" type="checkbox"/></td> <td><input name="D" id="11-000cD" type="checkbox"/></td> <td><input name="E" id="11-000cE" type="checkbox"/></td> <td><input name="F" id="11-000cF" type="checkbox"/></td> </tr>
說白了,就是用Table的方式來實現一個Tree的效果,這里子節點和葉節點是用<tr>的縮進長度來達到層級節點的效果
針對收縮/展開
只要能夠選擇到枝節點里面的span標簽,既可用toggle()來隱藏/展開子節點。根據命名的特點使用拼接id的方法來選擇子節點,即可實現.
然后分情況,依次判斷是鼠標點擊的是幾級枝節點,如果是一級,則只需要隱藏/展開其下的葉節點;如果是兩級,要隱藏/展開其下的枝節點、葉節點;以此類推
比如當點擊籃框所在的枝節點23-000時,葉節點231-00、23200、枝節點23300及葉節點2331-0、2332-0 均要隱藏/展開。
var lenth = $(this).parent().parent().attr('id').indexOf("-"); var s = $(this).parent().parent().attr('id').substring(0, lenth);
判斷前,先得到當前對象所在的 tr 的 id 中的字符 - 的位置,根據該位置可知當前鼠標點擊的是何級枝節點,然后隱藏/展開其下節點即可,此時對應的 lenth == 2 ,則有
$(this).parent().parent().siblings("#" + s + i + '-' + '00').toggle(); for (var q = 1; q < 6; q++) { if ($("#" + s + i + q + '-' + '0').is(":hidden")){ $(this).parent().parent().siblings("#" + s + i + q + '-' + '0').toggle(); } $(this).parent().parent().siblings("#" + s + i + q + '-' + '0').toggle(); }
若lenth == 3 ,即為最里層枝節點,則有
$(this).parent().parent().siblings("#" + s + i + '-' + '0').toggle();
若lenth ==1 ,即為最外面的枝節點(根節點),同樣是按照id的拼接方法來判斷,不同的是,需要多循環一層而已
$(this).parent().parent().siblings("#" + s + i + '-' + '000').toggle(); for (var j = 1; j < 6; j++) { if ($("#" + s + i + j + '-' + '00').is(":hidden")) { $(this).parent().parent().siblings("#" + s + i + j + '-' + '00').toggle(); } $(this).parent().parent().siblings("#" + s + i + j + '-' + '00').toggle(); for (var p = 1; p < 6; p++) { if ($("#" + s + i + j + p + '-' + '0').is(":hidden")) { $(this).parent().parent().siblings("#" + s + i + j + p + '-' + '0').toggle(); } $(this).parent().parent().siblings("#" + s + i + j + p + '-' + '0').toggle(); } }
根據觀察比較,發現就是一層一層的去選擇節點,節點越靠外,最外是根節點,那么需要遍歷的層次就越多,同理,越內側,遍歷次數就越少。用到了大量的 if else 語句,其中又和 for 語句相互嵌套,層層相扣,寫完之后,我的感覺是,除了自己,估計很難有另外一個人能在短時間內明白,自己再也不要去維護自己寫的這個菜單授權。仔細思索,其實是可以進行大量優化代碼,比如:點擊第三層需要循環第二層和第一層,點擊第二層需要循環第一層,點擊第一層需要循環其下的葉節點,那么我最后的解決方案時采用 直接放在一個方法里面,然后用$.each() 來遍歷,把葉節點放在最下面,一層一層,這樣一來,代碼果然看的很舒服,質量也提高不少。
而對于單選/多選/全選/反選
相對來說判斷的情況復雜一些,主要是需要結合后臺邏輯,比如說:
三級葉節點勾選,則三級枝節點勾選、二級枝節點勾選、一級枝節點勾選
二級枝節點勾選,則其下所有子節點勾選,其上一級枝節點勾選
首先還是分情況討論,思路如下
if 勾選授權行(葉節點)所在的第一列(11-000、12-000)
其所在行的每一個節點均勾選(新增、修改、刪除等)
其上 各級直系枝節點勾選
else
if 勾選授權行所在的其他列(新增、修改、刪除、修改、上傳、下載)
當個數不少于1一個時,其第一列也要勾選(涉及到后臺的傳值), 其上 各級直系枝節點勾選
當個數為0時(點擊兩下),其第一列不勾選,其上父級節點的兄弟節點(大爹、二爹、小爹)若均無勾選,則祖父節點不勾選,
所有其一勾選,則祖父節點仍勾選,依次類推,直至根節點
else 勾選枝節點時
if 一級節點 逐級遍歷,其下所有子節點勾選,其上若兄弟節點均無勾選,則父節點不勾選,若有其一勾選,則父節點勾選
if 二級節點 逐級遍歷,其下所有子節點勾選,其上若兄弟節點均無勾選,則父節點不勾選,若有其一勾選,則父節點勾選,以此類推,直至祖父節點
if 三級節點 逐級遍歷,其下所有子節點勾選,其上若兄弟節點均無勾選,則父節點不勾選,若有其一勾選,則父節點勾選,以此類推,直至曾祖父節點
如此,就把所有的情況都考慮進去,按部就班,一行一行的碼js,即可達到要求,代碼有點多,思路就是這樣,這里就不貼詳細代碼
上面都是前臺的效果,下面來說說后臺傳值,這里有些技巧,值得一說,我給每個授權對應的td 都賦有name 值,這里其值對應的是角色表中某功能數據中一個列,比如,選擇11-000,新增、刪除;則表中會授權列會記錄 A、B 。寫到這里,無非就是一些傳值,直接記錄用Ajax傳遞后臺接受即可,用Push方法,具體的在 MVC與Ajax應用 中刪除一節有詳細記錄。這里也不再贅述。寫到這里,文中唯一值得說兩句的便是下文。當對某個角色的權限進行修改時,初次加載該界面,Table 表中的復選框 會對照 該角色本身的功能及權限,會有勾選。說白了就是點擊修改的時候,會有傳值的動作,先去數據庫中 根據該角色的主鍵信息,撈取其擁有的功能和對應的權限,根據這些數據Table表中的Checkbox 會有一個初始值。
這里用到了Each,不得不說真方便。
先在后臺拿到 兩列(功能列表、權限)的集合,然后傳到前臺View中(Authlist)
緊接著根據 @Html.Raw(Json.Encode(Authlist)) 將其轉換為Json 數組
再對其遍歷,最后根據其值給授權復選框一個初始值,具體如下:
function getcheck() { $("input[type=checkbox]").prop("checked", false); var data=@Html.Raw(Json.Encode(Authlist)); $.each(data,function(i, item) { var array = item.WebFunctItem.toString().split(','); var local = item.FunctID.toString().indexOf("0"); var sfunctid = item.FunctID.toString().substring(0, local); var lastnumber = item.FunctID.toString().substr(item.FunctID.length-1, 1); if (lastnumber === "0") { $("#" + sfunctid + '-' + Getzero(local) + 'u').prop("checked", true); for (var i = 0; i < array.length; i++) { $("#" + sfunctid + '-' +Getzero(local) + 'u'+array[i]).prop("checked", true); } } else { $("#" + item.FunctID.toString() + '-' + 'u').prop("checked", true); for (var i = 0; i < array.length; i++) { $("#" + item.FunctID.toString() + "-u" + array[i]).prop("checked", true); } } }); }
寫到這里,自然并沒有結束,對于前臺來說,效果僅僅實現了三分之一,其實最麻煩的是 ,挨個節點去做判斷,這里是Table標簽,只能挨個去遍歷,新增的話還好說,當對角色權限做修改操作時,因較難判斷出復選框狀態的改變/不改變。比如,未做修改,或者僅對已存在的功能菜單作部分權限(增、刪、改、查等)調整時,這時Ajax 傳值,后臺Update語句有效;如果勾選新的功能菜單,這是ajax傳值,后臺的Update語句無法完成,只能對新增的功能菜單執行Insert 方有效,此時,前臺就需要判斷哪些是對原有菜單的功能進行修改,哪些是新增的菜單及菜單下被授權的功能,如此,是很難做出判斷,對此,后臺邏輯控制為: 先刪除該角色所有的功能,然后逐個新增 ,刪除 和 新增的 sql 進行疊加,然后調用一個事物,以免中途語句執行失敗可回滾至原始值。
最近都在忙于前臺樣式,這個項目進行到此處,著實讓自己的JS水平 提高了一把,業務水平的最好的提高果真就是實踐,然后不斷的測試、測試、測試
市人皆大笑,舉手揶揄之
文章列表