`
yahaitt
  • 浏览: 760771 次
  • 性别: Icon_minigender_2
  • 来自: 杭州
社区版块
存档分类
最新评论

EXTJS动态树的实现

阅读更多
EXTJS动态树的实现举例
一、描述:通过dwr实现JS与后台的交互,从而实现动态树中叶子节点和目录节点的增加和编辑、以及节点的拖曳,节点的增删和拖曳都会改变自身以及它所在的目录节点下的相关节点的序号,能使得后台与前台同步。这个序号借助了tree中node的index。
1、相关基础:
servlet、mysql、dwr、json
2、涉及的ExtJs中部分知识点:
menu、tree、window以及事件机制
3、实现的效果图:
a)ExtJs动态树-右键叶子节点菜单

b)ExtJs动态树-选择右键叶子节点菜单的“编辑”选项

c)ExtJs动态树-右键目录节点菜单

d)ExtJs动态树-选择右键目录节点菜单的“编辑”选项

e)ExtJs动态树-拖曳节点

4、导航数据表结构:

5、源码结构图:

6、页面结构图:


二、实现流程
JAVA源码部分:
1、数据库连接
package com.demo.core.dao;

import java.sql.Connection;
import java.sql.DriverManager;

public class DBConn {

	private static  String url = "jdbc:mysql://localhost:3306/langsin";
	private static  String username = "root";
	private static  String password = "";
	private static  String driver = "com.mysql.jdbc.Driver";
	
	public static Connection getConnection(){
		Connection conn = null;
		try{
			Class.forName(driver);
			conn = DriverManager.getConnection(url,username,password);
		}catch(Exception e){
			e.printStackTrace();
		}
		return conn;
	}
}

2、dao层:
package com.demo.navigate.dao;

import java.io.Serializable;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

import com.demo.core.dao.DBConn;
import com.demo.navigate.model.Navigate;

public class NavigateDao {
	private static NavigateDao dao;
	private NavigateDao(){		
	}	
	public static NavigateDao getInstanece(){
		if(null == dao){
			dao = new NavigateDao();
		}
		return dao;
	}
	/**
	 * 获得指定ID的数据
	 * @param id
	 * @return
	 */
	public Navigate get(Serializable id){
		Connection conection = null;
		Statement stmt = null;
		ResultSet rs = null;
		Navigate obj = null;
		try{
			conection = DBConn.getConnection(); 
			stmt = conection.createStatement();
			StringBuffer sql = new StringBuffer("select * from navigate where id = ");
			sql.append(id);
			rs = stmt.executeQuery(sql.toString());
			if(rs.next())
			{
				obj = new Navigate();
				obj.setId(rs.getInt("id"));
				obj.setLeaf(rs.getInt("leaf"));
				obj.setNumber(rs.getInt("number"));
				obj.setParentId(rs.getInt("parentId"));
				obj.setTitle(rs.getString("title"));
				obj.setUrl(rs.getString("url"));
			}
		}catch(Exception e){
			e.printStackTrace();			
		}finally{
			try{
				if(rs != null) {
	        		try {
						rs.close();
					} catch (SQLException e) {
					}
	        		rs = null;
	        	}	        	
	        	if (stmt != null) {
		        	try {
		        		stmt.close();
		        	} catch (SQLException sqlex) {
		        	}
		        	stmt = null;
	        	}
	        	if (conection != null) {
		        	try {
		        		conection.close();
		        	} catch (SQLException sqlex) {
		        	}
		        	conection = null;
	        	}
			}catch(Exception e){
				e.printStackTrace();
			}
		}
		return obj;
	}
	
	/**
	 * 获得指定节点的所有儿子节点
	 * @param id
	 */
	@SuppressWarnings("unchecked")
	public List<Navigate> getChildrenById(Integer id){
		List<Navigate> list = new ArrayList<Navigate>();
		Connection conection = null;
		Statement stmt = null;
		ResultSet rs = null;
		try{
			conection = DBConn.getConnection(); 
			stmt = conection.createStatement();
			StringBuffer sql = new StringBuffer("select * from navigate where parentId = ");
			sql.append(id);
			sql.append(" order by number,id");
			rs = stmt.executeQuery(sql.toString());
			while(rs.next())
			{
				Navigate obj = new Navigate();
				obj.setId(rs.getInt("id"));
				obj.setLeaf(rs.getInt("leaf"));
				obj.setNumber(rs.getInt("number"));
				obj.setParentId(rs.getInt("parentId"));
				obj.setTitle(rs.getString("title"));
				obj.setUrl(rs.getString("url"));
				list.add(obj);
			}
		}catch(Exception e){
			e.printStackTrace();			
		}finally{
			try{
				if(rs != null) {
	        		try {
						rs.close();
					} catch (SQLException e) {
					}
	        		rs = null;
	        	}	        	
	        	if (stmt != null) {
		        	try {
		        		stmt.close();
		        	} catch (SQLException sqlex) {
		        	}
		        	stmt = null;
	        	}
	        	if (conection != null) {
		        	try {
		        		conection.close();
		        	} catch (SQLException sqlex) {
		        	}
		        	conection = null;
	        	}
			}catch(Exception e){
				e.printStackTrace();
			}
		}
		return list;
	}
	
	/**
	 * 保存数据
	 * @param obj 
	 */
	public void save(Navigate obj){
		StringBuffer sql = new StringBuffer("insert into navigate(parentId,title,leaf,number,url) values(");
		sql.append(obj.getParentId());
		sql.append(",'");
		sql.append(obj.getTitle());
		sql.append("',");
		sql.append(obj.getLeaf());
		sql.append(",");
		sql.append(obj.getNumber());
		sql.append(",'");
		sql.append(obj.getUrl());
		sql.append("')");
		this.bulkUpdate(sql.toString());
	}
	
	/**
	 * 更新数据
	 * @param obj 
	 */
	public void update(Navigate obj){
		StringBuffer sql = new StringBuffer("update navigate set");
		sql.append(" parentId = ");
		sql.append(obj.getParentId());
		sql.append(",");
		sql.append(" title = '");
		sql.append(obj.getTitle());
		sql.append("',");
		sql.append(" leaf = ");
		sql.append(obj.getLeaf());
		sql.append(",");
		sql.append(" number = ");
		sql.append(obj.getNumber());
		sql.append(", url = '");
		sql.append(obj.getUrl());
		sql.append("' where id = ");
		sql.append(obj.getId());
		this.bulkUpdate(sql.toString());
	}
	
	/**
	 * 异步更新标题
	 * @param id
	 * @param title
	 * @return true-修改成功 false-修改失败
	 */
	public Boolean ajaxUpdateTitle(Integer id,String title){
		Boolean flag = false;
		Navigate obj = this.get(id);
		if(null != obj){
			StringBuffer sql = new StringBuffer("update navigate set");
			sql.append(" title = '");
			sql.append(title);
			sql.append("'");
			sql.append(" where id = ");
			sql.append(id);
			this.bulkUpdate(sql.toString());
			flag = true;
		}
		return flag;
	}
	
	/**
	 * 删除指定的一条数据
	 * @param id
	 */
	public void removeById(Integer id){
		StringBuffer sql = new StringBuffer("delete from navigate where id = ");
		sql.append(id);
		this.bulkUpdate(sql.toString());
	}
	
	/**
	 * 异步删除数据,包括其子孙节点
	 * @param id
	 * @param title
	 */
	@SuppressWarnings("unchecked")
	public void ajaxRemoveNode(Integer id){
		List list = this.getChildrenById(id);
		for (Object object : list) {
			Navigate obj = (Navigate)object;
			ajaxRemoveNode(obj.getId());
		}
		this.removeById(id);
	}
	
	/**
	 * 移动指定节点
	 * @param id	指定的节点的id
	 * @param oldParentId	节点移动前所在的父节点
	 * @param newParentId	节点移动后的目标父节点
	 * @param nodeIndex		节点移动后的目标位置
	 */
	public void ajaxMoveNode(int id, int oldParentId, int newParentId, int nodeIndex){
		Navigate obj = this.get(id);
		int minIndex = obj.getNumber().intValue();
		int maxIndex = nodeIndex;
		if(oldParentId == newParentId && minIndex != maxIndex){
			// 在同一个父节点下发生移动
			if(minIndex < maxIndex){
				// 当要移动的节点的序号小于要移动到的目标序号,则下移
				this.downNode(oldParentId, minIndex, maxIndex);
			}else if(minIndex > maxIndex){
				// 当要移动的节点的序号大于要移动到的目标序号,则上移
				maxIndex = minIndex;
				minIndex = nodeIndex;
				this.upNode(oldParentId, minIndex, maxIndex);
			}
			// 节点本身的序号设置成要移动到的目标序号
			obj.setNumber(nodeIndex);
			this.update(obj);
		}
		if(oldParentId != newParentId){
			// 在不同父节点下发生移动
			//1、相当于要移动的节点在原父节点下下移到最后再删除掉,因此要指定移动发生时节点所在的位置
			this.downNode(oldParentId, minIndex, -1);
			//2、相当于要移动的节点在新父节点下上移到指定的位置,因此需要指定要移动到的位置
			this.upNode(newParentId, maxIndex, -1);
			// 节点本身的序号设置成要移动到的目标序号
			obj.setNumber(nodeIndex);
			obj.setParentId(newParentId);
			this.update(obj);
		}
	}
	/**
	 * 指定的节点下移
	 * @param parentId	指定范围内要移动的节点的父节点
	 * @param minIndex	指定节点移动发生时所在的位置
	 * @param maxIndex	指定节点要移动到的目标位置
	 */
	@SuppressWarnings("unchecked")
	public void downNode(int parentId, int minIndex, int maxIndex){
		// 指定的节点下移,意味着其范围内的节点各自减1
		StringBuffer sql = new StringBuffer("update navigate set number=number-1 where parentId = ");
		sql.append(parentId);
		if(maxIndex != -1){
			sql.append(" and number <= ");
			sql.append(maxIndex);
		}
		if(minIndex != -1){
			sql.append(" and number > ");
			sql.append(minIndex);
		}		
		this.bulkUpdate(sql.toString());
	}
	/**
	 * 指定的节点上移
	 * @param parentId	指定范围内要移动的节点的父节点
	 * @param minIndex	指定节点要移动到的目标位置
	 * @param maxIndex	指定节点移动发生时所在的位置
	 */
	@SuppressWarnings("unchecked")
	public void upNode(int parentId, int minIndex, int maxIndex){
		// 指定的节点上移,意味着其范围内的节点各自加1
		StringBuffer sql = new StringBuffer("update navigate set number=number+1 where parentId = ");
		sql.append(parentId);
		if(maxIndex != -1){
			sql.append(" and number < ");
			sql.append(maxIndex);
		}
		if(minIndex != -1){
			sql.append(" and number >= ");
			sql.append(minIndex);
		}
		this.bulkUpdate(sql.toString());
	}
	/**
	 * 批量更新或删除操作
	 * @param sql
	 */
	public void bulkUpdate(String sql){
		Connection conection = null;
		Statement stmt = null;
		try{
			conection = DBConn.getConnection(); 
			stmt = conection.createStatement();
			stmt.executeUpdate(sql);
		}catch(Exception e){
			e.printStackTrace();			
		}finally{
			try{    	
	        	if (stmt != null) {
		        	try {
		        		stmt.close();
		        	} catch (SQLException sqlex) {
		        	}
		        	stmt = null;
	        	}
	        	if (conection != null) {
		        	try {
		        		conection.close();
		        	} catch (SQLException sqlex) {
		        	}
		        	conection = null;
	        	}
			}catch(Exception e){
				e.printStackTrace();
			}
		}
	}
}


3、Service层
package com.demo.navigate.service;

import java.io.Serializable;
import java.util.List;

import com.demo.navigate.dao.NavigateDao;
import com.demo.navigate.model.Navigate;

public class NavigateManager {
	private NavigateDao dao = NavigateDao.getInstanece();
	public Navigate get(Serializable id){
		return dao.get(id);
	}
	/**
	 * 获得指定节点的所有儿子节点
	 * @param id
	 */
	@SuppressWarnings("unchecked")
	public List<Navigate> getChildrenById(Integer id){
		return dao.getChildrenById(id);
	}
	/**
	 * 保存数据
	 * @param obj 
	 */
	public void save(Navigate obj){
		dao.save(obj);
	}
	/**
	 * 更新数据
	 * @param obj 
	 */
	public void update(Navigate obj){
		dao.update(obj);
	}
	/**
	 * 删除指定的一条数据
	 * @param id
	 */
	public void removeById(Integer id){
		dao.removeById(id);
	}
	/**
	 * 异步更新标题
	 * @param id
	 * @param title
	 * @return true-修改成功 false-修改失败
	 */
	public Boolean ajaxUpdateTitle(Integer id,String title){
		return dao.ajaxUpdateTitle(id, title);
	}
	/**
	 * 异步删除数据,包括其子孙节点
	 * @param id
	 * @param title
	 */
	public void ajaxRemoveNode(Integer id){
		Navigate obj = dao.get(id);
		dao.downNode(obj.getParentId(), obj.getNumber(), -1);
		dao.ajaxRemoveNode(id);
	}
	/**
	 * 异步移动指定节点
	 * @param id	指定的节点的id
	 * @param oldParentId	节点移动前所在的父节点
	 * @param newParentId	节点移动后的目标父节点
	 * @param nodeIndex		节点移动后的目标位置
	 */
	public void ajaxMoveNode(int id, int oldParentId, int newParentId, int nodeIndex){
		dao.ajaxMoveNode(id, oldParentId, newParentId, nodeIndex);
	}
}


4、Servlet层
a)edit
package com.demo.navigate.web;

import java.io.IOException;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.demo.navigate.model.Navigate;
import com.demo.navigate.service.NavigateManager;

@SuppressWarnings("serial")
public class NavigateEditServlet extends HttpServlet {
	
	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		this.doPost(request, response);
	}
	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		String idstr = request.getParameter("id");
		String parentId = request.getParameter("parentId");
		String leaf = request.getParameter("leaf");
		String number = request.getParameter("number");
		Navigate obj = null;
		if(null != idstr){
			NavigateManager navigateManager = new NavigateManager();
			obj = navigateManager.get(idstr);
		}else{
			obj = new Navigate();
			obj.setParentId(new Integer(parentId));
			obj.setLeaf(new Integer(leaf));
			obj.setNumber(new Integer(number));
		}
		request.setAttribute("obj", obj);
		RequestDispatcher dispatcher = request.getRequestDispatcher("/navigate/console-edit.jsp");
		dispatcher.forward(request, response);
	}
}


b)save
package com.demo.navigate.web;

import java.io.IOException;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.demo.navigate.model.Navigate;
import com.demo.navigate.service.NavigateManager;

@SuppressWarnings("serial")
public class NavigateSaveServlet extends HttpServlet {
	
	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		this.doPost(request, response);
	}
	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		NavigateManager navigateManager = new NavigateManager();
		Navigate obj = null;
		request.setCharacterEncoding("UTF-8");
		String id = request.getParameter("id");
		String number = request.getParameter("number");
		String parentId = request.getParameter("parentId");
		String leaf = request.getParameter("leaf");
		String title = request.getParameter("title");
		String url = request.getParameter("url");
		
		if(null != id && !"".equals(id)){
			obj = navigateManager.get(id);
			if(obj == null){
				RequestDispatcher dispatcher = request.getRequestDispatcher("/navigate/error.jsp");
				dispatcher.forward(request, response);
				return;
			}
		}else{
			obj = new Navigate();
			obj.setLeaf(new Integer(leaf));
			obj.setParentId(new Integer(parentId));
		}
		obj.setNumber(new Integer(number));
		obj.setTitle(title);
		obj.setUrl(url);
		if(null != id && !"".equals(id)){
			navigateManager.update(obj);
		}else{
			navigateManager.save(obj);
		}
		RequestDispatcher dispatcher = request.getRequestDispatcher("/navigate/success.jsp");
		dispatcher.forward(request, response);		
	}

}


c)json
package com.demo.navigate.web;

import java.io.IOException;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.demo.navigate.service.NavigateManager;

@SuppressWarnings("serial")
public class NavigateJsonServlet extends HttpServlet {
	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		this.doPost(request, response);
	}
	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		NavigateManager navigateManager = new NavigateManager();
		request.setAttribute("list", navigateManager.getChildrenById(new Integer(request.getParameter("id"))));
		RequestDispatcher dispatcher = request.getRequestDispatcher("/navigate/console-json.jsp");
		dispatcher.forward(request, response);
	}

}



页面:
1、edit
<%@ page contentType="text/html;charset=UTF-8" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ include file="/common/in.jsp"%>
<html>
<head>
	<base href="<%=basePath%>">
	<title>菜单编辑</title>
	<link rel="stylesheet" type="text/css" href="scripts/ext/resources/css/ext-all.css">
	<script type="text/javascript" src="scripts/ext/adapter/ext/ext-base.js"></script>



	<script type="text/javascript" src="scripts/ext/ext-all.js"></script>
	<script type="text/javascript">
		function checkForm(form){
			if(form.parentId.value == "" || form.leaf.value == ""){
				Ext.Msg.alert("错误提示","表单信息不健全!");
				return false;
			}
			if(form.title.value == ""){
				Ext.Msg.alert("错误提示","标题不能为空!");
				return false;
			}
		}
	</script>
</head>
<body style="background-color: white">
	<br/><br/>
	<form action="navigatesave" method="post" onsubmit="return checkForm(this)">
		<input type="hidden" name="id" value="${obj.id}"/>
		<input type="hidden" name="parentId" value="${obj.parentId}"/>
		<input type="hidden" name="leaf" value="${obj.leaf}"/>
		<input type="hidden" name="number" value="${obj.number}"/>
		<table align="center">
			<tr><td width="60">标题:</td>
				<td><input type="text" name="title" value="${obj.title}"/></td></tr>
			<c:if test="${obj.leaf==1}">
			<tr><td>URL:</td>
				<td><input type="text" name="url" value="${obj.url}"/></td></tr>
			</c:if>
			<tr><td colspan="2" align="center">
					<br/>
					<input type="submit" name="submit" value="保存"/>
					&nbsp;&nbsp;
					<input type="reset" name="reset" value="重置"/>
					&nbsp;&nbsp;
					<input type="button" name="button" value="取消" onclick="window.parent.FormEditWin.close();">
				</td></tr>
		</table>
	</form>
</body>
</html>



2、success
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>信息更新成功</title>
<script type="text/javascript">
	// 信息保存成功后,刷新父节点
	this.parent.FormEditWin.reloadNavNode();
</script>
</head>
<body>
	<center>
		恭喜,信息更新成功!
	</center>
</body>
</html>


3、json
<%@ page contentType="text/html;charset=UTF-8" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>

<c:set var="len" value="${fn:length(list)-1}" ></c:set>
[
<c:forEach items="${list}" var="obj" varStatus="i">
{
	id:'${obj.id}',
	text:'${obj.title}',
	<c:if test="${obj.leaf == 1}">
		leaf:true,
	</c:if>
	singleClickExpand:true
}
	<c:if test="${i.index<len}">,</c:if>
</c:forEach>
]


4、in.jsp
<%@ page language="java" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>


js核心:
console-index.js
// 全局路径
var basePath = "http://localhost:8080/langsinext";
if(typeof(glbRootPath) != "undefined"){
	basePath = glbRootPath;
}
// 扩展窗体
FormEditWin = function(){
	var curFormWin;
	return {
		width : 600,
		height : 400,
		showAddDirWin : function(parentNode) {
			// 显示添加子目录窗口
			var number = parentNode.indexOf(parentNode.lastChild) + 1;
			var editpage = basePath
					+ "/navigateedit?parentId="
					+ parentNode.id + "&leaf=0&number=" + number;
			var window = this.createWin("windirnew", "新建目录节点", editpage, function() {
				parentNode.reload();
			});
			window.show();
		},
		showAddLeafWin : function(parentNode) {
			// 显示添加子叶子节点窗口
			var number = parentNode.indexOf(parentNode.lastChild) + 1;
			var editpage = basePath
					+ "/navigateedit?parentId="
					+ parentNode.id + "&leaf=1&number=" + number;
			var window = this.createWin("winleafnew", "新建叶子节点", editpage, function() {
				parentNode.reload();
			});
			window.show();
		},
		showEditDirWin : function(node) {
			// 显示目录编辑窗口
			var editpage = basePath
					+ "/navigateedit?id=" + node.id;
			var window = this.createWin("win" + node.id, node.text, editpage, function() {
				var nodeparent = node.parentNode;
				var tree = node.getOwnerTree();
				nodeparent.on("expand", function(pnode) {
					tree.getNodeById(node.id).select();
				}, this, {
					single : true
				});
				node.parentNode.reload();
			});
			window.show();
		},
		showEditLeafWin : function(node) {
			// 显示叶子节点编辑窗口
			var editpage = basePath
					+ "/navigateedit?id=" + node.id;
			var window = this.createWin("win" + node.id, node.text, editpage, function() {
				var nodeparent = node.parentNode;
				var tree = node.getOwnerTree();
				nodeparent.on("expand", function(pnode) {
					tree.getNodeById(node.id).select();
				}, this, {
					single : true
				});
				node.parentNode.reload();
			});
			window.show();
		},
		createWin : function(winId, winTitle, iframePage, closeFun) {
			// 供各类型窗口创建时调用
			var win = Ext.getCmp(winId);
			if (!win) {
				win = new Ext.Window({
					id : winId,
					title : "菜单编辑窗口-" + winTitle,
					width : this.width,
					height : this.height,
					maximizable : true,
					modal : true,
					html : "<iframe width='100%' height='100%' frameborder='0' src='"
							+ iframePage + "'></iframe>"
				});
				this.reloadNavNode = closeFun;
			}
			curFormWin = win;
			return win;
		},
		reloadNavNode : function() {
		},
		close : function() {
			if(curFormWin){
				curFormWin.close();
			}
		}
	}
}();

// 导航树
NavTree = function(){
	var nav;
	var navEditor;
	var leafMenu;
	var dirMenu;
	var loader;
	var root;
	var removeFlag = false;
	var titleChangeFlag = false;
	var nodeSelected;
	var mgr;
	return {
		init : function(){
			if(!mgr){
				Ext.Msg.alert("警告提示","请先通过NavTree.setMgr()设置mgr");
				return;
			}
			if(!loader){
				loader = new Ext.tree.TreeLoader({
					url : basePath + '/navigatejson'
				});
				loader.on('beforeload', function(treeloader, node) {
					treeloader.baseParams = {
						id : node.id,
						method : 'tree'
					};
				}, this);
			}
			if(!root){
				root = new Ext.tree.AsyncTreeNode({
					id : '0',
					text : "系统菜单"
				});
			}
			if(!nav){
				nav = new Ext.tree.TreePanel({
					title : "左部导航",
					width : 232,
					autoScroll : true,
					animate : true,
					loader : loader,
					root : root,
					enableDD : true,
					listeners : {
						'click' : function(node, event) {
							if (node.isLeaf()) {
								// 为叶子节点时,点击不进入链接
								event.stopEvent();
							}
						}
					}
				});
				// 添加右键菜单
				nav.on("contextmenu", this.showTreeMenu);
				// 当节点文本改变时触发事件
				nav.on("textchange", function(node, newText, oldText) {
					if (!titleChangeFlag && newText != oldText) {
						mgr.ajaxUpdateTitle(node.id, newText, function(success) {
							if (!success) {
								Ext.Msg.show({
									title : "操作失败!",
									msg : "菜单修改失败!",
									buttons : Ext.Msg.OK,
									icon : Ext.MessageBox.ERROR
								});
								titleChangeFlag = true;
								node.setText(oldText);
								titleChangeFlag = false;
							}
						});
					}
				});
				// 当节点移动时触发事件
				nav.on("movenode", function(tree, node, oldParent, newParent, index) {
					mgr.ajaxMoveNode(node.id, oldParent.id, newParent.id, index);
				});
				// 当节点删除时触发事件
				nav.on("remove", function(tree, parentNode, node) {
					if (removeFlag) {
						mgr.ajaxRemoveNode(node.id);
					}
				});
			}
			if(!navEditor){
				navEditor = new Ext.tree.TreeEditor(nav, {
					allowBlank : false,
					ignoreNoChange : true,
					blankText : '标题不能为空',
					selectOnFocus : true
				});
			}
			this.setLeafMenu();
			this.setDirMenu();
		},
		setMgr : function(manager){
			mgr = manager;
		},
		getMgr : function(){
			return mgr;
		},
		setLeafMenu: function(){
			// 设置叶子菜单
			if(!leafMenu){
				leafMenu = new Ext.menu.Menu({
					items : [{
						text : "修改标题",
						handler : function() {
							navEditor.triggerEdit(nodeSelected);
						}
					}, "-", {
						text : "编辑",
						handler : function() {
							FormEditWin.showEditLeafWin(nodeSelected);
						}
					}, "-", {
						text : "删除",
						handler : this.delTreeItemComfirm
					}]
				});
			}
		},
		setDirMenu: function(){
			// 设置目录菜单
			if(!dirMenu){
				dirMenu = new Ext.menu.Menu({
					items : [{
						text : "修改标题",
						handler : function() {
							navEditor.triggerEdit(nodeSelected);
						}
					}, "-", {
						text : "编辑",
						handler : function() {
							FormEditWin.showEditDirWin(nodeSelected);
						}
					}, "-", {
						text : "添加叶子节点",
						handler : function() {
							FormEditWin.showAddLeafWin(nodeSelected);
						}
					}, "-", {
						text : "添加目录节点",
						handler : function() {
							FormEditWin.showAddDirWin(nodeSelected);
						}
					}, "-", {
						text : "删除",
						handler : this.delTreeItemComfirm
					}]
				});
			}
		},
		showTreeMenu : function(node, e){
			nodeSelected = node;
			nodeSelected.select();
			if (node.isLeaf()) {
				// 显示叶子节点菜单
				leafMenu.showAt(e.getPoint());
			} else {
				// 显示目录节点菜单
				dirMenu.showAt(e.getPoint());
			}
		},
		delTreeItemComfirm : function(){
			Ext.Msg.confirm("确认删除", "确定要删除所选节点吗?", function(btn) {
				if (btn == "yes") {
					NavTree.delTreeItem();
				}
			});
		},
		delTreeItem : function(){
			if (nodeSelected != nav.getRootNode()) {
				removeFlag = true;
				nodeSelected.remove();
				removeFlag = false;
			} else {
				Ext.Msg.alert("警告", "不能删除树的根节点!");
			}
		},
		show : function(){
			nav.render(Ext.getBody());
			nav.getRootNode().toggle();
		}
	}
}();

// 文档加载完毕执行
Ext.onReady(function(){
	Ext.BLANK_IMAGE_URL = "../scripts/ext/resources/images/default/s.gif";
	if(typeof(NavigateManager)=="undefined"){
		Ext.Msg.alert("警告提示","请先设置DWR,并实例化NavigateManager");
	}else{
		NavTree.setMgr(NavigateManager);
		NavTree.init();
		NavTree.show();
	}
});


dwr配置:
dwr.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 2.0//EN" "http://www.getahead.ltd.uk/dwr//dwr20.dtd">

<dwr>
	<allow>
		<create javascript="NavigateManager" creator="new">
			<param name="class"
				value="com.demo.navigate.service.NavigateManager">
			</param>
			<include method="ajaxUpdateTitle" />
			<include method="ajaxRemoveNode" />
			<include method="ajaxMoveNode" />
		</create>
	</allow>
</dwr>


servlet配置:
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" 
	xmlns="http://java.sun.com/xml/ns/j2ee" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
	http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
  <servlet>
		<servlet-name>navigatejson</servlet-name>
		<servlet-class>
			com.demo.navigate.web.NavigateJsonServlet
		</servlet-class>
	</servlet>
	<servlet>
		<servlet-name>navigateedit</servlet-name>
		<servlet-class>
			com.demo.navigate.web.NavigateEditServlet
		</servlet-class>
	</servlet>
	<servlet>
		<servlet-name>navigatesave</servlet-name>
		<servlet-class>
			com.demo.navigate.web.NavigateSaveServlet
		</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>navigatejson</servlet-name>
		<url-pattern>/navigatejson</url-pattern>
	</servlet-mapping>
	<servlet-mapping>
		<servlet-name>navigateedit</servlet-name>
		<url-pattern>/navigateedit</url-pattern>
	</servlet-mapping>
	<servlet-mapping>
		<servlet-name>navigatesave</servlet-name>
		<url-pattern>/navigatesave</url-pattern>
	</servlet-mapping>
	<servlet>
		<servlet-name>dwr-invoker</servlet-name>
		<servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class>
		<init-param>
			<param-name>debug</param-name>
			<param-value>true</param-value>
		</init-param>
		<init-param>
			<param-name>
				allowGetForSafariButMakeForgeryEasier
			</param-name>
			<param-value>true</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>dwr-invoker</servlet-name>
		<url-pattern>/dwr/*</url-pattern>
	</servlet-mapping>
	<welcome-file-list>
		<welcome-file>index.jsp</welcome-file>
	</welcome-file-list>
</web-app>

分享到:
评论
41 楼 1045565111 2014-05-05  
谢谢,运行起来了,非常不错~~~
40 楼 Mr.xiaopang 2013-10-29  
请问下,把你这课树放在viewport的左边——west,该怎么弄啊?自己试着弄的不成功,可能是对楼主的代码理解的不透彻,QQ:993353141,希望能够指点一二,我也是才接触extjs。多谢!!!
39 楼 w493778311 2013-09-17  
缺少好多JS文件
38 楼 春夏虫 2012-08-28  
好强大的树
37 楼 lijin2031427 2012-06-01  
请问那个 URL 填完后,点击为什么没有响应,能帮忙说下是什么原因吗?
36 楼 lys221221 2011-09-22  
老师 我看了你的视频有些问题想问你  能加我qq吗 497234690
35 楼 lys221221 2011-09-22  
你好 老师  我把你的源码下载下来啦  部署上怎么 就光显示 一小部分啊  我不知道什么原因  光显示系统菜单  子菜单都不显示   能给解释下吗 我qq是497234690
34 楼 36032075 2011-07-25  
请先设置DWR,并实例化NavigateManager  啥意思啊?
33 楼 winnerliub 2011-05-22  
最近看了这个例子,很好。能否给个插入数据(insert into)的实例,谢谢!
32 楼 cl1154781231 2011-02-23  
非常好 可以用!
31 楼 fx23794087 2010-02-11  
如何把他放到指定的table中啊?
30 楼 zengqun89 2010-01-08  
丫姐姐,您的项目我下载了,用的很好,
太有才了,呵呵
只是页面中有乱码,在添加后,
这是什么原图呢
29 楼 longxiaoyan 2009-12-24  
jj,你的项目里面id不好使啊。每次新加一个叶子或者树枝节点,id都
String id = request.getParameter("id");

这样的话id就为0了,然后你:
obj = navigateManager.get(id);

这样的话根本就保存不了。
28 楼 wintys 2009-12-16  
davy138 写道
你好! 请问添加节点时, 提示需要验证:

http://localhost:8080 请求用户名和密码。信息为: “XDB”

用户名:

密码:

请问用什么用户和密码呢?



提示XDB,我试了也出现这样的情况。但是这是因为Oracle也占用了8080端口,这个提示是Oracle 中自带的Apache提示的。所以,要么改Oracle中的端口,要么把运行本工程的Tomcat服务器商品改了。
27 楼 javaAlpha 2009-11-11  
运行没问题
26 楼 javaAlpha 2009-11-11  
最近也在做ext项目,遇到类似问题。过来看看
25 楼 zjzh123456 2008-12-04  
如何设置tree的显示位子。我设置了用于显示树的层,但是在运行时无法显示完整。能指出如何在指定的层中显示树么?
24 楼 yahaitt 2008-11-28  
zjzh123456 写道

为什么我在界面上的操作没有存入数据库呢?我已经修改了DAO文件

请在跟踪下后台进行断点调试
23 楼 zjzh123456 2008-11-27  
为什么我在界面上的操作没有存入数据库呢?
我已经修改了DAO文件
22 楼 yahaitt 2008-11-04  
yourgame 写道

个人愚见:
&nbsp;&nbsp; extjs有了设计很完善的ajax交互类,为了提高效率extjs貌似只会创建一个全局的ajax请求交互对象,所以在这里,我认为没有必要去使用dwr的ajax功能,dwr能做的,Ext.ajax基本都能实现。这样貌似更加完美。

谢谢yourgame,包括这个树节点的修改和添加界面同样我也没有采用panel的方式来做,否则效果也更好。我要突出“树”,而不是要突出panel和Ext的ajax。因为ajax需要另外的文章来进行描述,这样对初学者来说才可以看懂。

相关推荐

    extjs 动态树实现的demo

    extjs、struts2、mysql做的一个动态树,仅是一个动态树的小demo,不涉及角色、权限,并且数据是手动加入到数据库中的;资源中包涵数据库sql,只需创建一个名称为tree的数据库,执行sql就可以了,另外修改一下练级...

    EXTJS动态树的实现举例示例代码

    以下是一个简单的EXTJS动态树实现的步骤: 1. **定义数据模型(Model)**:首先,我们需要定义一个数据模型来描述树节点的结构。例如: ```javascript Ext.define('NodeModel', { extend: 'Ext.data.Model', ...

    extjs实现动态树

    它具有丰富的配置项和事件,支持数据源绑定,能轻松实现动态加载。 2. 数据源:动态树的数据通常来自服务器,通过Ajax请求获取JSON格式的节点数据。这些数据包括节点ID、文本、子节点等信息。 3. 节点模型:每个树...

    extjs实现动态树加载菜单

    在 ExtJS 中实现动态树加载,我们需要遵循以下步骤: 1. **配置树节点**:首先,我们需要为树节点定义模型(Ext.data.TreeModel),并在模型中设置`leaf`属性为`false`来表示这是一个可扩展的节点,而非叶子节点。...

    Extjs动态树的实现以及节点拖拽

    同时,ExtJS中的menu、tree、window等组件以及事件机制也是实现动态树的关键。 在实际项目中,动态树的实现可能还需要考虑到数据的存储结构,如导航数据表,以及页面的布局和源码组织。为了创建一个完整的动态树...

    extjs 动态树及中文API

    你可以通过Ajax请求获取服务器上的数据,并将其加载到Store中,从而实现动态加载节点。这不仅提高了页面的加载速度,还使得用户可以查看大量的层次结构数据而无需一次性加载所有内容。 首先,创建一个树形控件...

    EXTJS动态树支持checkbox 全选

    在EXTJS中,实现动态树通常需要以下步骤: 1. **配置树面板**:首先创建一个EXTJS的TreePanel,设置其配置项,如`rootVisible`(是否显示根节点)、`displayField`(显示字段)等。为了实现动态加载,需要设置`...

    EXTJS动态树的实现举例

    在EXTJS中实现动态树,主要是通过EXTJS的TreePanel组件来完成,下面将详细介绍EXTJS动态树的实现过程及其相关知识点。 1. TreePanel组件: TreePanel是EXTJS中用来展示树形结构数据的组件。它包含节点(Node)、根...

    extjs动态树struts请求数据

    通过分析和学习这个文件,可以更深入地理解ExtJS和Struts如何协作实现动态树功能。 总结以上,ExtJS动态树与Struts的结合使用,需要熟练掌握ExtJS TreePanel的配置,JSON数据的构造和解析,以及Struts2的Action和...

    Extjs4动态树的实现

    总结来说,这个例子展示了如何使用ExtJS4和Java实现一个动态树结构。前端通过TreeStore从后端动态获取数据,当用户点击树节点时,会触发新的数据请求。后端根据请求参数返回JSON数据,更新树结构。这种动态加载的...

    Extjs 动态加载树

    在描述中提到的博客链接可能提供了一个实现动态加载树的实例或教程,虽然具体内容未给出,但我们可以推测讨论的内容可能包括以下几个方面: 1. **Extjs TreePanel**: TreePanel是Extjs中用于展示树形数据的组件,它...

    Extjs 动态树 数据库

    在ExtJS中,我们可以利用TreeStore和AjaxProxy来实现动态加载。TreeStore用于存储树节点的数据,而AjaxProxy则负责向服务器发送请求并处理响应。 接下来,我们探讨**JDBC访问SQL Server数据库**。Java Database ...

    Extjs 自定义树结构实现以及动态表头实现

    在本文中,我们将深入探讨如何使用ExtJS框架来实现自定义树结构以及动态表头的功能。ExtJS是一款强大的JavaScript库,常用于构建富客户端应用程序,它提供了丰富的UI组件和强大的数据绑定机制。VS2015是Visual ...

    tree 动态树 extjs ajax

    在ExtJS中,动态树通常通过TreePanel来实现。TreePanel是一个可配置的组件,可以设置各种属性,如节点的样式、展开/折叠行为、拖放功能等。它使用TreeStore来存储和管理数据,而TreeStore可以通过Ajax proxy与服务器...

    extjs动态树的示例代码.rar

    ExtJS 是一个强大的JavaScript框架,...通过分析和学习这段代码,你可以更好地理解和应用ExtJS动态树的实现方式。记住,实际项目中可能还需要结合服务器端的接口设计和数据格式,确保数据能正确地加载到树形结构中。

    extjs 树 搜索

    总的来说,EXTJS的树形搜索功能是通过结合TreePanel、TreeStore和过滤机制实现的,它提供了灵活的搜索选项,能够满足不同场景下的数据查找需求。通过深入理解和运用这些知识点,我们可以构建出功能强大、用户体验...

    jsp+access+extjs动态树实例

    下面我们将详细探讨这三个技术在实现动态树实例中的应用。 首先,JSP(JavaServer Pages)是Java的一种动态网页技术,它允许开发者在HTML代码中嵌入Java代码,以实现动态网页的生成。在本实例中,JSP将作为服务器端...

    extjs目录树编辑

    目录树编辑功能是指EXTJS中允许用户对树形结构进行动态操作,包括添加、删除、修改和查询节点。这个功能在许多业务场景中非常实用,例如文件管理系统、权限管理界面等。EXTJS提供了一套完整的API和事件机制,使得...

    EXTJS---完整数据库代码,全网唯一,非常适合EXTJS搭建框架,包含动态树,菜单等

    2. **EXTJS树菜单**: EXTJS中的树菜单(TreeMenu)是TreePanel的一个变体,通常用作下拉菜单。它结合了树的层次结构和菜单的功能,用户可以通过选择不同的菜单节点来执行相应的操作。这种设计使得复杂的操作结构变...

Global site tag (gtag.js) - Google Analytics