打造基于jQuery的高性能TreeView(上)
2009-10-27 00:00:00 来源:WEB开发网这样的结构有个好处就数据本身是带层次的,非常利于遍历,在后面的级联关联中会看到
3: 面子做好了那就开始做里子了,编写脚本(Javascript)
我是JQuery得拥护者,所以自然js的框架自然是采用Jquery了
先上个完整代码,再逐一分析
001./****************************************
002.author:xuanye.wan@gmail.com
003.page:http://xuanye.cnblogs.com/
004.***************************************/
005.(function($) {
006. $.fn.swapClass = function(c1, c2) {
007. return this.removeClass(c1).addClass(c2);
008. }
009. $.fn.switchClass = function(c1, c2) {
010. if (this.hasClass(c1)) {
011. return this.swapClass(c1, c2);
012. }
013. else {
014. return this.swapClass(c2, c1);
015. }
016. }
017. $.fn.treeview = function(settings) {
018. var dfop =
019. {
020. method: "POST",
021. datatype: "json",
022. url: false,
023. cbiconpath: "/images/icons/",
024. icons: ["checkbox_0.gif", "checkbox_1.gif", "checkbox_2.gif"],
025. showcheck: false, //是否显示选择
026. oncheckboxclick: false, //当checkstate状态变化时所触发的事件,但是不会触发因级联选择而引起的变化
027. onnodeclick: false,
028. cascadecheck: true,
029. data: null,
030. clicktoggle: true, //点击节点展开和收缩子节点
031. theme: "bbit-tree-arrows" //bbit-tree-lines ,bbit-tree-no-lines,bbit-tree-arrows
032. }
033.
034. $.extend(dfop, settings);
035. var treenodes = dfop.data;
036. var me = $(this);
037. var id = me.attr("id");
038. if (id == null || id == "") {
039. id = "bbtree" + new Date().getTime();
040. me.attr("id", id);
041. }
042.
043. var html = [];
044. buildtree(dfop.data, html);
045. me.addClass("bbit-tree").html(html.join(""));
046. InitEvent(me);
047. html = null;
048. //预加载图片
049. if (dfop.showcheck) {
050. for (var i = 0; i < 3; i++) {
051. var im = new Image();
052. im.src = dfop.cbiconpath + dfop.icons[i];
053. }
054. }
055. //region
056. function buildtree(data, ht) {
057. ht.push("<div class='bbit-tree-bwrap'>"); // Wrap ;
058. ht.push("<div class='bbit-tree-body'>"); // body ;
059. ht.push("<ul class='bbit-tree-root ", dfop.theme, "'>"); //root
060. var l = data.length;
061. for (var i = 0; i < l; i++) {
062. buildnode(data[i], ht, 0, i, i == l - 1);
063. }
064. ht.push("</ul>"); // root and;
065. ht.push("</div>"); // body end;
066. ht.push("</div>"); // Wrap end;
067. }
068. //endregion
069. function buildnode(nd, ht, deep, path, isend) {
070. ht.push("<li class='bbit-tree-node'>");
071. ht.push("<div id='", id, "_", nd.id, "' tpath='", path, "' unselectable='on'");
072. var cs = [];
073. cs.push("bbit-tree-node-el");
074. if (nd.hasChildren) {
075. cs.push(nd.isexpand ? "bbit-tree-node-expanded" : "bbit-tree-node-collapsed");
076. }
077. else {
078. cs.push("bbit-tree-node-leaf");
079. }
080. if (nd.classes) { cs.push(nd.classes); }
081.
082. ht.push(" class='", cs.join(" "), "'>");
083. //span indent
084. ht.push("<span class='bbit-tree-node-indent'>");
085. if (deep == 1) {
086. ht.push("<img class='bbit-tree-icon' src='http://tech.ddvip.com/Themes/Shared/images/s.gif'/>");
087. }
088. else if (deep > 1) {
089. ht.push("<img class='bbit-tree-icon' src='http://tech.ddvip.com/Themes/Shared/images/s.gif'/>");
090. for (var j = 1; j < deep; j++) {
091. ht.push("<img class='bbit-tree-elbow-line' src='http://tech.ddvip.com/Themes/Shared/images/s.gif'/>");
092. }
093. }
094. ht.push("</span>");
095. //img
096. cs.length = 0;
097. if (nd.hasChildren) {
098. if (nd.isexpand) {
099. cs.push(isend ? "bbit-tree-elbow-end-minus" : "bbit-tree-elbow-minus");
100. }
101. else {
102. cs.push(isend ? "bbit-tree-elbow-end-plus" : "bbit-tree-elbow-plus");
103. }
104. }
105. else {
106. cs.push(isend ? "bbit-tree-elbow-end" : "bbit-tree-elbow");
107. }
108. ht.push("<img class='bbit-tree-ec-icon ", cs.join(" "), "' src='http://tech.ddvip.com/Themes/Shared/images/s.gif'/>");
109. ht.push("<img class='bbit-tree-node-icon' src='http://tech.ddvip.com/Themes/Shared/images/s.gif'/>");
110. //checkbox
111. if (dfop.showcheck && nd.showcheck) {
112. if (nd.checkstate == null || nd.checkstate == undefined) {
113. nd.checkstate = 0;
114. }
115. ht.push("<img id='", id, "_", nd.id, "_cb' class='bbit-tree-node-cb' src='", dfop.cbiconpath, dfop.icons[nd.checkstate], "'/>");
116. }
117. //a
118. ht.push("<a hideFocus class='bbit-tree-node-anchor' tabIndex=1 href='javascript:void(0);'>");
119. ht.push("<span unselectable='on'>", nd.text, "</span>");
120. ht.push("</a>");
121. ht.push("</div>");
122. //Child
123. if (nd.hasChildren) {
124. if (nd.isexpand) {
125. ht.push("<ul class='bbit-tree-node-ct' style='z-index: 0; position: static; visibility: visible; top: auto; left: auto;'>");
126. if (nd.ChildNodes) {
127. var l = nd.ChildNodes.length;
128. for (var k = 0; k < l; k++) {
129. nd.ChildNodes[k].parent = nd;
130. buildnode(nd.ChildNodes[k], ht, deep + 1, path + "." + k, k == l - 1);
131. }
132. }
133. ht.push("</ul>");
134. }
135. else {
136. ht.push("<ul style='display:none;'></ul>");
137. }
138. }
139. ht.push("</li>");
140. nd.render = true;
141. }
142. function getItem(path) {
143. var ap = path.split(".");
144. var t = treenodes;
145. for (var i = 0; i < ap.length; i++) {
146. if (i == 0) {
147. t = t[ap[i]];
148. }
149. else {
150. t = t.ChildNodes[ap[i]];
151. }
152. }
153. return t;
154. }
155. function check(item, state, type) {
156. var pstate = item.checkstate;
157. if (type == 1) {
158. item.checkstate = state;
159. }
160. else {// 上溯
161. var cs = item.ChildNodes;
162. var l = cs.length;
163. var ch = true;
164. for (var i = 0; i < l; i++) {
165. if ((state == 1 && cs[i].checkstate != 1) || state == 0 && cs[i].checkstate != 0) {
166. ch = false;
167. break;
168. }
169. }
170. if (ch) {
171. item.checkstate = state;
172. }
173. else {
174. item.checkstate = 2;
175. }
176. }
177. //change show
178. if (item.render && pstate != item.checkstate) {
179. var et = $("#" + id + "_" + item.id + "_cb");
180. if (et.length == 1) {
181. et.attr("src", dfop.cbiconpath + dfop.icons[item.checkstate]);
182. }
183. }
184. }
185. //遍历子节点
186. function cascade(fn, item, args) {
187. if (fn(item, args, 1) != false) {
188. if (item.ChildNodes != null && item.ChildNodes.length > 0) {
189. var cs = item.ChildNodes;
190. for (var i = 0, len = cs.length; i < len; i++) {
191. cascade(fn, cs[i], args);
192. }
193. }
194. }
195. }
196. //冒泡的祖先
197. function bubble(fn, item, args) {
198. var p = item.parent;
199. while (p) {
200. if (fn(p, args, 0) === false) {
201. break;
202. }
203. p = p.parent;
204. }
205. }
206. function nodeclick(e) {
207. var path = $(this).attr("tpath");
208. var et = e.target || e.srcElement;
209. var item = getItem(path);
210.
211. //debugger;
212. if (et.tagName == "IMG") {
213. // +号需要展开
214. if ($(et).hasClass("bbit-tree-elbow-plus") || $(et).hasClass("bbit-tree-elbow-end-plus")) {
215. var ul = $(this).next(); //"bbit-tree-node-ct"
216. if (ul.hasClass("bbit-tree-node-ct")) {
217. ul.show();
218. }
219. else {
220. var deep = path.split(".").length;
221. if (item.complete) {
222. item.ChildNodes != null && asnybuild(item.ChildNodes, deep, path, ul, item);
223. }
224. else {
225. $(this).addClass("bbit-tree-node-loading");
226. asnyloadc(ul, item, function(data) {
227. item.complete = true;
228. item.ChildNodes = data;
229. asnybuild(data, deep, path, ul, item);
230. });
231. }
232. }
233. if ($(et).hasClass("bbit-tree-elbow-plus")) {
234. $(et).swapClass("bbit-tree-elbow-plus", "bbit-tree-elbow-minus");
235. }
236. else {
237. $(et).swapClass("bbit-tree-elbow-end-plus", "bbit-tree-elbow-end-minus");
238. }
239. $(this).swapClass("bbit-tree-node-collapsed", "bbit-tree-node-expanded");
240. }
241. else if ($(et).hasClass("bbit-tree-elbow-minus") || $(et).hasClass("bbit-tree-elbow-end-minus")) { //- 号需要收缩
242. $(this).next().hide();
243. if ($(et).hasClass("bbit-tree-elbow-minus")) {
244. $(et).swapClass("bbit-tree-elbow-minus", "bbit-tree-elbow-plus");
245. }
246. else {
247. $(et).swapClass("bbit-tree-elbow-end-minus", "bbit-tree-elbow-end-plus");
248. }
249. $(this).swapClass("bbit-tree-node-expanded", "bbit-tree-node-collapsed");
250. }
251. else if ($(et).hasClass("bbit-tree-node-cb")) // 点击了Checkbox
252. {
253. var s = item.checkstate != 1 ? 1 : 0;
254. var r = true;
255. if (dfop.oncheckboxclick) {
256. r = dfop.oncheckboxclick.call(et, item, s);
257. }
258. if (r != false) {
259. if (dfop.cascadecheck) {
260. //遍历
261. cascade(check, item, s);
262. //上溯
263. bubble(check, item, s);
264. }
265. else {
266. check(item, s, 1);
267. }
268. }
269. }
270. }
271. else {
272. if (dfop.citem) {
273. $("#" + id + "_" + dfop.citem.id).removeClass("bbit-tree-selected");
274. }
275. dfop.citem = item;
276. $(this).addClass("bbit-tree-selected");
277. if (dfop.onnodeclick) {
278. dfop.onnodeclick.call(this, item);
279. }
280. }
281. }
282. function asnybuild(nodes, deep, path, ul, pnode) {
283. var l = nodes.length;
284. if (l > 0) {
285. var ht = [];
286. for (var i = 0; i < l; i++) {
287. nodes[i].parent = pnode;
288. buildnode(nodes[i], ht, deep, path + "." + i, i == l - 1);
289. }
290. ul.html(ht.join(""));
291. ht = null;
292. InitEvent(ul);
293. }
294. ul.addClass("bbit-tree-node-ct").css({ "z-index": 0, position: "static", visibility: "visible", top: "auto", left: "auto", display: "" });
295. ul.prev().removeClass("bbit-tree-node-loading");
296. }
297. function asnyloadc(pul, pnode, callback) {
298. if (dfop.url) {
299. var param = builparam(pnode);
300. $.ajax({
301. type: dfop.method,
302. url: dfop.url,
303. data: param,
304. dataType: dfop.datatype,
305. success: callback,
306. error: function(e) { alert("error occur!"); }
307. });
308. }
309. }
310. function builparam(node) {
311. var p = [{ name: "id", value: encodeURIComponent(node.id) }
312. , { name: "text", value: encodeURIComponent(node.text) }
313. , { name: "value", value: encodeURIComponent(node.value) }
314. , { name: "checkstate", value: node.checkstate}];
315. return p;
316. }
317. function InitEvent(parent) {
318. var nodes = $("li.bbit-tree-node>div", parent);
319. nodes.each(function(e) {
320. $(this).hover(function() {
321. $(this).addClass("bbit-tree-node-over");
322. }, function() {
323. $(this).removeClass("bbit-tree-node-over");
324. })
325. .click(nodeclick)
326. .find("img.bbit-tree-ec-icon").each(function(e) {
327. if (!$(this).hasClass("bbit-tree-elbow")) {
328. $(this).hover(function() {
329. $(this).parent().addClass("bbit-tree-ec-over");
330. }, function() {
331. $(this).parent().removeClass("bbit-tree-ec-over");
332. });
333. }
334. });
335. });
336. }
337. function getck(items, c, fn) {
338. for (var i = 0, l = items.length; i < l; i++) {
339. items[i].checkstate == 1 && c.push(fn(items[i]));
340. if (items[i].ChildNodes != null && items[i].ChildNodes.length > 0) {
341. getck(items[i].ChildNodes, c, fn);
342. }
343. }
344. }
345. me[0].t = {
346. getSelectedNodes: function() {
347. var s = [];
348. getck(treenodes, s, function(item) { return item });
349. return s;
350. },
351. getSelectedValues: function() {
352. var s = [];
353. getck(treenodes, s, function(item) { return item.value });
354. return s;
355. },
356. getCurrentItem: function() {
357. return dfop.citem;
358. }
359. };
360. return me;
361. }
362. //获取所有选中的节点的Value数组
363. $.fn.getTSVs = function() {
364. if (this[0].t) {
365. return this[0].t.getSelectedValues();
366. }
367. return null;
368. }
369. //获取所有选中的节点的Item数组
370. $.fn.getTSNs = function() {
371. if (this[0].t) {
372. return this[0].t.getSelectedNodes();
373. }
374. return null;
375. }
376. $.fn.getTCT = function() {
377. if (this[0].t) {
378. return this[0].t.getCurrentItem();
379. }
380. return null;
381. }
382.
383.})(jQuery);
更多精彩
赞助商链接