代码之家  ›  专栏  ›  技术社区  ›  David Hicks

Dojo中的事件处理

  •  1
  • David Hicks  · 技术社区  · 18 年前

    带Jeff Atwood的 advice 我决定为我正在编写的非常基本的待办事项列表应用程序使用一个JavaScript库。我选择了 Dojo toolkit ,版本1.1.1。首先,一切都很好:我第一次编写的拖放代码工作正常,您可以在屏幕上拖动任务来更改它们的优先级顺序,并且每个拖放操作都调用一个事件处理程序,该事件处理程序向服务器发送一个Ajax调用,让服务器知道顺序已更改。

    然后我去添加电子邮件跟踪功能。标准资料:新收到的电子邮件在其主题行上有一个唯一的ID号,当您回复时,只需将该ID号留在主题中,就可以跟踪有关该问题的所有后续电子邮件。因此,我们有一个打开的任务列表,每个任务都有自己的ID号,并且每个任务都有一个相关电子邮件的时间顺序列表。我希望这些电子邮件的文本在用户查看任务列表时可供使用,因此我将每个任务框设置为dijit“树”控件-顶层包含任务描述,分支包含电子邮件日期,每个分支的单个“叶”包含电子邮件文本。

    第一个问题:默认情况下,我希望树视图完全折叠。在对Google进行了大量搜索之后,我发现了许多解决方案,所有这些方案似乎对Dojo的早期版本都有效,但对我使用的版本无效。我最终发现,最好的解决方案似乎是在加载树控件时调用一个事件处理程序,它只是折叠每个分支/叶。不幸的是,尽管树控件已经被实例化并且调用了它的“Startup”事件处理程序,但是分支和叶仍然没有加载(数据仍然通过Ajax调用加载)。所以,我修改了系统,以便所有电子邮件文本和树结构都添加到服务器端。这意味着当调用其启动事件处理程序时,整个完全填充的树控件都可用。

    因此,启动事件处理程序完全折叠树。接下来,我找不到一个“合适”的方法来为电子邮件的叶子设置好的文本格式。我可以将电子邮件文本放在叶中,但任何HTML都会被转义出来并显示在网页中。提示更多的是搜索Dojo的文档(往往是过时的,带有1.0之前版本的代码和示例)和Google。我最终想出了一个解决方案,让javascript去读取每个叶节点内的SPAN元素,并取消对其内部转义的HTML代码的转义。我想我应该在树控件的启动事件处理程序中使用代码来完全折叠树代码。

    然而。。。结果是,直到用户单击expando(在树视图中单击以展开节点的小“+”符号)之后,才实际创建span元素。好的,够公平的了-我将把重新格式化的代码添加到onexpand()事件处理程序中,或者它调用的任何东西中。似乎不存在。我搜索过文档,搜索过谷歌…我很可能误解了Dojo的“发布/订阅”事件处理系统,但我认为这主要是因为在任何地方似乎都没有关于它的全面文档(比如,我在哪里可以找到我可以订阅的事件?).

    因此,最后,我能想到的最好的解决方案是向每个树分支的expando节点添加onclick事件处理程序(不是“dojo”事件,而是dojo不知道的普通javascript事件),该节点在每个叶的SPAN元素中重新格式化HTML。除了…调用该元素时,SPAN元素仍然不存在(有时——有时缓存该元素,只是为了进一步混淆您)。因此,我让事件处理程序设置一个计时器,该计时器定期调用一个函数,检查相关的SPAN元素是否已经出现,然后重新格式化它。

    // An event handler called whenever a "email title" tree node is expanded.
    function formatTreeNode(nodeID) {
        if (dijit.byId(nodeID).getChildren().length != 0) {
            clearInterval(nodeUpdateIntervalID);
            messageBody = dijit.byId(nodeID).getChildren()[0].labelNode.innerHTML
            if (messageBody.indexOf("<b>Message text:</b>") == -1) {
                messageBody = messageBody.replace(/&gt;/g, ">");
                messageBody = messageBody.replace(/&lt;/g, "<");
                messageBody = messageBody.replace(/&amp;/g, "&");
                dijit.byId(nodeID).getChildren()[0].labelNode.innerHTML = "<b>Message text:</b><div style=\"font-family:courier\">"+messageBody+"</div>";
            }
        }
    }
    
    // An event handler called when a tree node has been set up - we changed the default fully-expanded to fully-collapsed.
    function setupTree(theTree) {
        dijit.byId("tree-"+theTree).rootNode.collapse();
    
        messageNode = dijit.byId("tree-"+theTree).rootNode.getChildren();
        for (pl = 0; pl < messageNode.length; pl++) {
            messageNode[pl].collapse();
            messageNode[pl].expandoNode.onclick = eval("nodeUpdateIntervalID = setInterval(\"formatTreeNode('"+messageNode[pl].id+"')\",200); formatTreeNode('"+messageNode[pl].id+"');");
        }
    }
    

    上面有一种真正可怕的黑客的感觉,我确信我在思维过程的早期某个地方一定走错了方向。有人能告诉我:

    • 将格式良好的文本放入Dojo/Dijit树控件的正确方法。
    • 处理Dojo事件的正确方法,比如我可以在哪里找到可供我订阅的事件。
    • 一个更好的javascript库来使用(我能用jquery做我想做的事情,避免上面看到的“全方位房屋”方法吗?).

    附言:如果你要给一个软件项目命名,请考虑一下它在谷歌中的独特性——我相信在谷歌中搜索“Dojo”文档会更容易,没有所有的武术结果阻碍。

    PPS:火狐拼写检查器知道如何拼写“阿特伍德”,当我把两个“T”而不是一个“T”的时候纠正我。杰夫现在就是那么有名吗?

    1 回复  |  直到 7 年前
        1
  •  3
  •   Brian Matthews    18 年前

    我想你是按照 dijit.Tree and dojo.data in Dojo 1.1 指导您使用数据存储将数据传递到树控件的教程。那让我在砖墙上敲了一会儿头。

    这并不是一个很好的方法,替代方法也没有很好的记录。您需要创建一个使用模型。我在下面提供了一个树模型的示例,它是我为显示LDAP目录的结构而创建的。

    您将在dojo发行版中的/dijit/_tree/model.js中找到该模型的默认实现。这些注释应该帮助您理解模型支持的功能。

    下面的IdTrimyService类是用于生成的服务器端Java POJOS的存根 Direct Web Remoting (DWR)。如果要进行大量的客户机-服务器交互,我强烈推荐DWR。

    dojo.declare("LDAPDirectoryTreeModel", [ dijit.tree.model ], {
        getRoot : function(onItem) {
            IDirectoryService.getRoots( function(roots) {
                onItem(roots[0])
            });
        },
    
        mayHaveChildren : function(item) {
            return true;
        },
    
        getChildren : function(parentItem, onComplete) {
            IDirectoryService.getChildrenImpl(parentItem, onComplete);
        },
    
        getIdentity : function(item) {
            return item.dn;
        },
    
        getLabel : function(item) {
            return item.rdn;
        }
    });
    

    这里是我的JSP页面的一个摘录,我在这里创建了模型并使用它来填充树控件。

    <div
      dojoType="LDAPDirectoryTreeModel"
      jsid="treeModel"
      id="treeModel">
    </div>
    <div
      jsid="tree"
      id="tree"
      dojoType="dijit.Tree" model="treeModel"
      labelAttr="name"
      label="${directory.host}:${directory.port}">
    </div>