Ztree,非同步逐級載入資料,連線資料庫增刪改,模糊搜尋
阿新 • • 發佈:2019-01-29
需求是需要做一個國家資訊的樹形結構圖,那麼就避免不了使用樹狀結構的外掛,而用的比較多的外掛就是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' onfocus='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()); } }