Ext tree基本使用及拖拽的使用

 近期对Ext树的使用比较多,把用到的技巧整理一下,主要分两部分:树的基本用法、拖拽时的几个难点。

一、基本用法

实现了如下功能点:右键功能、添加子节点、添加兄弟节点、树内的拖拽、叶子节点不可append问题

Ext.onReady(function() {
Ext.QuickTips.init();// tip信息
Ext.BLANK_IMAGE_URL = "lib/extjs/resources/images/default/s.gif";
Ext.form.Field.prototype.msgTarget = 'side';// 控件错误提示信息位置
var treeLoader = new Ext.tree.TreeLoader({
     dataUrl : 'tree.tbdo?cmd=loadData&pid=1'
    });
var rootNode = new Ext.tree.AsyncTreeNode({
     id : '1',
     text : 'Root'
    });

var tree = new Ext.tree.TreePanel({
     renderTo : 'treecontainer',
     loader : treeLoader,
     root : rootNode,
     enableDD : true
    });

var contextMenu = new Ext.menu.Menu({
     items : [{
        text : '添加子节点',
        handler : addHandler
       }, {
        text : '添加兄弟点',
        handler : addBrotherHandler
       }, {
        text : '删除',
        handler : deleteHandler
       }, {
        text : '重命名',
        handler : modifyHandler
       }, {
        text : '查看',
        handler : viewHandler
       }]
    });
var treeSorter = new Ext.tree.TreeSorter(tree, {
     folderSort : true,
     dir : 'asc'
    });
var treeEditor = new Ext.tree.TreeEditor(tree, {
     allowBlank : false,
     cancelOnEsc : true
    });
// 弹出窗口
var win = new Ext.Window({
     maskDisabled : false,
     id : 'tree-window',
     modal : true,// 是否为模式窗口
     constrain : true,// 窗口只能在viewport指定的范围
     closable : true,// 窗口是否可以关闭
     closeAction : 'hide',
     layout : 'fit',
     width : 300,
     height : 200,
     plain : true,
     items : [{
        id : 'tree-window-view',
        border : false
       }]
    });

tree.on('contextmenu', treeContextHandler);
// 用于展开节目时获取数据
tree.on('beforeload', function(node) {
     tree.loader.dataUrl = 'tree.tbdo?cmd=loadData&pid=' + node.id; // 定义子节点的Loader
    });
// 拖拽后
tree.on('beforemovenode',
function(tree, node, oldParent, newParent, index) {
     // alert(tree + '-' + node + '-' + oldParent + '-' + newParent + '-' + index);
     //TODO 存储入库的操作
    });

// 拖拽判断,用于处理叶节目不能append的问题
tree.on('nodedragover', function(e) {
     var n = e.target;
     if (n.leaf) {
      n.leaf = false;
     }
     return true;
    });
treeEditor.on('beforecomplete', function(editor, newValue, oldValue) {
    });

rootNode.expand(false, true);

function treeContextHandler(node, event) {
   event.preventDefault();// 这行是必须的,使用preventDefault方法可防止浏览器的默认事件操作发生
   node.select();
   contextMenu.show(node.ui.getAnchor());
}
// 插入子节点
function addHandler() {
   var newNode = new Ext.tree.TreeNode({
      text : '新建节点'
     });
   var selectedNode = tree.getSelectionModel().getSelectedNode();
   selectedNode.leaf = false;
   selectedNode.expand(false, true, function() {
      // 注意,应该先由expand展开非叶子节点,才能为之插入子节点,否则会出错
      selectedNode.appendChild(newNode);
      tree.getSelectionModel().select(newNode);
      setTimeout(function() {
         treeEditor.editNode = newNode;
         treeEditor.startEdit(newNode.ui.textNode);
        }, 10);
     });
}
function addBrotherHandler() {
   var newNode = new Ext.tree.TreeNode({
      text : '新建节点'
     });
   var selectedNode = tree.getSelectionModel().getSelectedNode();
   var selectedParentNode = selectedNode.parentNode;

   if (selectedParentNode == null) {
    selectedNode.appendChild(newNode);
   } else {
    selectedParentNode.insertBefore(newNode, selectedNode);
   }
   setTimeout(function() {
      treeEditor.editNode = newNode;
      treeEditor.startEdit(newNode.ui.textNode);
     }, 10);
}
function deleteHandler() {
   tree.getSelectionModel().getSelectedNode().remove();
}
function modifyHandler() {
   var selectedNode = tree.getSelectionModel().getSelectedNode();// 得到选中的节点
   treeEditor.editNode = selectedNode;
   treeEditor.startEdit(selectedNode.ui.textNode);
}
function viewHandler() {
   var viewPanel = Ext.getCmp('tree-window-view');
   var selectedNode = tree.getSelectionModel().getSelectedNode();
   // 得到选中的节点
   var tmpid = selectedNode.attributes.id;
   var tmpname = selectedNode.attributes.text;
   var tmpdes = selectedNode.attributes.description;
   var tmphref = selectedNode.attributes.href;

   win.setTitle(tmpname + '的介绍');
   win.show();

   var dataObj = {
    id : tmpid,
    name : tmpname,
    des : tmpdes,
    href : tmphref
   }
   var tmpTpl = new Ext.Template([
     '<div style="margin:10px"><div style="margin:10px">编号:{id}</div>',
     '<div style="margin:10px">名称:{name}</div>',
     '<div style="margin:10px">描述:{des}</div>',
     '<div style="margin:10px">链接:{href}</div></div></div>']);

   tmpTpl.overwrite(viewPanel.body, dataObj);
}
});

 

二、拖拽中遇到的几个问题

要实现树的拖拽,只要将treePanel中的几个属性打开即可,在此不再赘述。本文着重整理了一些在实际操作中会遇到的几个问题:

1. 树间拖拽会导致原始树节点减少问题。

当一个节目从树A拖到树B上,A上的该节目默认会减少,有时候我们并不需要这种效果,要求树A保持不变,可采用如下解决方案:

对接收节点的树B添加一个事件,将拖拽过来的节点copy一下,即可避免树A节点减少。

tree.on('beforenodedrop', function(e){
    var n = e.dropNode; // the node that was dropped
    var copy = new Ext.tree.TreeNode( // copy it
          Ext.apply({}, n.attributes) 
    );
    e.dropNode = copy; // assign the copy as the new dropNode
});

上述方法不能处理子节点,下面的操作则可解决子节点问题
tree.on('beforenodedrop', function(e){
e.dropNode = copyDropNode(e.dropNode);
});


function copyDropNode(node){
var newNode = new Ext.tree.TreeNode(Ext.apply({}, node.attributes));
   for(var i=0; i < node.childNodes.length; i++){
   n = node.childNodes[i];
   if(n){
    newNode.appendChild(copyDropNode(n));
   }
}
return newNode;
}

2. 飞回动画问题。

tree与panel之间的drag&drop,如下代码可正确实现tree与gridPanel之间的拖拽。
但有一点,tree节点被拖拽过去后会一个节点飞回树的动画,这不是我们所希望。
解决方案是在notifyDrop完成相应处理后要有一个为true的返回值。

MainGrid = new Ext.grid.GridPanel({
enableDragDrop: true,
ddGroup : 'TreeDD', 
.....
});
var ddropTarget = new Ext.dd.DropTarget(MainGrid.getEl(), {
ddGroup: "TreeDD", 
copy:false,
notifyDrop : function(dd, e, data){
   var target = Ext.lib.Event.getTarget(e);
   var rindex = MainGrid.getView().findRowIndex(target); // index of row where item is dropped
   var destination = "";

   // drag & drop from tree to grid
   if(data.node != null)
   { 
    if (rindex === false)
    // ### drop into grid
    destination = "GRID";
    else
     destination = MainGridStore.getAt(rindex).data.name; 
     data.node.remove();
     //alert("Source: " + data.node.attributes.text + " Dest: " + destination);
   }
   // grid to grid
   else
   { 
    if (rindex === false) return false;
    if (rindex == data.rowIndex) return false;
    var rows = MainGrid.getSelectionModel().getSelections();
    var nbRows = rows.length;
    var cindex = dd.getDragData(e).rowIndex;

    for(i = 0; i < nbRows; i++) 
    {
     rowData = MainGridStore.getById(rows[i].id); 
     MainGridStore.remove(MainGridStore.getById(rows[i].id)); 
    }
    //MainGrid.getView().refresh();

    // ### display source and destination
    var sel="";
    for(i = 0; i < data.selections.length; i++) 
    {
     sel+= data.selections[i].data.name + " ";
    } 
    //alert("Source: " + sel + " Dest: " + store.getAt(rindex).data.name);
   }
}
});

For the TreePanel:
==============

MainTree = new Ext.tree.TreePanel({ 
title:'Folders', 
split:true, 
ddGroup : 'TreeDD', 
enableDD:true, 
dropConfig: {appendOnly:true},
...

});

function TreeBeforeNodeDrop(dropObj)
{
// from grid to tree
if(dropObj.data.grid != null)
{
   // get all selected grid rows
   var rows = MainGrid.getSelectionModel().getSelections();
   var nbRows = rows.length;

   for(i = 0; i < nbRows; i++) 
   { 
    MainGridStore.remove(MainGridStore.getById(rows[i].id));
   }

   //alert("source: " + dropObj.source.dragData.selections[0].data.name + " dest: " +    //dropObj.target.attributes.text);
}
//from tree to tree
else

   //alert("source: " + dropObj.dropNode.attributes.text + " dest: " +      //dropObj.target.attributes.text);
}
}

 

转自:http://hi.baidu.com/lvjunnan/blog/item/c700891232a7aa0b203f2e50.html

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值