Dojo树使用心得

感谢reedseutozte的投稿,一篇关于dijit.Tree的使用方法介绍,非常好的文章,也很能体现出Dojo的核心设计思想。作为最常用的一个控件,相信这篇文章能帮助到很多同学。再次感谢reedseutozte,为Dojo中文博客带来了第一篇投稿文章:)


概述

Dojo的dijit.tree的代码结构完全遵循MVC结构,结构非常严谨:

M:model使用了dojo基础包提供的dojo.data.itemFileReadStore(只读)或者dojo.data.itemFileWriteStore(可读写)。Tree并不直接使用Store而是通过dijit.tree.TreeStoreModel这个类将sotre和树形结构所需要的结构的进行串接。
V:view就是tree.js中定义的dijit.tree和dijit_TreeNode。这个类主要完成前台的界面渲染,以及树上节点对象之间的管理。
C:_dndSelector.js这个文件名称开始迷惑了我,后来才发现即使不使用拖拽特性,该类中的代码依然会被调用,这个类定义选中节点,删除节点,增加节点,托拽节点的操作。

网上关于tree 的资料根多,而且dojo自身也提供了丰富的样例,这里介绍一些其样例中没有涉及的一些用法


树的懒加载(lazy load)
其实懒加载本身没什么太多的问题,只是有两点需要说明
图标处理
Dojo对于叶子/非叶子节点的图标处理时会做自动判断。在懒加载时由于有些节点没有加载子节点,dojo在处理这些节点的图标的时候会显示认的叶子图标,所以这里需要重 新实现treemodel的mayHaveChildren方法代码如下
[javascript] view plain copy
  1. vartreeModel=newdijit.tree.ForestMode({
  2. .......
  3. });
  4. treeModel.mayHaveChildren=function(item)
  5. {
  6. //item为对应节点的数据项,该函数返回true表示该节点为非叶子节点,dojo就会为这个节点附着上非叶子图标
  7. if(item.root)
  8. {
  9. returntrue;
  10. }
  11. else
  12. //这里认为初始化树的时候对于每一个节点的数据项中都有type属性,根据属性判断
  13. return(treeModel.store.getValue(item,'type')!='xxxx')
  14. }
  15. }

节点加载
Dojo树最大的特点就是完全可以靠数据驱动,因此节点的加载,完全可以通过往对应的 父节点的数据项中增加childran实现,参见如如下代码
copy
    varoldExpand=dijit.Tree.prototype._onExpandoClick;
  1. dojo.extend(dijit.Tree,{
  2. _onExpandoClick:function(message)
  3. varnode=message.node;
  4. reloadNode(node);
  5. oldExpand.apply(this,arguments);
  6. functionreloadNode(node)
  7. varstore=node.tree.model.store;
  8. varnodeItem=node.item;
  9. //假设我们通过这个方法后台取得了改node的子节点数据
  10. vardataList=getChildList();
  11. dojo.forEach(dataList,function(x){
  12. ......
  13. x.type='yyy';
  14. //以上的代码可以看需要添加,上面一行代码的作用是可以通过store.getValue方法访问该节点对应的item的type属性
  15. store.newItem(x,{parent:nodeItem,attribute:'children'});
  16. 增加删除修改节点
    之前已经说过dojo的tree采用了MVC模式,因此上述操作完全可以通过对store的操作实现
    1. 增加
    上面的懒加载代码已经列出这里不再赘述
    2. 修改
    假设需要修改的节点的treeNode对象实例为node
    copy
    tree.model.store.setValue(node.item,'name'/*取决于定义store时的label属性*/,newName)

3. 删除
假设需要删除的节点的treeNode对象实例为node
copy
    tree.model.store.deleteItem(node.item)

鼠标函数
上面说了很多,可以发现所有操作都需要获取树节点对应的dojo对象才可以进行。那么这个对象如何获得呢?我们知道对树的操作分为两种,左键点击或者右键菜单,鼠标点中了相对应的节点就可继续往下操作,因此下面介绍如何通过鼠标事件获得节点对象
click
copy
    tree.connect(tree,'onClick',clickTreeNode);
  1. functionclickTreeNode(item/*点中节点对应的数据项*/,node/*点中的对象,这里node.item就是的第一个参数*/,evt/*事件*/)
  2. ................
  3. }

rightClick
右击一般是打开菜单,这里的菜单也是dojo的,因此判断函数
copy
    dojo.connect(pMenu,'_openMyself',function(e){
  1. varnode=dijit.getEnclosingWidget(e.target);/*node就是节点对象*/
  2. });

代码选中节点
copy
    tree.dndController.setSelection([node])

托拽控制
Dojo的树提供托拽功能,使用托拽功能需要在实例化tree的时候将tree的dndController属性定义为’dijit.tree.dndSource' 。betweenThreshold为0表示不允许同目录下拖动。
实际应用中我们要增加一些限制,这坐介绍两种
i)选中的对象是否允许拖拽
copy
    dojo.connect(tree.dndController,'onMouseDown',0); background-color:inherit">//如果你的树上有滚动条,请加入如下代码,否则如果你选中了节点后拖动滚动条会出现节点拖拽精灵
  1. if(dijit.getEnclosingWidget(e.target)==tree)
  2. tree.dndController.mousedown=false;
  3. return;
  4. //tree.dndController.mousedown为true表示允许拖拽,反之就是不允许,e为鼠标事件对象
  5. //tree的selectednodes属性可以返回选中的节点列表,这里的代码表示每个选中节点的数据项中的type属性都是xxx才能拖动
  6. tree.dndController.mousedown=dojo.every(tree.selectednodes,153); background-color:inherit; font-weight:bold">function(node){
  7. return(tree.model.store.getValue(node.item,'type')=='xxx')
  8. });
  9. ii)判断目标节点是否接受正在拖拽的对象
    copy
      tree.checkItemAcceptance=function(target,source,position)
    1. //target:DomNode目标节点对应的dom,用dijit.getEnclosingWidget(target)可以获得TreeNode对象
    2. //source:dijit.tree.dndSource被拖动的treeNode对象,是一个列表,因为tree允许一次拖动多个节点
    3. //position:'over','before','after'
    4. //返回true表示允许drop
    5. }

    相关文章

    我有一个网格,可以根据更大的树结构编辑小块数据.为了更容易...
    我即将开始开发一款教育性的视频游戏.我已经决定以一种我可以...
    我正在使用带有Grails2.3.9的Dojo1.9.DojoNumberTextBox小部...
    1.引言鉴于个人需求的转变,本系列将记录自学arcgisapiforja...
    我正在阅读使用dojo’sdeclare进行类创建的语法.描述令人困惑...
    我的团队由更多的java人员和JavaScript经验丰富组成.我知道这...