最近幾個項目都用到了EasyUI這個Jquery框架,目前感覺起來還是很好使的,展示效果很好,幫助文檔什么的資料很多,而且互聯網上Easy粉很多,大多數擁護和喜愛EasyUI的粉絲們都願意在網絡平台互相分享學習成果,甚至有專門的社區來討論使用情況,網址是http://bbs.jeasyuicn.com/,里面的資源模塊里有很多都是免費的學習資料,包括視頻文檔項目源碼等,建議初學者去看視頻,然后研究一下這個網站(sypro)的實現http://sshe.jeasyuicn.com/,甚至有視頻教程教大家怎么實現這個項目。互聯網是一個巨人,他博學多才,期待能站在巨人的肩膀上開開眼界,學習到更多的知識技能,對於將來或現在的工作都是一個很大的收獲。
本篇博客是對EasyUI中樹的實現的總結。如果想要展示一棵樹,有很多方式,當然要分析你的需求。如果是展示省市區、學校、部門等大數據的話,建議還是使用異步加載。當然如果只是展示幾個幾乎不變的菜單項,就可以扁平化的展示你的數據了。
首先介紹怎么實現一棵異步樹。
項目前准備:
1、首先你要搭建一個你熟悉的框架環境,然后再前台加入EasyUI的源碼包,並在頁面引入js和css等文件。本文的實例主要講解怎么實現樹,以SSH框架為例。如果還有不懂怎么搭建EasyUI框架的同學,可以在EasyUI的中文社區里找EasyUI的初級視頻來看看,非常簡單的。
2、建立數據庫,比方說我們要通過樹來展示你的菜單,那么就要先看一下EasyUI中tree的Data Format,也就是說我們要了解后台傳給前台什么樣式的Json格式。
從上面的文檔截圖可以看出,他的數據格式有以下屬性:id,text,state,checked,attributes,children;
我們在設計數據庫的時候,可以盡量的將節點id和節點名稱分別設置成id和text,這樣在前台解析Json的時候就能直接認出這些屬性值,並顯示出數據來。當然利用擴展的方式的話,你可以不必按照這些規范來,但是需要在tree控件里傳入幾個參數來傳入屬性值。
首先,建立一個t_menu表:(注釋如圖)
外鍵:
測試數據:
准備完以上的內容之后,我們開始做demo。
1、加入EasyUI的樹控件:
<ul id="menuTree" class="easyui-tree" data-options="url:'<%=basePath%>menuAction!getTreeNode.action',parentField:'pid',lines:true,onLoadSuccess:function(node, data){$(this).tree('collapseAll')}"></ul>
解析:
data-options里的URL是Action的路徑,p
arentField設置成我們model里的pid,
lines:true用來顯示樹節點前的加減號,
onLoadSuccess:function(node, data){$(this).tree('collapseAll')}用來設置關閉所有的樹節點。
加入擴展js:
1 $.fn.tree.defaults.loadFilter = function (data, parent) { 2 var opt = $(this).data().tree.options; 3 var idFiled, 4 textFiled, 5 parentField; 6 if (opt.parentField) { 7 idFiled = opt.idFiled || 'id'; 8 textFiled = opt.textFiled || 'text'; 9 parentField = opt.parentField; 10
11 var i, 12 l, 13 treeData = [], 14 tmpMap = []; 15
16 for (i = 0, l = data.length; i < l; i++) { 17 tmpMap[data[i][idFiled]] = data[i]; 18 } 19
20 for (i = 0, l = data.length; i < l; i++) { 21 if (tmpMap[data[i][parentField]] && data[i][idFiled] != data[i][parentField]) { 22 if (!tmpMap[data[i][parentField]]['children']) 23 tmpMap[data[i][parentField]]['children'] = []; 24 data[i]['text'] = data[i][textFiled]; 25 tmpMap[data[i][parentField]]['children'].push(data[i]); 26 } else { 27 data[i]['text'] = data[i][textFiled]; 28 treeData.push(data[i]); 29 } 30 } 31 return treeData; 32 } 33 return data; 34 };
2、Action類實現
首先是model類TMenu.java,映射數據庫的類。
1 import java.util.HashSet; 2 import java.util.Set; 3 import javax.persistence.CascadeType; 4 import javax.persistence.Column; 5 import javax.persistence.Entity; 6 import javax.persistence.FetchType; 7 import javax.persistence.Id; 8 import javax.persistence.JoinColumn; 9 import javax.persistence.ManyToOne; 10 import javax.persistence.OneToMany; 11 import javax.persistence.Table; 12
13 /**
14 * TMenu entity. @author MyEclipse Persistence Tools 15 */
16 @Entity 17 @Table(name = "t_menu", catalog = "easyui") 18 public class TMenu implements java.io.Serializable { 19
20 // Fields
21
22 private String id; 23 private TMenu TMenu; 24 private String text; 25 private String iconCls; 26 private String url; 27 private Set<TMenu> TMenus = new HashSet<TMenu>(0); 28
29 // Constructors
30
31 /** default constructor */
32 public TMenu() { 33 } 34
35 /** minimal constructor */
36 public TMenu(String id) { 37 this.id = id; 38 } 39
40 /** full constructor */
41 public TMenu(String id, TMenu TMenu, String text, String iconCls, String url, Set<TMenu> TMenus) { 42 this.id = id; 43 this.TMenu = TMenu; 44 this.text = text; 45 this.iconCls = iconCls; 46 this.url = url; 47 this.TMenus = TMenus; 48 } 49
50 // Property accessors
51 @Id 52 @Column(name = "id", unique = true, nullable = false, length = 36) 53 public String getId() { 54 return this.id; 55 } 56
57 public void setId(String id) { 58 this.id = id; 59 } 60
61 @ManyToOne(fetch = FetchType.LAZY) 62 @JoinColumn(name = "pid") 63 public TMenu getTMenu() { 64 return this.TMenu; 65 } 66
67 public void setTMenu(TMenu TMenu) { 68 this.TMenu = TMenu; 69 } 70
71 @Column(name = "text", length = 100) 72 public String getText() { 73 return this.text; 74 } 75
76 public void setText(String text) { 77 this.text = text; 78 } 79
80 @Column(name = "iconCls", length = 50) 81 public String getIconCls() { 82 return this.iconCls; 83 } 84
85 public void setIconCls(String iconCls) { 86 this.iconCls = iconCls; 87 } 88
89 @Column(name = "url", length = 200) 90 public String getUrl() { 91 return this.url; 92 } 93
94 public void setUrl(String url) { 95 this.url = url; 96 } 97
98 @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "TMenu") 99 public Set<TMenu> getTMenus() { 100 return this.TMenus; 101 } 102
103 public void setTMenus(Set<TMenu> TMenus) { 104 this.TMenus = TMenus; 105 } 106
107 }
其次是model類Menu.java,此處的model是pageModel,是為了接應前台的name值的:
1 public class Menu { 2
3 private String pid;//父菜單ID
4 private String pText;//父菜單名稱
5 private String id;//子菜單Id
6 private String text;//子菜單名稱
7 private String iconCls;//子菜單圖標
8 private String url;//子菜單路徑
9 private String state; 10
11 //---------------set/get--------------
12
13 public String getPid() { 14 return pid; 15 } 16 public void setPid(String pid) { 17 this.pid = pid; 18 } 19
20 public String getpText() { 21 return pText; 22 } 23 public void setpText(String pText) { 24 this.pText = pText; 25 } 26 public String getId() { 27 return id; 28 } 29 public void setId(String id) { 30 this.id = id; 31 } 32
33 public String getText() { 34 return text; 35 } 36 public void setText(String text) { 37 this.text = text; 38 } 39 public String getIconCls() { 40 return iconCls; 41 } 42 public void setIconCls(String iconCls) { 43 this.iconCls = iconCls; 44 } 45 public String getUrl() { 46 return url; 47 } 48 public void setUrl(String url) { 49 this.url = url; 50 } 51 public String getState() { 52 return state; 53 } 54 public void setState(String state) { 55 this.state = state; 56 } 57
58
59 }
Action類:
1 package com.action; 2
3
4 import org.apache.struts2.convention.annotation.Action; 5 import org.apache.struts2.convention.annotation.Namespace; 6 import org.apache.struts2.convention.annotation.ParentPackage; 7 import org.springframework.beans.factory.annotation.Autowired; 8
9 import com.pageModel.Menu; 10 import com.service.IMenuService; 11
12 import com.opensymphony.xwork2.ModelDriven; 13
14 @ParentPackage("basePackage") 15 @Namespace("/") 16 @Action(value="menuAction") 17 public class MenuAction extends BaseAction implements ModelDriven<Menu> { 18 Menu menu=new Menu(); 19 @Override 20 public Menu getModel() { 21 // TODO Auto-generated method stub
22 return menu; 23 } 24 private IMenuService menuService; 25
26 public IMenuService getMenuService() { 27 return menuService; 28 } 29 @Autowired 30 public void setMenuService(IMenuService menuService) { 31 this.menuService = menuService; 32 } 33 /**
34 * 異步獲得樹節點 35 */
36 public void getTreeNode(){ 37 super.writeJson(menuService.getTreeNode(menu.getId())); 38 } 39 }
2、了解getTreeNode()方法的實現:
對應service的實現類:
1 package com.service.impl; 2 3 import java.util.ArrayList; 4 import java.util.HashMap; 5 import java.util.List; 6 import java.util.Map; 7 import java.util.Set; 8 9 import org.springframework.beans.BeanUtils; 10 import org.springframework.beans.factory.annotation.Autowired; 11 import org.springframework.stereotype.Service; 12 13 import com.dao.IBaseDao; 14 import com.model.TMenu; 15 import com.pageModel.Menu; 16 import com.service.IMenuService; 17 18 @Service("menuService") 19 public class MenuServiceImpl implements IMenuService { 20 private IBaseDao<TMenu> menuDao; 21 22 23 public IBaseDao<TMenu> getMenuDao() { 24 return menuDao; 25 } 26 27 @Autowired 28 public void setMenuDao(IBaseDao<TMenu> menuDao) { 29 this.menuDao = menuDao; 30 } 31 32 33 @Override 34 public List<Menu> getTreeNode(String id) { 35 List<Menu> menus=new ArrayList<Menu>(); 36 StringBuffer hql=new StringBuffer(); 37 hql=hql.append("from TMenu t where "); 38 Map<String, Object> map=new HashMap<String, Object>(); 39 if (id==null || "".equals(id)) { 40 //返回總根節點 41 hql=hql.append(" t.TMenu is null"); 42 43 } else { 44 //異步加載當前id下的子節點 45 hql=hql.append(" t.TMenu.id=:id"); 46 map.put("id", id); 47 } 48 List<TMenu> tMenus= menuDao.find(hql.toString(),map); 49 for (TMenu tMenu : tMenus) { 50 Menu menu=new Menu(); 51 BeanUtils.copyProperties(tMenu, menu); 52 Set<TMenu> set=tMenu.getTMenus(); 53 if (set!=null && !set.isEmpty()) { 54 menu.setState("closed"); //節點以根節點形式體現(文件夾) 55 } else { 56 menu.setState("open"); //節點 以葉子形式體現(文件) 57 } 58 menus.add(menu); 59 } 60 return menus; 61 } 62 63 }
最后展示實現效果:當單擊加號的時候才會加載其子節點,異步實現了功能樹。
下篇博客將介紹另一種加載樹的方式,就是一次把所有的樹節點都加載上來,顯示扁平化數據。