dojo提供了不錯的樹控件,但上下文菜單比較簡單,不能動態改變:比如我想根據不同節點顯示不同的上下文菜單就比較困難,根據多種實驗和查閱下面提供一種實現方式。在此過程中也學到不少東西。先把解決方案說一下,再把發現過程說一下:
DOJO提供了AOP的方式來“注入”代碼,我們就把修改menu的代碼注入到TreeContextMenuV3里就可以了:
在open事件前注入我們的代碼:
dojo.event.connect("before", dojo.widget.byId("contextMenu1"), "open", this, "onContextMenuOpen");
注意before是表示在menu打開之前調用,其它關鍵字還可以是after,around。強,贊一個!
在onContextMenuOpen函數中,做改變菜單的事情:

this.onContextMenuOpen = function (evt)
{
dojo.log.info ("before context open");
dojo.log.info (evt);
var m = dojo.widget.byId("contextMenu1");
dojo.log.info (m);
m.removeChild (dojo.widget.byId("treeContextMenuEdit"));
m.removeChild (dojo.widget.byId("treeContextMenuDown"));
m.removeChild (dojo.widget.byId("treeContextMenuCreate"));
m.removeChild (dojo.widget.byId("treeContextMenuCreate2"));


if (null == this.context_menu["MenuItem2"])
{

var id = dojo.widget.createWidget("MenuItem2",
{caption: "Page Info"});
dojo.log.info (id);
this.context_menu["MenuItem2"] = id;
m.addChild(id);
}
//m.destroyChildren ();
dojo.log.info (m);
//w.destory ();
};
在這里可以根據節點來增刪菜單項了,context_menu成員是用來記錄加入過的菜單項,以免重復加入。
另外,removeChild沒有destory掉菜單項,應該可以重復使用。所以,我設想的實現是,在程序開頭將所有可能的菜單項動態創建好,存在一個MAP中,然后,在這里來動態加刪它們。
下面是尋找解決方法的過程:
剛開始時,我想是改變整個樹的菜單,確實也找到了可以編程改變它的方法:
var ctxMenu = dojo.widget.byId("contextMenu");
var tree = dojo.widget.byId("phyTree");
dojo.log.info (ctxMenu);

ctxMenu.listenTree(tree);
ctxMenu.bindDomNode(tree.domNode);

關鍵是一句:bindDomNode。
這樣雖然可以動態“加載”菜單了,可是沒有“時機”來加載新菜單,無法達到根據節點變化來做改變。
隨后,我又想到重載,去創造這個“時機”:
dojo.require ("dojo.widget.TreeContextMenuV3");

dojo.provide("mywidgets.MyTreeContextMenu");

dojo.widget.defineWidget(
// widget name and class
"mywidgets.MyTreeContextMenu",
// superclass
[dojo.widget.TreeContextMenuV3],


function()
{
dojo.log.info ("my context menu create1");
},
// properties and methods

{

open: function()
{
var result = dojo.widget.PopupMenu2.prototype.open.apply(this, arguments);
dojo.log.info ("my context menu create");

for(var i=0; i< this.children.length; i++)
{

/**//* notify children */

if (this.children[i].menuOpen)
{
this.children[i].menuOpen(this.getTreeNode());
}
}
return result;
}
}
);

這也是我第一次重載DOJO,發現其實很簡單,關鍵要注意它的namespace:
dojo.require()語句的尋找方法是:
dojo.xxx => dojo/src/xxx.js
dojo.xxx.yyy => dojo/src/xxx/yyy.js
dojo.xxx.yyy.zzz => dojo/src/xxx/yyy/zzz.js
如果遇到不是dojo開頭時,它的尋找方法是:
example.xxx => dojo/../example/xxx.js
example.xxx.yyy => dojo/../example/xxx/yyy.js
example.xxx.yyy.zzz => dojo/../example/xxx/yyy/zzz.js
所以要把自己的代碼放到跟dojo同級就可以了。
這個辦法我沒往下試,因為重載的是contextmenu,在它里面把它“整個自己”換成別的menu,我覺得是不可行的。而看半天代碼也沒找著在哪重載右鍵點擊這個事件。不過啟發我可以更換子item來解決。
于是有了開頭的解決方案。
posted on 2007-07-01 11:15
我愛佳娃 閱讀(2613)
評論(3) 編輯 收藏 所屬分類:
AJAX