使用easyui的treegrid实现行编辑和拖拽效果。
下面是demo界面。可以拖拽菜单(放在tr上,则拖拽到目标的子目录,放在边框上则是拖拽到同级目录)
具体实现代码:
menuList.jsp
<html>
<head>
<title>菜单列表</title>
<base href="http://localhost:8080/mysys/">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="stylesheet" type="text/css" href="easyui/themes/default/easyui.css">
<link rel="stylesheet" type="text/css" href="easyui/themes/icon.css">
<script type="text/javascript" src="easyui/jquery.min.js"></script>
<script type="text/javascript" src="easyui/jquery.easyui.min.js"></script>
<script src="easyui/locale/easyui-lang-zh_CN.js"></script>
<script type="text/javascript" src="js/js.js"></script>
<link rel="stylesheet" type="text/css" href="css/icon.css">
<script type="text/javascript" src="ms/menuList.js?d=4"></script>
<style type="text/css">
.fitem{
margin: 5px;
}
.fitem label{
display:inline-block;
width: 70px;
text-align: right;
}
.panel.datagrid{
margin: 0 auto;
}
/* 修改表格表头里面字体大小 */
.datagrid-header .datagrid-cell span{
font-size: 18px;
}
/* 修改表格里面字体大小 */
.datagrid-cell{
font-size: 16px;
}
/* 修改表格行高 */
.datagrid-row {
height: 40px;
}
td[field="enable"] td{
text-align: center;
}
</style>
<style type="text/css">
/* treegrid拖动效果 */
.row-top td{
border-top:1px solid red;
background:#fff;
}
.row-bottom td{
border-bottom:1px solid red;
background:#fff;
}
.row-append td{
border:0;
background:#FBEC88;
}
</style>
</head>
<body>
<!-- 数据网格 -->
<table id="tg" title="菜单列表"
style="width:100%;height:auto;margin:0 auto;">
</table>
</body>
</html>
$(function() {
query();
})
function query() {
// $('#tg').treegrid("options")
$('#tg').treegrid({
url:'menu/list',
idField:'id',
treeField:'name',
rownumbers:true,//第一列显示序号
fitColumns:true,//列宽按比例扩展到最大
onDblClickRow:function(row){edit()},
onLoadSuccess: function(row){
//$(this).treegrid('enableDnd', row?row.id:null);
//上面的代码是demo中的,但是对于要保存更改到数据库显然走不通,需要向其他办法
//启用拖动排序
enableDnd($('#tg'));
},
columns:[[
{field:'name',title:'name',width:100,align:'left', halign: 'center',editor:"text"},
{field:'url',title:'url',width:100,align:'center',editor:"text"},
{field:'icon',title:'icon',width:160,align:'center',editor:"text"},
{field:'seq',title:'seq',width:160,align:'center',editor:"numberbox" }
]],
toolbar: [
{ text: '添加子菜单', iconCls: 'icon-add', handler: function () {
append();
}
}, '-',
{ text: '删除', iconCls: 'icon-remove', handler: function () {
remove();
}
}, '-',
{ text: '编辑', iconCls: 'icon-edit', handler: function () {
edit();
}
}, '-',
{ text: '保存', iconCls: 'icon-save', handler: function () {
save();
}
}, '-',
{ text: '取消编辑', iconCls: 'icon-undo', handler: function () {
cancelEdit();
}
}, '-',
{ text: '刷新', iconCls: 'icon-reload', handler: function () {
query();
}
}, '-',
{ text: '更新到数据库', iconCls: 'icon-save', handler: function () {
saveToDB();
}
}, '-']
});
}
var editingId;
function append(){
var node = $('#tg').treegrid('getSelected');
if(node){
var obj = {
id: -1*Math.random(),
name:'新建菜单',
parent:{id:node.id},
left:true,
visible:true,
seq:99
};
$('#tg').treegrid('append',{
parent: node.id, // the node has a 'id' value that defined through 'idField' property
data: [obj]
});
enableDnd($('#tg'));
params_data.add.push($('#tg').treegrid('find', obj.id));
}
}
function insert(){
var node = $('#tg').treegrid('getSelected');
if (node){
var obj = {
id: -1*Math.random(),
name:'新建菜单',
parent:node.parent,
left:true,
visible:true,
seq:99
};
$('#tg').treegrid('insert', {
after: node.id,
data: obj
});
enableDnd($('#tg'));
params_data.add.push($('#tg').treegrid('find', obj.id));
}
}
function edit(){
if (editingId != undefined){
save();
}
var row = $('#tg').treegrid('getSelected');
if (row){
editingId = row.id
$('#tg').treegrid('beginEdit', editingId);
//解决添加拖拽功能后无法编辑问题
/*
var eds = $('#tg').treegrid('getEditors',editingId);
for(var i=0;i<eds.length;i++){
$(eds[i].target).bind('mousedown',function(e){
e.stopPropagation();
});
}*/
$(".datagrid-row-editing input").each(function(){
$(this).bind('mousedown',function(e){
e.stopPropagation();
});
});
}
}
function save(){
if (editingId != undefined){
$('#tg').treegrid('endEdit', editingId);
var row = $('#tg').treegrid('find', editingId);
if(row.id > 0){
params_data.update.push(row);
}
editingId = undefined;
}
}
function remove(){
var node = $('#tg').treegrid('getSelected');
if (node){
$('#tg').treegrid('remove', node.id);
if(editingId != undefined && editingId == node.id){
editingId = undefined;
}
if(node.id > 0){
params_data.delete.push(node);
}else{
var idx = params_data.add.indexOf(node);
params_data.add.remove(idx);
}
}
}
function cancelEdit(){
if (editingId != undefined){
$('#tg').treegrid('cancelEdit', editingId);
editingId = undefined;
}
}
/**保存到数据库*/
var params_data = {add: [],update: [],delete: []};
function saveToDB(){
save();
var data = {
add: [],
update: [],
delete: []
};
for(var i=0;i<params_data.add.length;i++){
delete params_data.add[i]._parentId;
delete params_data.add[i].checkState;
delete params_data.add[i].checked;
delete params_data.add[i].state;
}
for(var i=0;i<params_data.update.length;i++){
delete params_data.update[i]._parentId;
delete params_data.update[i].checkState;
delete params_data.update[i].checked;
delete params_data.update[i].state;
}
for(var i=0;i<params_data.update.length;i++){
delete params_data.update[i]._parentId;
delete params_data.update[i].checkState;
delete params_data.update[i].checked;
delete params_data.update[i].state;
}
var req_data = {};
req_data.add = JSON.stringify(params_data.add);
req_data.update = JSON.stringify(params_data.update);
req_data.delete = JSON.stringify(params_data.delete);
$.ajax({
type: "POST",
url: 'menu/save',
dataType: "json",
data: req_data,
success: function (rarg) {
if (rarg.err == undefined) {
$.messager.show({ title: '提示',
msg: '保存成功.',
timeout: 3000,
showType: 'slide'
});
params_data = {add: [],update: [],delete: []};
query();
}
else $.messager.alert('提示', rarg.err);
//refreshTab();
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
$.messager.alert('提示', '保存失败,系统繁忙,请稍后再试!');
}
});
}
function enableDnd(t){
var nodes = t.treegrid('getPanel').find('tr[node-id]');
nodes.find('span.tree-hit').bind('mousedown.treegrid',function(){
return false;
});
nodes.draggable({
disabled:false,
revert:true,
cursor:'pointer',
proxy: function(source){
var p = $('<div class="tree-node-proxy tree-dnd-no"></div>').appendTo('body');
p.html($(source).find('.tree-title').html());
p.hide();
return p;
},
deltaX: 15,
deltaY: 15,
onBeforeDrag:function(){
$(this).next('tr.treegrid-tr-tree').find('tr[node-id]').droppable({accept:'no-accept'});
},
onStartDrag:function(){
$(this).draggable('proxy').css({
left:-10000,
top:-10000
});
},
onDrag:function(e){
$(this).draggable('proxy').show();
this.pageY = e.pageY;
},
onStopDrag:function(){
$(this).next('tr.treegrid-tr-tree').find('tr[node-id]').droppable({accept:'tr[node-id]'});
}
}).droppable({
accept:'tr[node-id]',
onDragOver:function(e,source){
var pageY = source.pageY;
var top = $(this).offset().top;
var bottom = top + $(this).outerHeight();
$(source).draggable('proxy').removeClass('tree-dnd-no').addClass('tree-dnd-yes');
$(this).removeClass('row-append row-top row-bottom');
if (pageY > top + (bottom - top) / 2){
if (bottom - pageY < 5){
$(this).addClass('row-bottom');
} else {
$(this).addClass('row-append');
}
} else {
if (pageY - top < 5){
$(this).addClass('row-top');
} else {
$(this).addClass('row-append');
}
}
},
onDragLeave:function(e,source){
$(source).draggable('proxy').removeClass('tree-dnd-yes').addClass('tree-dnd-no');
$(this).removeClass('row-append row-top row-bottom');
},
onDrop:function(e,source){
var action,point;
if ($(this).hasClass('row-append')){
action = 'append';
} else {
action = 'insert';
point = $(this).hasClass('row-top') ? 'top' : 'bottom';
}
$(this).removeClass('row-append row-top row-bottom');
//alert(action+":"+point);
// your logic code here
// do append or insert action and reload the treegrid data
var src = t.treegrid('find', $(source).attr('node-id'));
var dest = t.treegrid('find', $(this).attr('node-id'));
//alert(src.name+","+dest.name);
if (src){
t.treegrid('remove', src.id);
}
if(action == "append"){
src.parent = {};
src.parent.id = dest.id;
t.treegrid('append',{
parent: dest.id, // the node has a 'id' value that defined through 'idField' property
data: [src]
});
}else if(action == "insert"){
src.parent = dest.parent;
var obj = {
before: dest.id,
after: dest.id,
data: src
}
if(point == "top"){
delete obj.after;
}else{
delete obj.before;
}
t.treegrid('insert', obj);
}
if(src.id > 0){
params_data.update.push(src);
}
enableDnd(t);
/*
$.ajax({
url: 'updateCatalogList',
dataType: 'json',
type:'post',
data: {
"srcId": src.id,
"destId": dest.id
},
success:function(data){
if(data.result)
{
$('#tt').treegrid('reload'); //重新加载treegrid
}
}
});
*/
}
});
}
MenuAction.java
@RequestMapping(value = "list")
@ResponseBody
public List<Menu> list(@RequestParam Map map) {
List<Menu> list = menuService.list(map);
return list;
}
@RequestMapping(value = "save")
@ResponseBody
public Map save(@RequestParam String add
,@RequestParam String delete
,@RequestParam String update) {
JSONArray addArr = JSONArray.fromObject(add);
JSONArray deleteArr = JSONArray.fromObject(delete);
JSONArray updateArr = JSONArray.fromObject(update);
List<Menu> addlist = (List) JSONArray.toCollection(addArr,
Menu.class);
List<Menu> deletelist = (List) JSONArray.toCollection(deleteArr,
Menu.class);
List<Menu> updatelist = (List) JSONArray.toCollection(updateArr,
Menu.class);
menuService.saveAll(addlist,deletelist,updatelist);
Map map = new HashMap();
return map;
}
访问menu/list的结果:
[{"id":3,"parent":null,"name":"系统设置","url":null,"visible":true,"leaf":true,"seq":1,"roles":[],"children":[],"icon":null},{"id":6,"parent":null,"name":"基础数据","url":null,"visible":true,"leaf":true,"seq":2,"roles":[],"children":[],"icon":null},{"id":7,"parent":null,"name":"权限管理","url":null,"visible":true,"leaf":true,"seq":3,"roles":[],"children":[{"id":9,"parent":{"id":7,"parent":null,"name":null,"url":null,"visible":false,"leaf":false,"seq":0,"roles":[],"children":[],"icon":null},"name":"用户管理","url":"user/list","visible":true,"leaf":true,"seq":1,"roles":[],"children":[],"icon":"3"},{"id":10,"parent":{"id":7,"parent":null,"name":null,"url":null,"visible":false,"leaf":false,"seq":0,"roles":[],"children":[],"icon":null},"name":"角色管理","url":"role/list","visible":true,"leaf":true,"seq":2,"roles":[],"children":[],"icon":"2"},{"id":11,"parent":{"id":7,"parent":null,"name":null,"url":null,"visible":false,"leaf":false,"seq":0,"roles":[],"children":[],"icon":null},"name":"菜单管理","url":"menu/list","visible":true,"leaf":true,"seq":3,"roles":[],"children":[],"icon":null}],"icon":null},{"id":8,"parent":null,"name":"订单管理","url":null,"visible":true,"leaf":true,"seq":4,"roles":[],"children":[],"icon":null}]
1.结点的新增、删除、修改。editingId是使用treegrid控件后创建的一个全局变量。
2.实现拖拽功能。调用方法:enableDnd($('#tg'));
3.拖拽功能导致编辑器无法正常工作。解决方法是在edit()中执行下面代码:
$(".datagrid-row-editing input").each(function(){
$(this).bind('mousedown',function(e){
e.stopPropagation();
});
});
4.主要使用的到api:
$('#tg').treegrid('append', {parent: node.id,data: [obj]});
$('#tg').treegrid('insert', {before: node.id,data: obj});
$('#tg').treegrid('insert', {after: node.id,data: obj});
$('#tg').treegrid('beginEdit', editingId);
$('#tg').treegrid('endEdit', editingId);
var row = $('#tg').treegrid('find', editingId);
var node = $('#tg').treegrid('getSelected');
$('#tg').treegrid('cancelEdit', editingId);
onDblClickRow:function(row){edit()},