DOJO:onClick并不总是在自定义小部件中调用

时间:2015-07-28 13:15:22

标签: events dojo onclick widget

我遇到了Dojo 1.10的问题,需要一些关于如何找出罪魁祸首的建议。我有一个自定义小部件,TaskButton,实现onMouseDown,onMouseUp和onClick方法。这三个都有记录声明。始终会调用onMouseDown和onMouseUp,并在控制台中显示正确的时间及其日志语句。但是,尽管反复单击TaskButton,有时仍然无法调用onClick。大多数时候在TaskButton外部点击然后返回它内部使得onClick工作但并非总是如此。当没有调用onClick时,它的日志语句不会显示在控制台中。

TaskButton.js自定义小部件

define([
    "dojo/_base/declare",
    "dojo/_base/event",
    "dojo/_base/lang",
    "dojo/dom-class",
    "dojo/dom-construct",
    "dojo/mouse",
    "dojo/on",
    "dojo/query",
    "dojo/topic",
    "dijit/Menu",
    "dijit/MenuItem",
    "dijit/MenuSeparator",
    "dijit/PopupMenuItem",
    "dijit/popup",
    "dijit/Tooltip",
    "dijit/Tree",
    "dijit/tree/ForestStoreModel",
    "dijit/registry",
    "dijit/form/Button",
    "dijit/_WidgetBase",
    "dijit/_OnDijitClickMixin",
    "dijit/_TemplatedMixin",
    "dijit/_WidgetsInTemplateMixin",
    "dojo/text!./templates/TaskButton.html"
], function(declare, event, lang, domClass, domConstruct, mouse, on, query, topic, Menu, MenuItem, MenuSeparator, PopupMenuItem,
        Popup, Tooltip, Tree, ForestStoreModel, registry, button, _WidgetBase, _OnDijitClickMixin, _TemplatedMixin, _WidgetsInTemplateMixin, template){
    return declare("TaskButton", [_WidgetBase, _OnDijitClickMixin, _TemplatedMixin, _WidgetsInTemplateMixin, Menu], {
      scene:0,
      sceneId:0,
      target:"",
      state:"pending",
      cloudCover: false,
      cloudPercentage: 0,
      targetInterest: false,
      hsv: false,
      previousState:"pending",
      backgroundcolor:"#414141",
      templateString:template,
      baseClass: "TaskButton",
      innerNode:undefined,
      cm:null,
      theTask:null,
      eventHandle:null,

postCreate: function()
{
    // Get a DOM node reference for the root of our widget
    var domNode = this.domNode;
    this.innerNode = domNode.firstChild.nextElementSibling.firstElementChild;

    domClass.replace(this.innerFill, "task"+this.state+"Background", "task"+this.state+"Background");
    if (this.cloudCover && ((this.state === "Ready") || (this.state === "Unassigned"))) {
        domClass.replace(this.innerFill, "task"+"Red"+"Background", "task"+this.state+"Background");
    }
    this.previousState = this.state;
    console.log("getting context menu for Scene-" + this.scene + "ContextMenu");
    cm = registry.byId("Scene-" + this.scene + "ContextMenu");

    this.own(
      on(domNode, "contextmenu", lang.hitch(this, "_showContextMenu"))
    );

    this.inherited(arguments);
},

startup: function()
{
   //Turn off button icons if warranted Must do here after dom nodes built
   if (!this.cloudCover)
   {
     dojo.style(dojo.byId("Scene-"+this.scene+"Cloud"), "display", "none");
   }
   if (!this.targetInterest)
   {
     dojo.style(dojo.byId("Scene-"+this.scene+"Target"), "display", "none");
   }
   if (!this.hsv)
   {
     dojo.style(dojo.byId("Scene-"+this.scene+"HSV"), "display", "none");
   }

   this.inherited(arguments);
},

test: function(sceneId)
{
  console.log("testing");
              if (sceneId != this.scene)
              {
                  domClass.replace("Scene-" + sceneId + "Fill", "taskInnerFill", "taskInnerFillSelected");
              }
},

buildRendering: function()
{
  console.log("buildRendering scene:" + this.scene);
  this.inherited(arguments);
},

//
uninitialize: function()
{
  if (this.eventHandle != null)
  {
    console.log("unsubscribing from event topic");
    eventHandle.remove();
    eventHandle = null;
  }
  this.inherited(arguments);
},

//
_onMenuClick: function(event)
{
  console.log("menu item clicked");
},

_showContextMenu: function(event) {
  console.log("opening context menu for scene:" + this.scene);

  this.inherited(arguments);
},

// This is always called
_onMouseDown: function(e)
{
    var scene = e.currentTarget.attributes["scene"].value;
    if (e.button == 0)
    {
      console.log("mouse left pressed, scene=" + scene + " button=" + e.button);
      domClass.replace("Scene-" + scene + "OuterBorder", "taskOuterBorderPressed", "taskOuterBorder");
    }
    else if (e.button == 2)
    {
      console.log("mouse right pressed, scene=" + scene + " button=" + e.button);
      domClass.replace("Scene-" + scene + "OuterBorder", "taskOuterBorderPressed", "taskOuterBorder");
    }

    this.inherited(arguments);
},

// This is always called
_onMouseUp: function(e)
{
    var scene = e.currentTarget.attributes["scene"].value;
    if (e.button == 0)
    {
      console.log("mouse left released, scene=" + scene + " button=" + e.button);
    }
    else if (e.button == 2)
    {
      console.log("mouse right released, scene=" + scene + " button=" + e.button);
    }
  domClass.replace("Scene-" + this.scene + "OuterBorder", "taskOuterBorder", "taskOuterBorderPressed");
  dijit.hideTooltip(e.currentTarget);
  this.inherited(arguments);
},

//
_onMouseEnter: function(e)
{
    label = "Scene: " + this.scene + "<BR>State: " + this.state + "<BR>Target: " + this.target;
    dijit.showTooltip(label,e.currentTarget);
    dijit.popup.close();
    this.inherited(arguments);
},

//
_onMouseLeave: function(e)
{
  this._onMouseUp("");
  this.inherited(arguments);
  dijit.hideTooltip(e.currentTarget);
},

// This is what is not always called
_onClick: function(e)
{
  var scene = e.currentTarget.attributes["scene"].value;
  console.log("scene " + scene + " clicked");
  this._publishEvent(this.scene, "clicked");
  this.inherited(arguments);
},

//
_onBlur: function(e)
{
  dijit.popup.close();
  this.inherited(arguments);
},

//
_onContextMenu: function(e)
{
    this.inherited(arguments);
    this._publishEvent({"scene":this.scene,"sceneId":this.sceneId}, "clicked");
    dijit.hideTooltip(e.currentTarget);
    var widget = this;
    theNode = "TaskButtonContainer" + widget.scene;
    console.log("mouse right clicked, scene=" + widget.scene + " target: " + e.target + "current target");

                theTask = missionCache.query({"sceneId" : this.scene}).then( function(results) {
                theTask = results;
                if (widget.state === "Unassigned" || widget.state === "Ready") {
                    //The context menu should fire to allow assignment

                    var cb = new dijit.form.ComboBox({style:"width:96%;background-color:#414141;margin-top:4px;margin-bottom:4px;",
                        name:"usersByTask", placeholder:"Assign this task to: ", store:usersContextMenuCB,

                        labelAttr: 'name',
                        searchAttr: 'name',

                        onChange: function(){
                            theTask[0].taskStatus = "Assigned";
                            theTask[0].taskOwner = this.item.userName;
                            missionCache.put(theTask[0]);
                            console.log("nothing");
                            widget.set("state", "Assigned");
                            assignTask(this.item.userName);
                            widget.domNode.classList.remove("Unassigned");
                            widget.domNode.classList.add("Assigned");
                            widget.domNode.setAttribute("dndtype", "Assigned");
                            this.destroy();

                        },
                        onClose: function() { this.destroy();}
                    });
                    cb.toggleDropDown();
                    dijit.popup.open({parent: widget, popup:cb, around:e.target,
                        onClose: function(){
                            dijit.popup.close(cb);
                        }
                    });
                }
                });
},


_publishEvent: function(sceneNumber, eventName)
{
  console.log("publishing " + eventName + " for scene " + sceneNumber);
  topic.publish("TaskButton/tasks", { scene:sceneNumber, task:this, event:eventName });
},

_setStateAttr: function(newState)
{
    if (newState != "")
    {
        console.log("setting state for scene:" + this.scene + " to " + newState);
        this._set("state", newState);
        if (this.innerNode !== undefined)
        {
        domClass.replace(this.innerFill, "task"+newState+"Background", "task"+this.previousState+"Background");
        }
        this.previousState = this.state;
        this.state = newState;
    }
  this.inherited(arguments);
},

_changeTaskState: function(newState)
  {
    require(["dijit/registry"], function(registry) {
      var node = registry.byId(clickedItem);
      if (node !== undefined)
      {
        node.set("state", newState);
        console.log("changed task " + this.clickedItem + " state to " + newState);
      }
    });
  this.inherited(arguments);
  },

  _menuTaskDetails: function(e)
  {
    console.log("do task deatils");
  }

});
})

模板中的所有按钮操作都有附加事件。

TaskButton.html模板:

    <li class="dojoDndItem" dndType="${state}" style="border:none;padding:0" data-dojo-props="scene:${scene}">
<div id="TaskButtonContainer-${scene}" widgetid="TaskButtonContainer-${scene}" class="${baseClass}" data-dojo-attach-point="taskButtonContainer"
     data-dojo-attach-event="onContextMenu:_showContextMenu">
   <div widgetid="Scene-${scene}ContextMenu" data-dojo-type="dijit/Menu" data-dojo-props="contextMenuForWindow:false"
       data-dojo-attach-point="contextMenu" targetNodeIds="Scene-${scene}Fill" style="display: none;">
    <div data-dojo-type="dijit/MenuItem" data-dojo-attach-event="onClick:_menuTaskDetails">
      Task Details
    </div>
  </div>
  <div id="Scene-${scene}OuterBorder" widgetid="Scene-${scene}OuterBorder" class="taskOuterBorder" data-dojo-attach-point="outerBorder" scene="${scene}">
    <div id="Scene-${scene}Fill" class="taskInnerFill task${state}Background" data-dojo-attach-point="innerFill" scene="${scene}"
       data-dojo-attach-event="onMouseDown:_onMouseDown,onMouseUp:_onMouseUp,onDijitClick:_onClick,onMouseEnter:_onMouseEnter,onMouseLeave:_onMouseLeave,onContextMenu:_onContextMenu,onBlur:_onBlur">
      <div id="Scene-${scene}Text" class="taskText" data-dojo-attach-point="text">
            <table style="margin:0;padding:0">
              <tr>
                <td>${scene}</td>
              </tr>
              <tr>
                <td>
                  <img id="Scene-${scene}Cloud" src="img/cloud.png" alt="Cloud cover" height="21" width="21">
                  <img id="Scene-${scene}Target" src="img/target.png" alt="ATR" height="21" width="21">
                  <img id="Scene-${scene}HSV" src="img/HSV.png" alt="HSV" height="21" width="21">
                </td>
              </tr>
            </table>
         </div>
      </div>
    </div>
    </div>
    </li>

我还根据建议清理了代码,并且TaskButton的onClick事件处理程序的行为没有任何变化。

1 个答案:

答案 0 :(得分:0)

嗯, 有多个错误...

  • 您不需要继承_WidgetBase_TemplatedMixin_OnDijitClickMixin,而是Menu
  • Menu应该是Base(所以应该是继承列表中的第一个)
  • 您不应该使用domNode.firstChild.nextElementSibling.firstElementChild,而应该在模板中使用data-dojo-attach-point
  • cm = registry.byId('Scene-' + this.scene + 'ContextMenu');应为this.cm = registry.byId('Scene-' + this.scene + 'ContextMenu');
  • 不应使用
  • dojo命名空间。因此,dojo.style应该替换为dojo/dom-styledomStyle.set(),而dojo.byId应该替换为dojo/domdom.byId()
  • 不应使用
  • dijit命名空间。因此,dijit.hideTooltip应替换为dijit/Tooltip,然后Tooltip.hide()dijit.showTooltip应替换为Tooltip.show(),而dijit.popup.close()应替换为dijit/_base/popup要求popup.close()然后dijit.popup.open()popup.open()应替换为var
  • 方法label 中的_onMouseEnter之前缺少
  • onChange
  • 在您dijit.form.ComboBox assignTask的{​​{1}}中称为非现有方法_changeTaskState
  • dijit/registry方法中您需要_onClick,但它已经可用。所以额外的要求是没用的
  • 可能还有更多,但我不在那里重构您的代码
  • 最后,您的data-dojo-attach-event方法没有附加任何内容。我不了解事件有时会如何执行...但是可以使用define([ 'dojo/_base/declare', 'dojo/_base/event', 'dojo/_base/lang', 'dojo/dom', 'dojo/dom-class', 'dojo/dom-construct', 'dojo/dom-style', 'dojo/mouse', 'dojo/on', 'dojo/query', 'dojo/topic', 'dijit/Menu', 'dijit/MenuItem', 'dijit/MenuSeparator', 'dijit/PopupMenuItem', 'dijit/popup', 'dijit/Tooltip', 'dijit/Tree', 'dijit/tree/ForestStoreModel', 'dijit/registry', 'dijit/_base/popup', 'dijit/form/Button', 'dijit/_WidgetBase', 'dijit/_OnDijitClickMixin', 'dijit/_TemplatedMixin', 'dijit/_WidgetsInTemplateMixin', 'dojo/text!./templates/TaskButton.html' ], function(declare, event, lang, dom, domClass, domConstruct, domStyle, mouse, on, query, topic, Menu, MenuItem, MenuSeparator, PopupMenuItem, Popup, Tooltip, Tree, ForestStoreModel, registry, popup, button, _WidgetBase, _OnDijitClickMixin, _TemplatedMixin, _WidgetsInTemplateMixin, template) { return declare('TaskButton', [Menu, _WidgetsInTemplateMixin], { scene: 0, sceneId: 0, target: '', state: 'pending', cloudCover: false, cloudPercentage: 0, targetInterest: false, hsv: false, previousState: 'pending', backgroundcolor: '#414141', templateString: template, baseClass: 'TaskButton', innerNode: undefined, cm: null, theTask: null, eventHandle: null, postCreate: function() { // Get a DOM node reference for the root of our widget var domNode = this.domNode; this.innerNode = domNode.firstChild.nextElementSibling.firstElementChild; domClass.replace(this.innerFill, 'task' + this.state + 'Background', 'task' + this.state + 'Background'); if (this.cloudCover && ((this.state === 'Ready') || (this.state === 'Unassigned'))) { domClass.replace(this.innerFill, 'task' + 'Red' + 'Background', 'task' + this.state + 'Background'); } this.previousState = this.state; console.log('getting context menu for Scene-' + this.scene + 'ContextMenu'); cm = registry.byId('Scene-' + this.scene + 'ContextMenu'); this.own( on(domNode, 'contextmenu', lang.hitch(this, '_showContextMenu')) ); this.inherited(arguments); }, startup: function() { //Turn off button icons if warranted Must do here after dom nodes built if (!this.cloudCover) { domStyle.set(dom.byId('Scene-' + this.scene + 'Cloud'), 'display', 'none'); } if (!this.targetInterest) { domStyle.set(dom.byId('Scene-' + this.scene + 'Target'), 'display', 'none'); } if (!this.hsv) { domStyle.set(dom.byId('Scene-' + this.scene + 'HSV'), 'display', 'none'); } this.inherited(arguments); }, test: function(sceneId) { console.log('testing'); if (sceneId != this.scene) { domClass.replace('Scene-' + sceneId + 'Fill', 'taskInnerFill', 'taskInnerFillSelected'); } }, buildRendering: function() { console.log('buildRendering scene:' + this.scene); this.inherited(arguments); }, // uninitialize: function() { if (this.eventHandle != null) { console.log('unsubscribing from event topic'); eventHandle.remove(); eventHandle = null; } this.inherited(arguments); }, // _onMenuClick: function(event) { console.log('menu item clicked'); }, _showContextMenu: function(event) { console.log('opening context menu for scene:' + this.scene); this.inherited(arguments); }, // This is always called _onMouseDown: function(e) { var scene = e.currentTarget.attributes['scene'].value; if (e.button == 0) { console.log('mouse left pressed, scene=' + scene + ' button=' + e.button); domClass.replace('Scene-' + scene + 'OuterBorder', 'taskOuterBorderPressed', 'taskOuterBorder'); } else if (e.button == 2) { console.log('mouse right pressed, scene=' + scene + ' button=' + e.button); domClass.replace('Scene-' + scene + 'OuterBorder', 'taskOuterBorderPressed', 'taskOuterBorder'); } this.inherited(arguments); }, // This is always called _onMouseUp: function(e) { var scene = e.currentTarget.attributes['scene'].value; if (e.button == 0) { console.log('mouse left released, scene=' + scene + ' button=' + e.button); } else if(e.button == 2) { console.log('mouse right released, scene=' + scene + ' button=' + e.button); } domClass.replace('Scene-' + this.scene + 'OuterBorder', 'taskOuterBorder', 'taskOuterBorderPressed'); Tooltip.hide(e.currentTarget); this.inherited(arguments); }, // _onMouseEnter: function(e) { var label = 'Scene: ' + this.scene + '<BR>State: ' + this.state + '<BR>Target: ' + this.target; Tooltip.show(label, e.currentTarget); popup.close(); this.inherited(arguments); }, // _onMouseLeave: function(e) { this._onMouseUp(''); this.inherited(arguments); Tooltip.hide(e.currentTarget); }, // This is what is not always called _onClick: function(e) { var scene = e.currentTarget.attributes['scene'].value; console.log('scene ' + scene + ' clicked'); this._publishEvent(this.scene, 'clicked'); this.inherited(arguments); }, // _onBlur: function(e) { popup.close(); this.inherited(arguments); }, // _onContextMenu: function(e) { this.inherited(arguments); this._publishEvent({ 'scene': this.scene, 'sceneId': this.sceneId }, 'clicked'); Tooltip.hide(e.currentTarget); var widget = this; theNode = 'TaskButtonContainer' + widget.scene; console.log('mouse right clicked, scene=' + widget.scene + ' target: ' + e.target + 'current target'); theTask = missionCache.query({ 'sceneId': this.scene }).then(function(results) { theTask = results; if (widget.state === 'Unassigned' || widget.state === 'Ready') { //The context menu should fire to allow assignment var cb = new dijit.form.ComboBox({ style: 'width:96%;background-color:#414141;margin-top:4px;margin-bottom:4px;', name: 'usersByTask', placeholder: 'Assign this task to: ', store: usersContextMenuCB, labelAttr: 'name', searchAttr: 'name', onChange: function() { theTask[0].taskStatus = 'Assigned'; theTask[0].taskOwner = this.item.userName; missionCache.put(theTask[0]); console.log('nothing'); widget.set('state', 'Assigned'); //assignTask(this.item.userName); widget.domNode.classList.remove('Unassigned'); widget.domNode.classList.add('Assigned'); widget.domNode.setAttribute('dndtype', 'Assigned'); this.destroy(); }, onClose: function() { this.destroy(); } }); cb.toggleDropDown(); popup.open({ parent: widget, popup: cb, around: e.target, onClose: function() { popup.close(cb); } }); } }); }, _publishEvent: function(sceneNumber, eventName) { console.log('publishing ' + eventName + ' for scene ' + sceneNumber); topic.publish('TaskButton/tasks', { scene: sceneNumber, task: this, event: eventName }); }, _setStateAttr: function(newState) { if (newState != '') { console.log('setting state for scene:' + this.scene + ' to ' + newState); this._set('state', newState); if (this.innerNode !== undefined) { domClass.replace(this.innerFill, 'task' + newState + 'Background', 'task' + this.previousState + 'Background'); } this.previousState = this.state; this.state = newState; } this.inherited(arguments); }, _changeTaskState: function(newState) { var node = registry.byId(clickedItem); if (node !== undefined) { node.set('state', newState); console.log('changed task ' + this.clickedItem + ' state to ' + newState); } this.inherited(arguments); }, _menuTaskDetails: function(e) { console.log('do task deatils'); } }); }) 进行连接吗?如果是,那么请同时提供您的模板。

尝试应用所有更改来清除一些错误,并查看它是否更好。 如果不是,请分享按钮的模板。

LPAD