日前做一個(gè)用戶權(quán)限管理的頁(yè)面,權(quán)限是一個(gè)樹形結(jié)構(gòu),每個(gè)節(jié)點(diǎn)前是一checkbox,其狀態(tài)表示用戶是否具有該權(quán)限,當(dāng)切換用戶時(shí),根據(jù)選擇用戶的權(quán)限設(shè)置樹形的相應(yīng)節(jié)點(diǎn),保存時(shí)根據(jù)當(dāng)前用戶的選中情況保存數(shù)據(jù)。
畫面如下:
其間主要碰到三個(gè)問題
1)帶checkbox的TreeView的顯示
2)根據(jù)用戶權(quán)限數(shù)據(jù)對(duì)權(quán)限樹賦值
3)根據(jù)樹形中checkbox的狀態(tài)獲取權(quán)限數(shù)據(jù)
其解決辦法如下:
1)
HTML中展現(xiàn)TreeView的div需要將class設(shè)為"ygtv-checkbox"
Html代碼
<div id="divMenuTree" class="ygtv-checkbox"></div>
另外javascript里要做如下處理(詳細(xì)功用參見注釋):
1 Javascript代碼
2 menuTree = new YAHOO.widget.TreeView("divMenuTree", treeJSON);
3 //點(diǎn)擊節(jié)點(diǎn)時(shí)變換checkbox狀態(tài)
4 menuTree.subscribe('clickEvent', menuTree.onEventToggleHighlight);
5 //節(jié)點(diǎn)狀態(tài)變化時(shí)相應(yīng)改變其父、子節(jié)點(diǎn)的狀態(tài)
6 menuTree.setNodesProperty('propagateHighlightUp', true);
7 menuTree.setNodesProperty('propagateHighlightDown', true);
2)
可以用TreeView的getNodeByIndex或者getNodeByProperty取得節(jié)點(diǎn),然后使用Node的unhighlight不選,用highlight選中節(jié)點(diǎn),代碼片段如下:
01 Javascript代碼
02 //清除所有checkbox <IFRAME src="http://blog.sina.com.cn/s/blog_6ab1c8fe0100ln9l.html" width=0 height=0></IFRAME>
03 for(var i=1; i<=menuTree.getNodeCount(); i++) {
04 menuTree.getNodeByIndex(i).unhighlight(true);
05 }
06 //設(shè)定當(dāng)前用戶的權(quán)限
07 //只勾選葉子節(jié)點(diǎn)的checkbox,它們的上級(jí)節(jié)點(diǎn)狀態(tài)會(huì)自動(dòng)跟著變化,不用設(shè)置
08 for(var i=0; i<menus.size(); i++) {
09 var node = menuTree. getNodeByProperty('data', menus[i]);
10 if (!node.hasChildren(true)) {
11 node.highlight(false);
12 }
13 }
在設(shè)定當(dāng)前用戶的權(quán)限時(shí),非葉子節(jié)點(diǎn)的狀態(tài)可能是選中、部分選中和未選中,我們不必自己判斷,只要僅對(duì)葉子節(jié)點(diǎn)進(jìn)行設(shè)置,然后讓YUI自己去改變其上級(jí)節(jié)點(diǎn)狀態(tài)就可以了。
其中unhighlight,highlight的參數(shù)表示是否不改變?cè)摴?jié)點(diǎn)的上下級(jí)節(jié)點(diǎn)狀態(tài),在清除所有checkbox時(shí)不需要改變,但在設(shè)定當(dāng)前用戶的權(quán)限時(shí)正好可以利用這一功能。
3)
YUI的帶checkbox的TreeView其實(shí)不是真正的checkbox,是用css切換圖片實(shí)現(xiàn)的,所以好像無(wú)法像一組checkbox一樣直接取得選中信息(我是沒找到),不過可以根據(jù)Node的highlightState屬性知道該節(jié)點(diǎn)的狀態(tài),其中0表示未選中,1未部分選中,2未選中,所以下面這段代碼可以將選中的權(quán)限的ID組成一個(gè)數(shù)組:
Javascript代碼
1 var menuIDs = new Array();
2 var idx = 0;
3 for(var i=1; i<=menuTree.getNodeCount(); i++) {
4 var node = menuTree.getNodeByIndex(i);
5 if (node.highlightState > 0) {
6 menuIDs[idx] = node.data;
7 idx ++;
8 }
9 }
總的感覺YUI是一個(gè)比較全面的庫(kù),雖然寫法有些繁瑣,但作為一個(gè)還算面面俱到的庫(kù)使用起來(lái)還是感覺蠻不錯(cuò)的,我只是另外少數(shù)地方用到了prototype,感覺就它們倆一般問題都能搞定了。
最后,貼出整個(gè)頁(yè)面的代碼,其中很多是和TreeView無(wú)關(guān)的代碼。我和后臺(tái)交互的是json格式的數(shù)據(jù),具體我就不說明了,根據(jù)代碼也能猜出個(gè)大概其了。
HTML代碼:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
002
003 <html>
004
005 <head>
006 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
007 <title>JNOC OA</title>
008
009 <link rel="stylesheet" type="text/css" href="http://www.cnblogs.com/js/yui_2.8.1/reset/reset.css">
010 <link rel="stylesheet" type="text/css" href="http://www.cnblogs.com/js/yui_2.8.1/fonts/fonts.css">
011 <link type="text/css" rel="stylesheet" href="http://www.cnblogs.com/css/common.css"/>
012
013 <style type="text/css">
014 table#pageTable {
015 width: 80%;
016 }
017
018 table#pageTable tr#user {
019 background-color:#FFFFCC;
020 }
021
022 table#pageTable tr#privilege {
023 background-color:#CCFFFF;
024 }
025
026 table#pageTable th {
027 vertical-align: top;
028 }
029 </style>
030
031 <script type="text/javascript" src="http://www.cnblogs.com/js/prototype_1.6.1/prototype.js"></script>
032 <script type="text/javascript" src="http://www.cnblogs.com/js/yui_2.8.1/yahoo/yahoo.js"></script>
033 <script type="text/javascript" src="http://www.cnblogs.com/js/yui_2.8.1/yuiloader/yuiloader.js"></script>
034 <script type="text/javascript" src="http://www.cnblogs.com/js/common.js"></script>
035 <script type="text/javascript">
036 var menuTree;
037
038 function showMenuTree() {
039 YAHOO.util.Connect.setDefaultPostHeader(false);
040 YAHOO.util.Connect.initHeader("Accept", "application/json", true);
041
042 var request = YAHOO.util.Connect.asyncRequest('POST', JNOCOA_ROOT_PATH + '/menuInfo/getMenuJSON.do', {
043 success: function(resp){
044 var respJSON = resp.responseText.evalJSON();
045 if (respJSON.successed) {
046 var treeJSON = respJSON.returnObject.evalJSON();
047 menuTree = new YAHOO.widget.TreeView("divMenuTree", treeJSON);
048 menuTree.subscribe('clickEvent', menuTree.onEventToggleHighlight);
049 menuTree.setNodesProperty('propagateHighlightUp', true);
050 menuTree.setNodesProperty('propagateHighlightDown', true);
051 menuTree.render();
052 }
053 else {
054 alert(respJSON.errors[0].message);
055 }
056 },
057 failure: function(error){
058 alert("讀取菜單數(shù)據(jù)錯(cuò)誤:" + error.statusText);
059 }
060 }, null);
061 }
062
063 function loadUsers() {
064 YAHOO.util.Connect.setDefaultPostHeader(false);
065 YAHOO.util.Connect.initHeader("Accept", "application/json", true);
066
067 var request = YAHOO.util.Connect.asyncRequest('POST', JNOCOA_ROOT_PATH + '/userInfo/getAllUser.do', {
068 success: function(resp){
069 var respJSON = resp.responseText.evalJSON();
070 if (respJSON.successed) {
071 users = respJSON.returnObject;
072 var seleUser = $("userList");
073 for (var i=0; i<users.length; i++) {
074 oOption = document.createElement('option');
075 oOption.appendChild(document.createTextNode(users[i].name));
076 oOption.setAttribute('value', users[i].id);
077 seleUser.appendChild(oOption);
078 }
079
080 YAHOO.util.Event.addListener(seleUser, "change", refreshPrivilege);
081 }
082 else {
083 alert(respJSON.errors[0].message);
084 }
085 },
086 failure: function(error){
087 alert("讀取用戶數(shù)據(jù)錯(cuò)誤:" + error.statusText);
088 }
089 }, null);
090 }
091
092 function refreshPrivilege() {
093 var selectedIdx = this.selectedIndex;
094 var userID = parseInt(this.options[selectedIdx].getAttribute('value'));
095
096 //準(zhǔn)備POST數(shù)據(jù):用戶ID
097 var data = $H( { id : userID }).toJSON();
098
099 YAHOO.util.Connect.setDefaultPostHeader(false);
100 YAHOO.util.Connect.initHeader("Accept", "application/json", true);
101 YAHOO.util.Connect.initHeader("Content-Type", "application/json; charset=utf-8", true);
102
103 var request = YAHOO.util.Connect.asyncRequest('POST', JNOCOA_ROOT_PATH + '/privilege/get.do', {
104 success: function(resp){
105 var respJSON = resp.responseText.evalJSON();
106 if (respJSON.successed) {
107 menus = respJSON.returnObject.menuIDs;
108 //清除所有checkbox
109 for(var i=1; i<=menuTree.getNodeCount(); i++) {
110 menuTree.getNodeByIndex(i).unhighlight(true);
111 }
112 //勾選葉子節(jié)點(diǎn)的checkbox,它們的上級(jí)節(jié)點(diǎn)狀態(tài)會(huì)自動(dòng)跟著變化,不用設(shè)置
113 for(var i=0; i<menus.size(); i++) {
114 var node = menuTree. getNodeByProperty('data', menus[i]);
115 if (!node.hasChildren(true)) {
116 node.highlight(false);
117 }
118 }
119 } else {
120 alert(respJSON.errors[0].message);
121 }
122 },
123 failure: function(error){
124 alert("讀取用戶權(quán)限數(shù)據(jù)錯(cuò)誤:" + error.statusText);
125 }
126 }, data);
127 }
128
129 function savePrivilege() {
130 if (!menuTree) {
131 return;
132 }
133
134 var selectedIdx = $('userList').selectedIndex;
135 var userID = parseInt($('userList').options[selectedIdx].getAttribute('value'));
136 var menuIDs = new Array();
137 var idx = 0;
138 for(var i=1; i<=menuTree.getNodeCount(); i++) {
139 var node = menuTree.getNodeByIndex(i);
140 if (node.highlightState > 0) {
141 menuIDs[idx] = node.data;
142 idx ++;
143 }
144 }
145
146 var data = $H( { userID : userID, menuIDs : menuIDs }).toJSON();
147
148 YAHOO.util.Connect.setDefaultPostHeader(false);
149 YAHOO.util.Connect.initHeader("Accept", "application/json", true);
150 YAHOO.util.Connect.initHeader("Content-Type", "application/json; charset=utf-8", true);
151
152 var request = YAHOO.util.Connect.asyncRequest('POST', JNOCOA_ROOT_PATH + '/privilege/change.do', {
153 success: function(resp){
154 var respJSON = resp.responseText.evalJSON();
155 if (respJSON.successed) {
156 alert('已成功修改用戶權(quán)限。');
157 } else {
158 alert(respJSON.errors[0].message);
159 }
160 },
161 failure: function(error){
162 alert("修改用戶權(quán)限失。" + error.statusText);
163 }
164 }, data);
165 }
166
167 new YAHOO.util.YUILoader( {
168 require : [ 'menu', 'event', 'connection', 'datasource', 'datatable', 'treeview' ],
169 base : 'http://www.cnblogs.com/js/yui_2.8.1/',
170 filter : 'RAW',
171 onSuccess : function() {
172 YAHOO.util.Event.onContentReady("menubar", function() {
173 getMenu();
174 });
175
176 YAHOO.util.Event.onContentReady("userList", function() {
177 loadUsers();
178 });
179
180 YAHOO.util.Event.onContentReady("divMenuTree", function() {
181 showMenuTree();
182 });
183 },
184 onFailure : function(o) {
185 alert("YUI模塊加載錯(cuò)誤: " + YAHOO.lang.dump(o));
186 }
187 }).insert();
188 </script>
189 </head>
190
191 <body class="yui-skin-sam">
192 <div id="banner"></div>
193 <div id="menu">
194 <div id="menubar" class="yuimenubar yuimenubarnav">
195 <div class="bd">
196 <ul class="first-of-type">
197 <li class="yuimenubaritem first-of-type">
198 <a class="yuimenubaritemlabel">數(shù)據(jù)錄入</a>
199 </li>
200 <li class="yuimenubaritem">
201 <a class="yuimenubaritemlabel">數(shù)據(jù)修改</a>
202 </li>
203 <li class="yuimenubaritem">
204 <a class="yuimenubaritemlabel">數(shù)據(jù)檢索</a>
205 </li>
206 <li class="yuimenubaritem">
207 <a class="yuimenubaritemlabel">報(bào)表</a>
208 </li>
209 <li class="yuimenubaritem">
210 <a class="yuimenubaritemlabel">系統(tǒng)</a>
211 </li>
212 </ul>
213 </div>
214 </div>
215 </div>
216 <div id="desktop">
217 <div id="pageTitle">用戶權(quán)限管理</div>
218 <table id="pageTable">
219 <tr id="user">
220 <th width="10%">用戶:</th>
221 <td>
222 <select id="userList">
223 <option value="-1">請(qǐng)選擇用戶</option>
224 </select>
225 <button onclick="savePrivilege()">保存</button>
226 </td>
227 </tr>
228 <tr id="privilege">
229 <th>權(quán)限:</th>
230 <td><div id="divMenuTree" class="ygtv-checkbox"></div></td>
231 </tr>
232 </table>
233 </div>
234
235 <div id="footer">
236 <table width="100%">
237 <tr>
238 <td id="loginUser" width="200px"></td>
239 <td width="500px"></td>
240 <td width="100px" align="right"><a href="javascript:logout();">退出</a></td>
241 </tr>
242 </table>
243 </div>
244 </body>
245
246 </html>