需求是需要做一個國家信息的樹形結構圖,那麼就避免不了使用樹狀結構的插件,而用的比較多的插件就是Ztree和Jstree,個人在這裏強烈推薦Ztree,
原因如下:1、Ztree的插件文檔全中文解釋,畢竟是國產插件,所以對於英語不太好的同學來說,會減少很多麻煩,而Jstree全英文
2、Ztree的demo比Jstree更加詳細,更能夠去理解插件中各種事件,屬性的使用
下面直接放圖:
一、JS頁面;需要引用的ztree的包我就不累贅了,不過推薦一個網站 http://www.bootcdn.cn/ 不用下載包,直接複製鏈接就可以
1)首先是異步逐級加載數據,即點擊一個節點加載一層數據,不點擊就不會去查詢該節點下的子節點,優點:後臺代碼邏輯簡單,只需要將節點ID作爲parentId去查即可,缺點就是對於後面的模糊搜索來說,如果你的某個節點下的數據沒有打開也就是說沒有去後臺查,那模糊搜索是搜索不到該節點下的數據信息的,比如你沒有打開湖南省這個節點,湖南省節點下有長沙市這個節點信息,但是因爲你沒有打開所以不會去後臺查詢,那麼你模糊搜索長,是不會顯示出湖南省下長沙市的節點信息的。
<script type="text/javascript">
(function () { //下面的參數如果有不懂的,可以結合文檔查詢,很詳細
var setting = {
async: {
enable: true, //是否異步
url: "geographic/getAllInfo",
autoParam: ["id"], //傳的參數
},
view: {
expandSpeed: "",
addHoverDom: addHoverDom,
removeHoverDom: removeHoverDom,
selectedMulti: false,
showIcon: true,
showLine: true,
fontCss:getFontCss
},
edit: {
enable: true
},
callback: {
onClick: zTreeOnOnClick,
beforeRemove: beforeRemove,
beforeRename: beforeRename
},
data: {
simpleData: {
enable: true,
idKey: "id",
pIdKey: "pId",
rootPId: 0
}
}
};
$(function () {
$.ajax({
type: "POST",
url: "geographic/getAllInfo",
dataType: "json",
success: function (data) {
$.fn.zTree.init($("#geographicInfoTree"), setting, data.data);
}
})
key = $("#key");
key.bind("focus", focusKey)
.bind("blur", blurKey)
.bind("propertychange", searchNode)
.bind("input", searchNode);
});
function zTreeOnOnClick(even, treeId, treeNode) {
var treeObj = $.fn.zTree.getZTreeObj(treeId);
var node = treeObj.getNodeByTId(treeNode.tId);
if (!node.children) {
$.ajax({
type: "POST",
url: "geographic/getAllInfo",
data: {
id: treeNode.id
},
dataType: "json",
success: function (data) {
if (data) {
newNode = treeObj.addNodes(node, data);
}
},
error: function () {
layer.msg('Operation failed!', {icon: 2, time: 2000});
}
});
}
}
2)實現鼠標放到節點上,就會出現增加,刪除,修改的圖標(用到事件),其中刪除修改按鈕是Ztree自帶的,增加的話需要我們手動去寫按鈕代碼
function beforeRemove(treeId, treeNode) {
$.ajax({
type: "POST",
url: "geographic/deleteNode",
data: {
id: treeNode.id
},
dataType: "json",
success: function (data) {
if (data === 'success') {
window.parent.layer.close(window.parent.layer.index);
layer.msg('Delete successful!', {icon: 1, time: 1000});
} else {
layer.msg('Delete failed!', {icon: 2, time: 2000});
}
}
})
}
function beforeRename(treeId, treeNode, newName) {
if (!newName) {
layer.msg('The name can not be empty!', {icon: 2, time: 2000});
return false;
}
$.ajax({
type: "post",
url: "geographic/updateInfo",
data: {
id: treeNode.id,
name: newName
},
dataType: "json",
success: function (data) {
if (data == 'success') {
window.parent.layer.close(window.parent.layer.index);
layer.msg('Update successful!', {icon: 1, time: 1000});
} else {
layer.msg('Update failed!', {icon: 2, time: 2000});
}
}
});
}
var newCount = 1;
function addHoverDom(treeId, treeNode) {
var sObj = $("#" + treeNode.tId + "_span");
if (treeNode.editNameFlag || $("#addBtn_" + treeNode.tId).length > 0) {
return;
}
var addStr = "<span class='button add' id='addBtn_" + treeNode.tId
+ "' title='add node' οnfοcus='this.blur();'></span>";
sObj.after(addStr);
var btn = $("#addBtn_" + treeNode.tId);
var id;
if (btn) {
btn.bind("click", function () {
var zTree = $.fn.zTree.getZTreeObj("geographicInfoTree");
var name = "new name" + (newCount++);
$.post(
"geographic/addInfo",
{
id: treeNode.id,
name: name,
},
function(data){
id = data; //需要從後臺返回增加的節點的ID
zTree.addNodes(treeNode, { //增加一個節點後需要將樹刷新,需用到此方法,數據只需要滿足 zTree 的節點數據必需的屬性即可,具體請參考API
id:id,
pId: treeNode.id,
name: name
});
}
);
});
return false;
} else {
return false;
}
};
function removeHoverDom(treeId, treeNode) {
$("#addBtn_" + treeNode.tId).unbind().remove();
};
3)模糊搜索(此處爲樓主借鑑http://blog.csdn.net/wangjingna/article/details/50488921)點擊打開鏈接
var lastValue = "", nodeList = [], fontCss = {};
function callNumber(){
var zTree = $.fn.zTree.getZTreeObj("geographicInfoTree");
if(nodeList.length){
zTree.selectNode(nodeList[0],false );
document.getElementById("key").focus();
}else if(nodeList.length === 0){
zTree.cancelSelectedNode();
}
if(document.getElementById("key").value ===""){
zTree.cancelSelectedNode();
}
}
function focusKey(e) {
if (key.hasClass("empty")) {
key.removeClass("empty");
}
}
function blurKey(e) {
if (key.get(0).value === "") {
key.addClass("empty");
}
}
function searchNode(e) {
var zTree = $.fn.zTree.getZTreeObj("geographicInfoTree");
var value = $.trim(key.get(0).value);
var keyType = "name";
if (key.hasClass("empty")) {
value = "";
}
if (lastValue === value) {return;}
lastValue = value;
if (value === ""){
updateNodes(false);
return;
}
updateNodes(false);
nodeList = zTree.getNodesByParamFuzzy(keyType, value);
updateNodes(true); }
unction updateNodes(highlight){
var zTree = $.fn.zTree.getZTreeObj("geographicInfoTree");
for( var i=0, l=nodeList.length; i<l; i++) {
nodeList[i].highlight = highlight;
zTree.expandNode(nodeList[i].getParentNode(), true, false, false);
zTree.updateNode(nodeList[i]);
}
}
function getFontCss(treeId, treeNode) {
return (!!treeNode.highlight) ? {color:"#A60000", "font-weight":"bold"} : {color:"#333", "font-weight":"normal"};
}})();
二、controller層
@Controller @RequestMapping("/geographic") public class GeographicInfoController extends BaseController { @Autowired private GeographicInfoService geographicInfoService; @RequestMapping("/addInfo") @ResponseBody public String addInfo(@RequestParam(value = "id", defaultValue = "0") String id,String name) { String str = geographicInfoService.addInfo(name, id); return str; } @RequestMapping("/updateInfo") @ResponseBody public String updateInfo(GeographicInfoDO geographicInfoDO) { boolean flag = geographicInfoService.updateInfo(geographicInfoDO); return flag ? "success" : "false"; } @RequestMapping(value = "/getAllInfo") @ResponseBody public List getNodeInfo(@RequestParam(value = "id", defaultValue = "0") String id) { List<Map<String, Object>> list = geographicInfoService.getChildrenInfo(id); return list; } @RequestMapping(value = "/deleteNode") @ResponseBody public String deleteNodeInfo(String id){ boolean flag =geographicInfoService.deleteNodeInfo(id); return flag ? "success" : "false"; } @RequestMapping(value = "/getListPage") public String getListPage(){ return "geographicInfo/geographicInfoList"; } }三、service層
@Service public class GrographicServiceImpl implements GeographicInfoService { @Autowired private GrographicInfoDAO grographicInfoDAO; @Override public String addInfo(String name, String parent_id) { GeographicInfoDO geographicInfoDO = new GeographicInfoDO(); geographicInfoDO.setId(DataBaseUtil.getTimeUUID()); //樓主採用手動添加ID而不是自增加,因爲前臺需要返回一個增加節點的ID,這樣很方便,當然還有其他的返回ID方法,可以自行百度
geographicInfoDO.setParentId(parent_id); geographicInfoDO.setName(name); geographicInfoDO.setStatus("1"); grographicInfoDAO.save(geographicInfoDO); return geographicInfoDO.getId(); } @Override public boolean updateInfo(GeographicInfoDO geographicInfoDO) { int acount = grographicInfoDAO.update(geographicInfoDO); if(acount > 0){ return true; } return false; } @Override public List<Map<String,Object>> getChildrenInfo(String id) { return grographicInfoDAO.findGeographicChildrenByParentId(id); } @Override public boolean deleteNodeInfo(String id) { int acount = grographicInfoDAO.delete(id); if(acount > 0){ return true; } return false; } }四、DO層
public class GeographicInfoDO extends BaseDo<String, String> { private String parentId; private String name; private String status; public String getStatus() { return status; } public void setStatus(String status) { this.status = status; } public String getParentId() { return parentId; } public void setParentId(String parentId) { this.parentId = parentId; } public String getName() { return name; } public void setName(String name) { this.name = name; } }五、時區
public class DataBaseUtil { private static final Logger logger = LoggerFactory.getLogger(DataBaseUtil.class); private static final String DATABASE_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss"; private static final String DATABASE_DATE_NOTTIME_FORMAT = "yyyy-MM-dd"; private static final String DATABASE_SHORT_UUID_FORMAT = "yyMMddHHmmss"; public DataBaseUtil() { } public static String getUUID() { return StringUtil.replace(UUID.randomUUID().toString(), "-", ""); } public static String getTimeUUID() { return "K" + (new SimpleDateFormat("yyMMddHHmmss")).format(new Date()) + getStringRandom(7); } public static Date getDateByString(String date) { DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); if (date != null && date.length() >= "yyyy-MM-dd HH:mm:ss".length()) { try { return dateFormat.parse(date); } catch (Exception var3) { logger.warn("[databaseUtil] converter to Data error,", var3); return null; } } else { return null; } } public static String getDateStrByDate(Date date) { return date != null && !StringUtil.isBlank("yyyy-MM-dd HH:mm:ss") ? (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.SIMPLIFIED_CHINESE)).format(date) : ""; } public static String getDateStrByNow() { return getDateStrByDate(new Date()); } public static Date getDateByStringNotTime(String date) { DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); if (date != null && date.length() >= "yyyy-MM-dd".length()) { try { return dateFormat.parse(date); } catch (Exception var3) { logger.warn("[databaseUtil] converter to Data error,", var3); return null; } } else { return null; } } public static String getDateStrNotTimeByDate(Date date) { return date != null && !StringUtil.isBlank("yyyy-MM-dd") ? (new SimpleDateFormat("yyyy-MM-dd", Locale.SIMPLIFIED_CHINESE)).format(date) : ""; } public static String getDateStrNotTimeByNow() { return getDateStrNotTimeByDate(new Date()); } public static String getStringRandom(int length) { String val = ""; Random random = new Random(); for(int i = 0; i < length; ++i) { val = val + String.valueOf(random.nextInt(10)); } return val; } public static void main(String[] args) { System.out.println(getTimeUUID()); } }