UPDATE:回答網友提出的設置節點的自定義圖片的問題,同時歡迎你們提問,我儘可能在第一時間回覆,詳見最後 2009-11-03javascript
項目中常常會遇到樹形數據的展示,包括導航,選擇等功能,因此樹控件在大多項目中都是必須的。那一個實用的樹應該具有什麼功能呢?css
根據個人項目實踐狀況,主要是幾個關鍵點:html
1:支持靜態的樹,即一次性將所有數據加載到客戶端。java
2:異步樹,即一次只加載一級或若干級節點,子節點能夠異步加載數據。node
3:Checkbox樹(多是靜態樹也多是異步樹),用於選擇(如選擇組織機構,選擇數據字典項)等,最好是可以支持節點級聯(這個是難點)jquery
4:可以承載大數據量,並性能表現優異web
5:可以在主流瀏覽器中運行良好ajax
那我要打造的TreeView就是爲了實現這個5個主要指標的。json
先來看下效果圖windows
上圖是中國行政區域的數據樹,總共得節點是3500+。
那麼咱們要開工了;
1:第一個肯定的節點Dom結構(即用什麼樣的HTML來構建節點)
- 比較土的是table套table的(樣式上好控制,可是大數據量,和層次較深的樹,這種結構確定頂不住的)
- 還有一種是比較新鮮的UL套LI的方式,這是現下不少書採起的方式如Jquery.treeview就是採用的這種格式,好處比較明顯就是結構簡潔明瞭,
並且在不支持Js的瀏覽器上,一樣也能呈現出樹的形狀(這種狀況其實咱能夠忽略),可是Jquery.treeview的節點在IE下,特別是IE6下沒法被內部元素撐開,(IE7,8當達到必定深度時沒法撐開),請奇怪的現象(我猜想是由於使用padding來作縮進,margin-left:負值來控制圖標位置有關,可是修改起來難度也較大),在這種狀況下書會變形(Jquery.treeview)就有這種問題,只能經過設置節點的width來解決。
JQuery.treeview的節點結構
Jquery.TreeView IE6 下 展開第三級即出現錯位
而我採用的也是第二種方式,可是縮進採用了填空的方式,即縮進的位置用空白的圖片填充來避免Jquery.treeview的問題
個人樹節點結構
肯定了節點的HTML咱們就能夠來寫CSS了。有了效果圖,有個節點結構接着就編寫CSS了
下面是CSS的完整代碼
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
|
.ie .bbit-tree .bbit-tree-bwrap{
}
.bbit-tree ul,.bbit-tree li
{
list-style-type
:
none
;
margin
:
0px
;
padding
:
0px
;
}
.bbit-tree-body
{
font-size
:
12px
;
}
.bbit-tree-
icon
, .bbit-tree-ec-
icon
, .bbit-tree-node-cb,.bbit-tree-elbow-line, .bbit-tree-elbow, .bbit-tree-elbow-end, .bbit-tree-elbow-plus, .bbit-tree-elbow-minus, .bbit-tree-elbow-end-plus, .bbit-tree-elbow-end-minus{
border
:
0
none
;
height
:
18px
;
margin
:
0
;
padding
:
0
;
vertical-align
:
top
;
width
:
16px
;
background-repeat
:
no-repeat
;
}
.bbit-tree-node-cb
{
height
:
16px
;
}
.bbit-tree-node-collapsed .bbit-tree-node-
icon
, .bbit-tree-node-
expanded
.bbit-tree-node-
icon
, .bbit-tree-node-leaf .bbit-tree-node-
icon
{
border
:
0
none
;
height
:
18px
;
margin
:
0
;
padding
:
0
;
vertical-align
:
top
;
width
:
16px
;
background-position
:
center
;
background-repeat
:
no-repeat
;
}
.ie .bbit-tree-node-indent img, .ie .bbit-tree-node-
icon
, .ie .bbit-tree-ec-
icon
{
vertical-align
:
middle
!important
;
}
.bbit-tree-noicon .bbit-tree-node-
icon
{
width
:
0
;
height
:
0
;
}
/* No line styles 沒有線的樣式 */
.bbit-tree-no-lines .bbit-tree-elbow{
background
:
transparent
;
}
.bbit-tree-no-lines .bbit-tree-elbow-end{
background
:
transparent
;
}
.bbit-tree-no-lines .bbit-tree-elbow-line{
background
:
transparent
;
}
/* Arrows Vista系統樹的樣式只有箭頭*/
.bbit-tree-arrows .bbit-tree-elbow{
background
:
transparent
;
}
.bbit-tree-arrows .bbit-tree-elbow-plus{
background
:
transparent
no-repeat
0
0
;
}
.bbit-tree-arrows .bbit-tree-elbow-minus{
background
:
transparent
no-repeat
-16px
0
;
}
.bbit-tree-arrows .bbit-tree-elbow-end{
background
:
transparent
;
}
.bbit-tree-arrows .bbit-tree-elbow-end-plus{
background
:
transparent
no-repeat
0
0
;
}
.bbit-tree-arrows .bbit-tree-elbow-end-minus{
background
:
transparent
no-repeat
-16px
0
;
}
.bbit-tree-arrows .bbit-tree-elbow-line{
background
:
transparent
;
}
.bbit-tree-arrows .bbit-tree-ec-over .bbit-tree-elbow-plus{
background-position
:
-32px
0
;
}
.bbit-tree-arrows .bbit-tree-ec-over .bbit-tree-elbow-minus{
background-position
:
-48px
0
;
}
.bbit-tree-arrows .bbit-tree-ec-over .bbit-tree-elbow-end-plus{
background-position
:
-32px
0
;
}
.bbit-tree-arrows .bbit-tree-ec-over .bbit-tree-elbow-end-minus{
background-position
:
-48px
0
;
}
.bbit-tree-elbow-plus, .bbit-tree-elbow-minus, .bbit-tree-elbow-end-plus, .bbit-tree-elbow-end-minus{
cursor
:
pointer
;
}
.ie ul.bbit-tree-node-ct{
font-size
:
0
;
line-height
:
0
;
zoom:
1
;
}
.bbit-tree-node{
white-space
:
nowrap
;
}
.bbit-tree-node-el {
line-height
:
18px
;
cursor
:
default
;
/* cursor:pointer;*/
}
.bbit-tree-node a{
text-decoration
:
none
;
-khtml-user-select:
none
;
-moz-user-select:
none
;
-webkit-user-select:ignore;
-kthml-user-focus:
normal
;
-moz-user-focus:
normal
;
-moz-
outline
:
0
none
;
outline
:
0
none
;
}
.bbit-tree-node a span{
text-decoration
:
none
;
padding
:
1px
3px
1px
2px
;
}
.bbit-tree-node .bbit-tree-node-disabled .bbit-tree-node-
icon
{
-moz-opacity:
0.5
;
opacity:.
5
;
filter: alpha(opacity=
50
);
}
.bbit-tree-node .bbit-tree-node-inline-
icon
{
background
:
transparent
;
}
.bbit-tree-node a:hover{
text-decoration
:
none
;
}
/* Fix for ie rootVisible:false issue,修正一個IEdebug */
.bbit-tree-root {
zoom:
1
;
}
/***********這裏是圖標了,能夠在這裏替換哦*****************/
.bbit-tree-node-
expanded
.bbit-tree-node-
icon
{
background-image
:
url
(images/tree/folder-open.gif);
}
.bbit-tree-node-leaf .bbit-tree-node-
icon
{
background-image
:
url
(images/tree/leaf.gif);
}
.bbit-tree-node-collapsed .bbit-tree-node-
icon
{
background-image
:
url
(images/tree/folder.gif);
}
.bbit-tree-node-loading .bbit-tree-node-
icon
{
background-image
:
url
(images/tree/loading.gif)
!important
;
}
.bbit-tree-node .bbit-tree-node-inline-
icon
{
background-image
:
none
;
}
.bbit-tree-node-loading a span{
font-style
:
italic
;
color
:
#444444
;
}
.bbit-tree-lines .bbit-tree-elbow{
background-image
:
url
(images/tree/elbow.gif);
}
.bbit-tree-lines .bbit-tree-elbow-plus{
background-image
:
url
(images/tree/elbow-plus.gif);
}
.bbit-tree-lines .bbit-tree-elbow-minus{
background-image
:
url
(images/tree/elbow-minus.gif);
}
.bbit-tree-lines .bbit-tree-elbow-end{
background-image
:
url
(images/tree/elbow-end.gif);
}
.bbit-tree-lines .bbit-tree-elbow-end-plus{
background-image
:
url
(images/tree/elbow-end-plus.gif);
}
.bbit-tree-lines .bbit-tree-elbow-end-minus{
background-image
:
url
(images/tree/elbow-end-minus.gif);
}
.bbit-tree-lines .bbit-tree-elbow-line{
background-image
:
url
(images/tree/elbow-line.gif);
}
.bbit-tree-no-lines .bbit-tree-elbow-plus{
background-image
:
url
(images/tree/elbow-plus-nl.gif);
}
.bbit-tree-no-lines .bbit-tree-elbow-minus{
background-image
:
url
(images/tree/elbow-minus-nl.gif);
}
.bbit-tree-no-lines .bbit-tree-elbow-end-plus{
background-image
:
url
(images/tree/elbow-end-plus-nl.gif);
}
.bbit-tree-no-lines .bbit-tree-elbow-end-minus{
background-image
:
url
(images/tree/elbow-end-minus-nl.gif);
}
.bbit-tree-arrows .bbit-tree-elbow-plus{
background-image
:
url
(images/tree/arrows.gif);
}
.bbit-tree-arrows .bbit-tree-elbow-minus{
background-image
:
url
(images/tree/arrows.gif);
}
.bbit-tree-arrows .bbit-tree-elbow-end-plus{
background-image
:
url
(images/tree/arrows.gif);
}
.bbit-tree-arrows .bbit-tree-elbow-end-minus{
background-image
:
url
(images/tree/arrows.gif);
}
/*TreeNode 選中的Disabled的一些顏色,字體樣式*/
.bbit-tree-node{
color
:
#000
;
font
:
normal
11px
arial
,
tahoma
,
helvetica
,
sans-serif
;
}
.bbit-tree-node a{
color
:
#000
;
}
.bbit-tree-node a span{
color
:
#000
;
}
.bbit-tree-node .bbit-tree-node-disabled a span{
color
:
gray
!important
;
}
.bbit-tree-node .bbit-tree-node-over {
background-color
:
#eee
;
}
.bbit-tree-node .bbit-tree-selected {
background-color
:
#d9e8fb
;
}
|
上面了樹的基本樣式外,定義了一個有+號帶line的樣式和+號不帶line的樣式
css中所用到的全部圖片
2:肯定數據結構
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
var
menudata = [{
id:
"0.1"
,
//惟一的ID便可
text:
"Beyondbit UI Demo"
,
hasChildren:
true
,
isexpand:
true
,
complete:
true
,
ChildNodes: [{
id:
"0.1.1"
,
text:
"日期選擇"
,
hasChildren:
true
,
isexpand:
false
,
complete:
true
,
ChildNodes: [{
id:
"0.1.1.1"
,
text:
"控件演示"
,
value:
"Testpages/datepickerDemo.htm"
,
hasChildren:
false
,
isexpand:
false
,
complete:
true
,
ChildNodes:
null
},
...
]
|
這樣的結構有個好處就數據自己是帶層次的,很是利於遍歷,在後面的級聯關聯中會看到
3: 面子作好了那就開始作裏子了,編寫腳本(Javascript)
我是JQuery得擁護者,因此天然js的框架天然是採用Jquery了
先上個完整代碼,再逐一分析
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
|
/****************************************
author:xuanye.wan@gmail.com
page:http://xuanye.cnblogs.com/
***************************************/
(
function
($) {
$.fn.swapClass =
function
(c1, c2) {
return
this
.removeClass(c1).addClass(c2);
}
$.fn.switchClass =
function
(c1, c2) {
if
(
this
.hasClass(c1)) {
return
this
.swapClass(c1, c2);
}
else
{
return
this
.swapClass(c2, c1);
}
}
$.fn.treeview =
function
(settings) {
var
dfop =
{
method:
"POST"
,
datatype:
"json"
,
url:
false
,
cbiconpath:
"/images/icons/"
,
icons: [
"checkbox_0.gif"
,
"checkbox_1.gif"
,
"checkbox_2.gif"
],
showcheck:
false
,
//是否顯示選擇
oncheckboxclick:
false
,
//當checkstate狀態變化時所觸發的事件,可是不會觸發因級聯選擇而引發的變化
onnodeclick:
false
,
cascadecheck:
true
,
data:
null
,
clicktoggle:
true
,
//點擊節點展開和收縮子節點
theme:
"bbit-tree-arrows"
//bbit-tree-lines ,bbit-tree-no-lines,bbit-tree-arrows
}
$.extend(dfop, settings);
var
treenodes = dfop.data;
var
me = $(
this
);
var
id = me.attr(
"id"
);
if
(id ==
null
|| id ==
""
) {
id =
"bbtree"
+
new
Date().getTime();
me.attr(
"id"
, id);
}
var
html = [];
buildtree(dfop.data, html);
me.addClass(
"bbit-tree"
).html(html.join(
""
));
InitEvent(me);
html =
null
;
//預加載圖片
if
(dfop.showcheck) {
for
(
var
i = 0; i < 3; i++) {
var
im =
new
Image(16,16);
im.src = dfop.cbiconpath + dfop.icons[i];
}
}
//region
function
buildtree(data, ht) {
ht.push(
"<div class='bbit-tree-bwrap'>"
);
// Wrap ;
ht.push(
"<div class='bbit-tree-body'>"
);
// body ;
ht.push(
"<ul class='bbit-tree-root "
, dfop.theme,
"'>"
);
//root
var
l = data.length;
for
(
var
i = 0; i < l; i++) {
buildnode(data[i], ht, 0, i, i == l - 1);
}
ht.push(
"</ul>"
);
// root and;
ht.push(
"</div>"
);
// body end;
ht.push(
"</div>"
);
// Wrap end;
}
//endregion
function
buildnode(nd, ht, deep, path, isend) {
ht.push(
"<li class='bbit-tree-node'>"
);
ht.push(
"<div id='"
, id,
"_"
, nd.id,
"' tpath='"
, path,
"' unselectable='on'"
);
var
cs = [];
cs.push(
"bbit-tree-node-el"
);
if
(nd.hasChildren) {
cs.push(nd.isexpand ?
"bbit-tree-node-expanded"
:
"bbit-tree-node-collapsed"
);
}
else
{
cs.push(
"bbit-tree-node-leaf"
);
}
if
(nd.classes) { cs.push(nd.classes); }
ht.push(
" class='"
, cs.join(
" "
),
"'>"
);
//span indent
ht.push(
"<span class='bbit-tree-node-indent'>"
);
if
(deep == 1) {
ht.push(
"<img class='bbit-tree-icon' src='../Themes/Shared/images/s.gif'/>"
);
}
else
if
(deep > 1) {
ht.push(
"<img class='bbit-tree-icon' src='../Themes/Shared/images/s.gif'/>"
);
for
(
var
j = 1; j < deep; j++) {
ht.push(
"<img class='bbit-tree-elbow-line' src='../Themes/Shared/images/s.gif'/>"
);
}
}
ht.push(
"</span>"
);
//img
cs.length = 0;
if
(nd.hasChildren) {
if
(nd.isexpand) {
cs.push(isend ?
"bbit-tree-elbow-end-minus"
:
"bbit-tree-elbow-minus"
);
}
else
{
cs.push(isend ?
"bbit-tree-elbow-end-plus"
:
"bbit-tree-elbow-plus"
);
}
}
else
{
cs.push(isend ?
"bbit-tree-elbow-end"
:
"bbit-tree-elbow"
);
}
ht.push(
"<img class='bbit-tree-ec-icon "
, cs.join(
" "
),
"' src='../Themes/Shared/images/s.gif'/>"
);
ht.push(
"<img class='bbit-tree-node-icon' src='../Themes/Shared/images/s.gif'/>"
);
//checkbox
if
(dfop.showcheck && nd.showcheck) {
if
(nd.checkstate ==
null
|| nd.checkstate == undefined) {
nd.checkstate = 0;
}
ht.push(
"<img id='"
, id,
"_"
, nd.id,
"_cb' class='bbit-tree-node-cb' src='"
, dfop.cbiconpath, dfop.icons[nd.checkstate],
"'/>"
);
}
//a
ht.push(
"<a hideFocus class='bbit-tree-node-anchor' tabIndex=1 href='javascript:void(0);'>"
);
ht.push(
"<span unselectable='on'>"
, nd.text,
"</span>"
);
ht.push(
"</a>"
);
ht.push(
"</div>"
);
//Child
if
(nd.hasChildren) {
if
(nd.isexpand) {
ht.push(
"<ul class='bbit-tree-node-ct' style='z-index: 0; position: static; visibility: visible; top: auto; left: auto;'>"
);
if
(nd.ChildNodes) {
var
l = nd.ChildNodes.length;
for
(
var
k = 0; k < l; k++) {
nd.ChildNodes[k].parent = nd;
buildnode(nd.ChildNodes[k], ht, deep + 1, path +
"."
+ k, k == l - 1);
}
}
ht.push(
"</ul>"
);
}
else
{
ht.push(
"<ul style='display:none;'></ul>"
);
}
}
ht.push(
"</li>"
);
nd.render =
true
;
}
function
getItem(path) {
var
ap = path.split(
"."
);
var
t = treenodes;
for
(
var
i = 0; i < ap.length; i++) {
if
(i == 0) {
t = t[ap[i]];
}
else
{
t = t.ChildNodes[ap[i]];
}
}
return
t;
}
function
check(item, state, type) {
var
pstate = item.checkstate;
if
(type == 1) {
item.checkstate = state;
}
else
{
// 上溯
var
cs = item.ChildNodes;
var
l = cs.length;
var
ch =
true
;
for
(
var
i = 0; i < l; i++) {
if
((state == 1 && cs[i].checkstate != 1) || state == 0 && cs[i].checkstate != 0) {
ch =
false
;
break
;
}
}
if
(ch) {
item.checkstate = state;
}
else
{
item.checkstate = 2;
}
}
//change show
if
(item.render && pstate != item.checkstate) {
var
et = $(
"#"
+ id +
"_"
+ item.id +
"_cb"
);
if
(et.length == 1) {
et.attr(
"src"
, dfop.cbiconpath + dfop.icons[item.checkstate]);
}
}
}
//遍歷子節點
function
cascade(fn, item, args) {
if
(fn(item, args, 1) !=
false
) {
if
(item.ChildNodes !=
null
&& item.ChildNodes.length > 0) {
var
cs = item.ChildNodes;
for
(
var
i = 0, len = cs.length; i < len; i++) {
cascade(fn, cs[i], args);
}
}
}
}
//冒泡的祖先
function
bubble(fn, item, args) {
var
p = item.parent;
while
(p) {
if
(fn(p, args, 0) ===
false
) {
break
;
}
p = p.parent;
}
}
function
nodeclick(e) {
var
path = $(
this
).attr(
"tpath"
);
var
et = e.target || e.srcElement;
var
item = getItem(path);
//debugger;
if
(et.tagName ==
"IMG"
) {
// +號須要展開
if
($(et).hasClass(
"bbit-tree-elbow-plus"
) || $(et).hasClass(
"bbit-tree-elbow-end-plus"
)) {
var
ul = $(
this
).next();
//"bbit-tree-node-ct"
if
(ul.hasClass(
"bbit-tree-node-ct"
)) {
ul.show();
}
else
{
var
deep = path.split(
"."
).length;
if
(item.complete) {
item.ChildNodes !=
null
&& asnybuild(item.ChildNodes, deep, path, ul, item);
}
else
{
$(
this
).addClass(
"bbit-tree-node-loading"
);
asnyloadc(ul, item,
function
(data) {
item.complete =
true
;
item.ChildNodes = data;
asnybuild(data, deep, path, ul, item);
});
}
}
if
($(et).hasClass(
"bbit-tree-elbow-plus"
)) {
$(et).swapClass(
"bbit-tree-elbow-plus"
,
"bbit-tree-elbow-minus"
);
}
else
{
$(et).swapClass(
"bbit-tree-elbow-end-plus"
,
"bbit-tree-elbow-end-minus"
);
}
$(
this
).swapClass(
"bbit-tree-node-collapsed"
,
"bbit-tree-node-expanded"
);
}
else
if
($(et).hasClass(
"bbit-tree-elbow-minus"
) || $(et).hasClass(
"bbit-tree-elbow-end-minus"
)) {
//- 號須要收縮
$(
this
).next().hide();
if
($(et).hasClass(
"bbit-tree-elbow-minus"
)) {
$(et).swapClass(
"bbit-tree-elbow-minus"
,
"bbit-tree-elbow-plus"
);
}
else
{
$(et).swapClass(
"bbit-tree-elbow-end-minus"
,
"bbit-tree-elbow-end-plus"
);
}
$(
this
).swapClass(
"bbit-tree-node-expanded"
,
"bbit-tree-node-collapsed"
);
}
else
if
($(et).hasClass(
"bbit-tree-node-cb"
))
// 點擊了Checkbox
{
var
s = item.checkstate != 1 ? 1 : 0;
var
r =
true
;
if
(dfop.oncheckboxclick) {
r = dfop.oncheckboxclick.call(et, item, s);
}
if
(r !=
false
) {
if
(dfop.cascadecheck) {
//遍歷
cascade(check, item, s);
//上溯
bubble(check, item, s);
}
else
{
check(item, s, 1);
}
}
}
}
else
{
if
(dfop.citem) {
$(
"#"
+ id +
"_"
+ dfop.citem.id).removeClass(
"bbit-tree-selected"
);
}
dfop.citem = item;
$(
this
).addClass(
"bbit-tree-selected"
);
if
(dfop.onnodeclick) {
dfop.onnodeclick.call(
this
, item);
}
}
}
function
asnybuild(nodes, deep, path, ul, pnode) {
var
l = nodes.length;
if
(l > 0) {
var
ht = [];
for
(
var
i = 0; i < l; i++) {
nodes[i].parent = pnode;
buildnode(nodes[i], ht, deep, path +
"."
+ i, i == l - 1);
}
ul.html(ht.join(
""
));
ht =
null
;
InitEvent(ul);
}
ul.addClass(
"bbit-tree-node-ct"
).css({
"z-index"
: 0, position:
"static"
, visibility:
"visible"
, top:
"auto"
, left:
"auto"
, display:
""
});
ul.prev().removeClass(
"bbit-tree-node-loading"
);
}
function
asnyloadc(pul, pnode, callback) {
if
(dfop.url) {
var
param = builparam(pnode);
$.ajax({
type: dfop.method,
url: dfop.url,
data: param,
dataType: dfop.datatype,
success: callback,
error:
function
(e) { alert(
"error occur!"
); }
});
}
}
function
builparam(node) {
var
p = [{ name:
"id"
, value: encodeURIComponent(node.id) }
, { name:
"text"
, value: encodeURIComponent(node.text) }
, { name:
"value"
, value: encodeURIComponent(node.value) }
, { name:
"checkstate"
, value: node.checkstate}];
return
p;
}
function
InitEvent(parent) {
var
nodes = $(
"li.bbit-tree-node>div"
, parent);
nodes.each(
function
(e) {
$(
this
).hover(
function
() {
$(
this
).addClass(
"bbit-tree-node-over"
);
},
function
() {
$(
this
).removeClass(
"bbit-tree-node-over"
);
})
.click(nodeclick)
.find(
"img.bbit-tree-ec-icon"
).each(
function
(e) {
if
(!$(
this
).hasClass(
"bbit-tree-elbow"
)) {
$(
this
).hover(
function
() {
$(
this
).parent().addClass(
"bbit-tree-ec-over"
);
},
function
() {
$(
this
).parent().removeClass(
"bbit-tree-ec-over"
);
});
}
});
});
}
function
getck(items, c, fn) {
for
(
var
i = 0, l = items.length; i < l; i++) {
items[i].checkstate == 1 && c.push(fn(items[i]));
if
(items[i].ChildNodes !=
null
&& items[i].ChildNodes.length > 0) {
getck(items[i].ChildNodes, c, fn);
}
}
}
me[0].t = {
getSelectedNodes:
function
() {
var
s = [];
getck(treenodes, s,
function
(item) {
return
item });
return
s;
},
getSelectedValues:
function
() {
var
s = [];
getck(treenodes, s,
function
(item) {
return
item.value });
return
s;
},
getCurrentItem:
function
() {
return
dfop.citem;
}
};
return
me;
}
//獲取全部選中的節點的Value數組
$.fn.getTSVs =
function
() {
if
(
this
[0].t) {
return
this
[0].t.getSelectedValues();
}
return
null
;
}
//獲取全部選中的節點的Item數組
$.fn.getTSNs =
function
() {
if
(
this
[0].t) {
return
this
[0].t.getSelectedNodes();
}
return
null
;
}
$.fn.getTCT =
function
() {
if
(
this
[0].t) {
return
this
[0].t.getCurrentItem();
}
return
null
;
}
})(jQuery);
|
第一步:天然是全部Jquery的控件的第一步都是搭這個架子,兼容JQuery和$避免閉包,避免和其餘類庫衝突,接受一個參數(是個對象)
1
2
3
4
5
6
|
;(
function
($) {
//也可使用$.fn.extend(treeview:function(setting){})
$.fn.treeview =
function
(settings) {
}
})(jQuery);
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
var
dfop ={
method:
"POST"
,
//默認採用POST提交數據
datatype:
"json"
,
//數據類型是json
url:
false
,
//異步請求的url
cbiconpath:
"/images/icons/"
,
//checkbox icon的目錄位置
icons: [
"checkbox_0.gif"
,
"checkbox_1.gif"
,
"checkbox_2.gif"
],
//checkbxo三態的圖片
showcheck:
false
,
//是否顯示checkbox
oncheckboxclick:
false
,
//點擊checkbox時觸發的事件
onnodeclick:
false
,
//點擊node觸發的時間
cascadecheck:
true
,
//是否啓用級聯
data:
null
,
//初始化數據
theme:
"bbit-tree-arrows"
//三種風格備選bbit-tree-lines ,bbit-tree-no-lines,bbit-tree-arrows
}
//用傳進來的參數覆蓋默認,沒傳則保留
$.extend(dfop, settings);
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
var
treenodes = dfop.data;
//內部的數據,其實直接用 dfop.data也能夠
var
me = $(
this
);
var
id = me.attr(
"id"
);
if
(id ==
null
|| id ==
""
) {
id =
"bbtree"
+
new
Date().getTime();
me.attr(
"id"
, id);
}
//全局惟一的ID
var
html = [];
buildtree(dfop.data, html);
//生成展開節點的HTML,push到數組中
me.addClass(
"bbit-tree"
).html(html.join(
""
));
InitEvent(me);
//初始化事件
html =
null
;
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
if
(nd.hasChildren) {
//存在子節點
if
(nd.isexpand) {
//同時節點已經展開則輸出子節點
ht.push(
"<ul class='bbit-tree-node-ct' style='z-index: 0; position: static; visibility: visible; top: auto; left: auto;'>"
);
if
(nd.ChildNodes) {
var
l = nd.ChildNodes.length;
for
(
var
k = 0; k < l; k++) {
//遞歸調用並生產節點的路徑
nd.ChildNodes[k].parent = nd;
buildnode(nd.ChildNodes[k], ht, deep + 1, path +
"."
+ k, k == l - 1);
}
}
ht.push(
"</ul>"
);
}
else
{
//不然是待輸出狀態
ht.push(
"<ul style='display:none;'></ul>"
);
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
function
InitEvent(parent) {
var
nodes = $(
"li.bbit-tree-node>div"
, parent);
nodes.each(
function
(e) {
$(
this
).hover(
function
() {
$(
this
).addClass(
"bbit-tree-node-over"
);
//鼠標浮動節點的樣式變化
},
function
() {
$(
this
).removeClass(
"bbit-tree-node-over"
);
})
.click(nodeclick)
//node的onclick事件,這個是重點哦
.find(
"img.bbit-tree-ec-icon"
).each(
function
(e) {
//arrow的hover事件,爲了實現vista那個風格的
if
(!$(
this
).hasClass(
"bbit-tree-elbow"
)) {
$(
this
).hover(
function
() {
$(
this
).parent().addClass(
"bbit-tree-ec-over"
);
},
function
() {
$(
this
).parent().removeClass(
"bbit-tree-ec-over"
);
});
}
});
});
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
|
function
nodeclick(e) {
var
path = $(
this
).attr(
"tpath"
);
//獲取節點路徑
var
et = e.target || e.srcElement;
//獲取事件源
var
item = getItem(path);
//根據path獲取節點的數據
//debugger;
if
(et.tagName ==
"IMG"
) {
// +號須要展開,處理加減號
if
($(et).hasClass(
"bbit-tree-elbow-plus"
) || $(et).hasClass(
"bbit-tree-elbow-end-plus"
)) {
var
ul = $(
this
).next();
//"bbit-tree-node-ct"
if
(ul.hasClass(
"bbit-tree-node-ct"
)) {
ul.show();
}
else
{
var
deep = path.split(
"."
).length;
if
(item.complete) {
item.ChildNodes !=
null
&& asnybuild(item.ChildNodes, deep, path, ul, item);
}
else
{
$(
this
).addClass(
"bbit-tree-node-loading"
);
asnyloadc(ul, item,
function
(data) {
item.complete =
true
;
item.ChildNodes = data;
asnybuild(data, deep, path, ul, item);
});
}
}
if
($(et).hasClass(
"bbit-tree-elbow-plus"
)) {
$(et).swapClass(
"bbit-tree-elbow-plus"
,
"bbit-tree-elbow-minus"
);
}
else
{
$(et).swapClass(
"bbit-tree-elbow-end-plus"
,
"bbit-tree-elbow-end-minus"
);
}
$(
this
).swapClass(
"bbit-tree-node-collapsed"
,
"bbit-tree-node-expanded"
);
}
else
if
($(et).hasClass(
"bbit-tree-elbow-minus"
) || $(et).hasClass(
"bbit-tree-elbow-end-minus"
)) {
//- 號須要收縮
$(
this
).next().hide();
if
($(et).hasClass(
"bbit-tree-elbow-minus"
)) {
$(et).swapClass(
"bbit-tree-elbow-minus"
,
"bbit-tree-elbow-plus"
);
}
else
{
$(et).swapClass(
"bbit-tree-elbow-end-minus"
,
"bbit-tree-elbow-end-plus"
);
}
$(
this
).swapClass(
"bbit-tree-node-expanded"
,
"bbit-tree-node-collapsed"
);
}
else
if
($(et).hasClass(
"bbit-tree-node-cb"
))
// 點擊了Checkbox
{
var
s = item.checkstate != 1 ? 1 : 0;
var
r =
true
;
if
(dfop.oncheckboxclick) {
//觸發配置的函數
r = dfop.oncheckboxclick.call(et, item, s);
}
if
(r !=
false
) {
//若是返回值不爲false,即checkbxo變化有效
if
(dfop.cascadecheck) {
//容許觸發級聯
//遍歷
cascade(check, item, s);
//則向下關聯
//上溯
bubble(check, item, s);
//向上關聯
}
else
{
check(item, s, 1);
//不然只管本身
}
}
}
}
else
{
//點擊到了其餘地方
if
(dfop.citem) {
//上一個當前節點
$(
"#"
+ id +
"_"
+ dfop.citem.id).removeClass(
"bbit-tree-selected"
);
}
dfop.citem = item;
//此次的當前節點
$(
this
).addClass(
"bbit-tree-selected"
);
if
(dfop.onnodeclick) {
dfop.onnodeclick.call(
this
, item);
}
}
}
|
展開節點,異步請求的部分代碼應該不是很複雜就不細訴了,關鍵來說一下級聯
級聯有兩個問題要處理,第一個是遍歷子節點,第二個是上溯到祖節點,由於咱們的數據結構這兩個操做都顯得很是簡單
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
//遍歷子節點
function
cascade(fn, item, args) {
if
(fn(item, args, 1) !=
false
) {
if
(item.ChildNodes !=
null
&& item.ChildNodes.length > 0) {
var
cs = item.ChildNodes;
for
(
var
i = 0, len = cs.length; i < len; i++) {
cascade(fn, cs[i], args);
}
}
}
}
//冒泡的祖先
function
bubble(fn, item, args) {
var
p = item.parent;
while
(p) {
if
(fn(p, args, 0) ===
false
) {
break
;
}
p = p.parent;
}
}
|
找到節點的同時都會觸發check這個回調函數,來判斷當前節點的狀態,詳細請看下面代碼中的註釋部分應該是比較清晰,描寫了這個過程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
function
check(item, state, type) {
var
pstate = item.checkstate;
//當前狀態
if
(type == 1) {
item.checkstate = state;
//若是是遍歷子節點,父是什麼子就是什麼
}
else
{
// 上溯 ,這個就複雜一些了
var
cs = item.ChildNodes;
//獲取當前節點的全部子節點
var
l = cs.length;
var
ch =
true
;
//是否不是中間狀態 半選
for
(
var
i = 0; i < l; i++) {
if
((state == 1 && cs[i].checkstate != 1) || state == 0 && cs[i].checkstate != 0) {
ch =
false
;
break
;
//他的子節點只要有一個沒選中,那麼他就是半選
}
}
if
(ch) {
item.checkstate = state;
//不是半選,則子節點是什麼他就是什麼
}
else
{
item.checkstate = 2;
//半選
}
}
//change show 若是節點已輸出,而其先後狀態不同,則變化checkbxo的顯示
if
(item.render && pstate != item.checkstate) {
var
et = $(
"#"
+ id +
"_"
+ item.id +
"_cb"
);
if
(et.length == 1) {
et.attr(
"src"
, dfop.cbiconpath + dfop.icons[item.checkstate]);
}
}
}
|
至此咱們樹的主體功能已經徹底實現了。其餘就是公開一些方法等,你們可詳見代碼,示例中公開了兩個一個當前選中的全部節點,另一個當前的節點。
你們能夠經過如下網址查看文中的示例,selected拼錯了,你們海涵! windows azure部署仍是麻煩懶得修改了3500+節點一次加載,你們能夠點擊根節點的全選來看看速度
http://jscs.cloudapp.net/ControlsSample/BigTreeSample
異步加載,按需加載的狀況也是很是經常使用的,使用的是SQL Azure服務器在美國ing,因此可能異步有點慢,本地數據源那是瞬間的
http://jscs.cloudapp.net/ControlsSample/TreeAsnySample
FAQ:
1:如何設置每一個節點不一樣的圖標?
回答:
其實不用擴展,自己就支持,只是沒有說明而已,咱們來看一下這個代碼吧?在BuildNode方法中有這麼一句?
if (nd.classes) { cs.push(nd.classes); }
在節點的數據結構中能夠設置屬性classes ,該屬性將做爲節點特殊的Css Class 添加到節點上。那麼利用這點,就能夠設置節點的圖標了
而後就是編寫一個Style 便可
最後來看下效果吧?