Dojo 1.7:BorderContainer和ContentPanes无法在自定义小部件模板中工作

时间:2011-10-27 11:43:56

标签: dojo

这类似于已经在这里的question,但我正在使用Dojo 1.7。所以,我不能让BorderContainer和ContentPanes在自定义小部件模板中工作。这让我很生气。我尝试添加其他帖子中建议的mixins,但它没有用。

所以我有两个例子。第一个是以声明方式使用dojo的单个页面,它工作正常。第二个例子是完全相同的页面,但我使用一个小部件来嵌入模板。它呈现小部件,但它们都在右上角粘在一起。相同的页面,相同的样式。但是,当我调整浏览器窗口的大小时,页面就会成形。仍然有一些缺失,但它更好

非常感谢

这是第一个有效的例子

<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Demo: Application Controller</title>
    <link rel="stylesheet" href="/js/tag/widgets/BorderWidget/css/demo.css" media="screen">
    <link rel="stylesheet" href="/js/tag/widgets/BorderWidget/css/style.css" media="screen">
    <link rel="stylesheet" href="/js/dijit/themes/claro/claro.css" media="screen">

    <!-- Configure Dojo -->
    <script type="text/javascript">
      var djConfig = {
        isDebug : true,
        parseOnLoad : true
      };
    </script>
    <script type="text/javascript" src="/js/dojo/dojo.js"></script>
    <script>
      dojo.require("dijit.layout.BorderContainer");
      dojo.require("dijit.layout.TabContainer");
      dojo.require("dijit.layout.ContentPane");
    </script>
  </head>
  <body class="claro">
    <div style="height:100%">
      <div id="appLayout" class="demoLayout" data-dojo-type="dijit.layout.BorderContainer" data-dojo-props="design: 'headline'">
        <div class="centerPanel" id="tabs" data-dojo-type="dijit.layout.TabContainer" data-dojo-props="region: 'center', tabPosition: 'bottom'">
          <div data-dojo-type="dijit.layout.ContentPane" data-dojo-props="title: 'About'">
            <h2>Flickr keyword photo search</h2>
            <p>
              Each search creates a new tab with the results as thumbnails
            </p>
            <p>
              Click on any thumbnail to view the larger image
            </p>
          </div>
        </div>
        <div class="edgePanel" data-dojo-type="dijit.layout.ContentPane" data-dojo-props="region: 'top'">
          <div class="searchInputColumn">
            <div class="searchInputColumnInner">
              <input id="searchTerms" placeholder="search terms">
            </div>
          </div>
          <div class="searchButtonColumn">
            <button id="searchBtn">
              Search
            </button>
          </div>
        </div>
      </div>
    </div>
  </body>
</html>

这是使用小部件的第二个例子

<!DOCTYPE HTML>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Demo: Application Controller</title>
    <link rel="stylesheet" href="/js/tag/widgets/BorderWidget/css/demo.css" media="screen">
    <link rel="stylesheet" href="/js/tag/widgets/BorderWidget/css/style.css" media="screen">
    <link rel="stylesheet" href="/js/dijit/themes/claro/claro.css" media="screen">

    <!-- Configure Dojo -->
    <script type="text/javascript">
      var djConfig = {
        isDebug : true,
        parseOnLoad : true,
        paths : {
          'tag' : '../tag/widgets/BorderWidget'
        }
      };
    </script>
    <script type="text/javascript" src="/js/dojo/dojo.js"></script>
    <script>
      dojo.require("dijit.layout.BorderContainer");
      dojo.require("dijit.layout.TabContainer");
      dojo.require("dijit.layout.ContentPane");
      dojo.require('tag.Widget');

      dojo.ready(function() {
        new tag.Widget().startup();
      });
    </script>
  </head>
  <body class="claro">

  </body>
</html>

这是小部件代码

define('tag/Widget', 
[
  'dojo', 
  'dijit/_Widget', 
  'dijit/_TemplatedMixin', 
  'dijit/_WidgetsInTemplateMixin',
  'dijit/layout/BorderContainer',
  'dijit/layout/TabContainer',
  'dijit/layout/ContentPane'
], 
function(d) {
  //The widget contructor will be returned
  return d.declare('tag.Widget', 
  [
    dijit._Widget, 
    dijit._TemplatedMixin, 
    dijit._WidgetsInTemplateMixin
  ], 
  {
    templateString : d.cache("tag", "templates/template.html"),

    postCreate : function() {
      this.inherited(arguments);
      var domNode = this.domNode;
    },

    startup : function(args) {
      this.inherited(arguments);
      this.placeAt(dojo.doc.body);
    }


  });
});

这是小部件的模板

<div style="height:100%">
  <div id="appLayout" class="demoLayout" data-dojo-type="dijit.layout.BorderContainer" data-dojo-props="design: 'headline'">
    <div class="centerPanel" id="tabs" data-dojo-type="dijit.layout.TabContainer" data-dojo-props="region: 'center', tabPosition: 'bottom'">
      <div data-dojo-type="dijit.layout.ContentPane" data-dojo-props="title: 'About'">
        <h2>Flickr keyword photo search</h2>
        <p>
          Each search creates a new tab with the results as thumbnails
        </p>
        <p>
          Click on any thumbnail to view the larger image
        </p>
      </div>
    </div>
    <div class="edgePanel" data-dojo-type="dijit.layout.ContentPane" data-dojo-props="region: 'top'">
      <div class="searchInputColumn">
        <div class="searchInputColumnInner">
          <input id="searchTerms" placeholder="search terms">
        </div>
      </div>
      <div class="searchButtonColumn">
        <button id="searchBtn">
          Search
        </button>
      </div>
    </div>
  </div>
</div>

8 个答案:

答案 0 :(得分:4)

您可能需要在自己的startup()方法中显式调用BorderContainer和ContentPane布局小部件上的启动。如果要覆盖和继承方法,您可能希望在任何窗口小部件生命周期方法中始终具有this.inherited(arguments)

startup : function(args) {
    this.inherited(arguments);
    //console.log('asdasd')
    dojo.empty("body");
    this.placeAt('body');

    this.subContainerWidget.startup();
    //I think the border container will automatically call startup on its children 
    //(the content panes), but you may also need to call startup on them.
}

另外,正如@missingno所提到的,你可能不希望清空<body>并在小部件启动期间替换它,作为一般的可重用性。

答案 1 :(得分:4)

我在自定义Widget和BorderContainers中遇到了一个非常类似的问题,它在我继承BorderContainer而不是BaseWidget或_Widget后终于工作了。 希望这也有助于您的情况!

答案 2 :(得分:2)

我正在创建我的模板化自定义小部件,其中包含带有周围div的BorderContainer(因为我无法使顶层BorderContainer工作),如下所示:

<div style="height: 100%;">
<div style="height: 100%;" data-dojo-type="dijit/layout/BorderContainer"
     data-dojo-attach-point="bc"
     data-dojo-props="design: 'headline', gutters: false">
    <div data-dojo-type="dijit/layout/ContentPane"
         data-dojo-props="region: 'top'">
    </div>
    <div data-dojo-type="dijit/layout/ContentPane"
         data-dojo-props="region: 'center'">
    </div>
</div>

我有完全相同的布局问题(BorderContainer只会在页面调整大小后才能正确布局),直到我意识到(感谢上面John Brinnand的答案)我需要转发任何resize来自dijit到“内部”BorderContainer。所以我所做的是在我的小部件中实现resize方法("bc"是BorderContainer小部件,通过data-dojo-attach-point引入,如上面的代码所示):

        resize: function () {
        this.bc.resize(arguments);
        this.inherited(arguments);
    }

瞧瞧:一切正常。

(我正在使用dojo 1.9,但这应该适用于dojo&gt; = 1.7)

答案 3 :(得分:1)

BorderContainer是一个需要大小调整的布局小部件。你已经覆盖了启动方法,我敢打赌这至少是其中一个问题。

由于您的启动方法内容并非真正启动,我建议您尝试删除或重命名它(以显示原始启动)。

d.declare(...)|{
    ...
    toFullScreen: function(){
        dojo.empty("body");
      this.placeAt('body');
    }
}

var w = new FlickApiView({...});
w.toFullScreen();
w.startup();

修改(针对新问题):

我找到了

startup : function(args) {
  this.inherited(arguments);
  this.placeAt(dojo.doc.body);
}

要怀疑,因为所有调整大小都是在实际放置小部件之前在this.inherited部分完成的(因此调整大小最初不起作用)

您可以尝试在此处切换订单,但我认为最好完全删除启动方法并将主要内容更改为

var w  = new tags.Widget();
w.placeAt(dojo.body());
s.startup();

答案 4 :(得分:1)

创建布局的方法不是使用模板化小部件,而是以编程方式执行。我实际上并没有在任何地方找到这个,但我也找不到任何导致我这样做的人;

// view
define('tag/views/CampaignTest/layout', [
  'dojo',
  'dbp/widgetStore',
  'dijit/layout/BorderContainer',
  'dijit/layout/TabContainer',
  'dijit/layout/ContentPane',
  'dojo/NodeList-manipulate'
],

function(dojo, widgetStore, BorderContainer, TabContainer, ContentPane) {
  return {
    create : function (layoutName) {
      var deferred = new dojo.Deferred(),
          add = dojo.partial(widgetStore.add, layoutName);

      dojo.query("body").prepend("<div id='appLayout' class='demoLayout'></div>");

      var appLayout = add(
        new BorderContainer({
          design: "headline"
        }, dojo.byId("appLayout"))
      );


      // create the TabContainer
      var contentTabs = add(
        new dijit.layout.TabContainer({
          region: "center",
          id: "contentTabs",
          tabPosition: "bottom",
          "class": "centerPanel",
          href: "contentCenter.html"
        })
      );

      // add the TabContainer as a child of the BorderContainer
      appLayout.addChild( contentTabs );

      // create and add the BorderContainer edge regions
      appLayout.addChild(
        add(
          new dijit.layout.ContentPane({
            style : "height:50px",
            region: "top",
            id : "top",
            "class": "edgePanel",
            content: "Header content (top)"
          })
        )
      );

      appLayout.addChild(
        add(
          new dijit.layout.ContentPane({
            style : "height:50px",
            region: "top",
            id : "top2",
            "class": "edgePanel",
            content: "Next content (top)"
          })
        )
      );

      appLayout.addChild(
        add(
          new dijit.layout.ContentPane({
              region: "left",
              id: "leftCol",
              "class": "edgePanel",
              content: "Sidebar content (left)",
              splitter: true
          })
        )
      );

      contentTabs.addChild(
        add(
          new dijit.layout.ContentPane({
            title: "Start"
          }, dojo.byId("startContent"))
        )
      );

      // not even sure this is necessary but I
      // check to make sure layout has finished
      (function check(){
        setTimeout(function(){
          appLayout.domNode ? deferred.resolve() : check();
        }, 10);
      })();


      appLayout.startup();

      return deferred;
    }
  };
}); 

答案 5 :(得分:1)

在dojo 1.7中,小部件的构造和布局发生了变化。这有一个固有的顺序:构建一个小部件,将其添加到它的父级,启动,调整大小。在1.7之前,启动小部件的操作顺序是不同的。

在你的例子中:

  • 构造BorderContainer:var bc = new dijit.layout.BorderContainer({...});
  • 将其添加到父级:parent.addChild或parent.appendChild(bc)
  • 启动它:bc.startup();
  • 调整大小:bc.resize();

相同的序列将适用于边框容器的子项:

  • 构建内容窗格:var cp1 = new dijit.layout.ContentPane({...});
  • 将其添加到其父级:bc.addChild(cp1);
  • 启动内容窗格:cp1.startup(); //可能没有必要,但没有伤害
  • 调整内容窗格的大小:cp1.resize(); //可能没有必要,但没有伤害
  • 重启边框容器:bc.startup(); //这很重要。
  • 调整边框容器的大小:bc.resize(); //非常重要:没有它,布局就不会呈现。

启动已启动的容器似乎有点多余。您可以使用此序列来查找有用或不必要的内容。但是,resize()是至关重要的。没有它,布局的大小不正确,也不会渲染。

注意:此示例意味着dojo小部件的编程构造和连接。

答案 6 :(得分:0)

将BorderContainer而不是_Widget子类化为suggested by skython似乎解决了大多数问题。在最初绘制窗口小部件时,有些边缘仍然没有被绘制,所以我在resize()方法的子窗口小部件上调用了startup()。请注意,立即从启动方法调用resize不起作用,但使用setTimeout() 0延迟工作:

startup : function(args) {
    // Hack to force widget to initially draw properly.
    array.forEach(this.getChildren(), function(elem, id) {
        setTimeout(elem.resize, 0);
    });

    this.inherited(arguments);
},

答案 7 :(得分:0)

我挣扎了4个小时,最终让它以声明式和编程式方式工作。关键是你必须在其dom元素就位(可见?)之后调用yourBorderContainerObj.startup()或.resize()。

我试图创建一个模板化的小部件,其中包含BorderContainer和一些ContentPanes,并将其放在Dialog中。首先,当对话框显示时,我无法正确显示BorderContainer和ContentPanes,它们已被初始化并分配了正确的类名,但css效果似乎并未应用。

我通过在小部件中执行此操作来使模板化小部件工作:

resize: function() {
      this.inherited(arguments);
      this.myBorderContainerObj.resize();
}

就是这样。然后BorderContainer和ContentPanes都可以正常工作。

BTW,我使用的是1.8.3。