如何相对于其触发器定位dijit.menu?

时间:2010-02-03 20:38:30

标签: dojo

我有几个这样的菜单:

// Contextual Menu
// triggers
<div id="contextMenuTrigger0">0</div>
<div id="contextMenuTrigger1">1</div>
// menu
<div dojoType="dijit.Menu" 
     targetNodeIds="contextMenuTrigger0, contextMenuTrigger1" 
     leftClicktoOpen="true" style="display:none">
      <div dojoType="dijit.MenuItem" class="first">Item One</div>
      <div dojoType="dijit.MenuItem">Item Two</div>
      <div dojoType="dijit.MenuItem">Item Three</div>
      <div dojoType="dijit.MenuItem">Item Four is really, really long item.</div>
</div>

和此:

// Tools Menu
// trigger
<div id="toolsButton">Tools</div>
// menu
<div dojoType="dijit.Menu" class="toolsMenu" 
     targetNodeIds="toolsButton" 
     leftClicktoOpen="true" style="display:none">
      <div dojoType="dijit.MenuItem" class="first">Item One</div>
      <div dojoType="dijit.MenuItem">Item Two</div>
      <div dojoType="dijit.MenuItem">Item Three</div>
      <div dojoType="dijit.MenuItem">Item Four</div>
</div>

现在,当菜单打开时,它会显示在鼠标下方。我希望它出现在相对于触发器*的特定位置。我找到了启动和onOpen事件,并尝试编写一个函数来设置菜单的domNode的样式,但它们似乎没有生效。

另外,在没有多个节点的情境中,我没有找到找出哪个节点是触发器的方法。

我看到this&amp; this,但无法进一步了解他们。

* FWIW,我希望它们的位置使菜单的左上角与上下文触发器的右上角对齐,并与工具菜单的左下角对齐。

3 个答案:

答案 0 :(得分:4)

我发现以下css覆盖效果很好,如果你只是想要自动定位的相对差异:

.dijitMenuPopup {
    margin-left: -25px !important;
    margin-top: 15px !important;
}

答案 1 :(得分:3)

事实证明,dojo.popup.open(我猜是菜单继承自)有一个参数(orient),您可以使用该参数来定位相对于节点的菜单。我最终定义了一个知道如何利用它的自定义触发器类。 (我还为其他具有不同方向的菜单类型创建了子类,但为了清楚起见,我会将它们留下来。)

UPDATE :根据this page,我不推荐在templateString中使用的变量替换方法。相反,你应该创建一个attributeMap,我在下面做了。

http://docs.dojocampus.org/quickstart/writingWidgets

// Define a basic MenuTrigger
dojo.declare("my.MenuTrigger", [dijit._Widget, dijit._Templated], {
    // summary:
    //      A button that shows a popup.
    //      Supply label and popup as parameter when instantiating this widget.

    label: null,
    orient: {'BL': 'TL', 'BR': 'TR'}, // see http://api.dojotoolkit.org/jsdoc/1.3.2/dijit.popup.__OpenArgs (orient)
    templateString: "<a  href='#' class='button enabled' dojoAttachEvent='onclick: openPopup' onClick='return false;' ><span dojoAttachPoint='labelNode'></span></a>",
    disabled: false,
    attributeMap: {
        label: {
            node: "labelNode",
            type: "innerHTML"
        }
    },

    openPopup: function(){
        if (this.disabled) return;
        var self = this;

        dijit.popup.open({
            popup: this.popup,
            parent: this,
            around: this.domNode,
            orient: this.orient,
            onCancel: function(){
                console.log(self.id + ": cancel of child");
            },
            onExecute: function(){
                console.log(self.id + ": execute of child");
                dijit.popup.close(self.popup);
                self.open = false;
            }
        });

        this.open = true;
    },

    closePopup: function(){
        if(this.open){
            console.log(this.id + ": close popup due to blur");
            dijit.popup.close(this.popup);
            this.open = false;
        }
    },

    toggleDisabled: function() {
        this.disabled = !this.disabled
        dojo.toggleClass(this.domNode, 'buttonDisabled');
        dojo.toggleClass(this.domNode, 'enabled');
        dojo.attr(this.domNode, 'disabled', this.disabled);
    },

    _onBlur: function(){
        // summary:
        //      This is called from focus manager and when we get the signal we
        //      need to close the drop down
        //      (note: I don't fully understand where this comes from
        //      I couldn't find docs. Got the code from this example:
        //      http://archive.dojotoolkit.org/nightly/dojotoolkit/dijit/tests/_base/test_popup.html
        this.closePopup();
    }
});

// create some menus & triggers and put them on the page
dojo.addOnLoad(function(){
    // MENU
    cMenu = new dijit.Menu();
    cMenu.addChild(new dijit.MenuItem({ label: "First Item" }));
    cMenu.addChild(new dijit.MenuItem({ label: "Second Item" }));
    cMenu.addChild(new dijit.MenuItem({ label: "Third Item" }));
    cMenu.addChild(new dijit.MenuItem({ label: "Fourth Item is truly a really, really, really long item" }));

    // TRIGGER
    cTrigger = new my.MenuTrigger({
        id: "cTrigger",
        popup: cMenu
    }).placeAt(dojo.body());
    cTrigger = new my.MenuTrigger({
        id: "cTrigger2",
        popup: cMenu
    }).placeAt(dojo.byId('contextTriggerContainer2'));
 });

答案 2 :(得分:0)

正如我从dijit.Menu源代码中看到的那样,您不需要支持您想要的功能 我能想到的是声明一个继承自dijit.Menu并覆盖bindDomNode方法的新小部件。它将_openMyself处理程序绑定到onClick事件,如下所示:

dojo.connect(cn, (this.leftClickToOpen)?"onclick":"oncontextmenu", this, "_openMyself")

_openMyself处理程序从作为参数出现的事件对象中获取coords 因此,我们的想法是使用所需的坐标传递一个伪造的事件对象。

dojo.connect(cn, (this.leftClickToOpen)?"onclick":"oncontextmenu", this, function(){
  var e = { target: desiredTarget, pageX: desiredX, pageY: desiredY };
  this._openMyself(e);
});