【问题标题】:Dojo 1.7: BorderContainer and ContentPanes not working inside of a custom widget templateDojo 1.7:BorderContainer 和 ContentPanes 在自定义小部件模板中不起作用
【发布时间】:2011-12-16 10:52:44
【问题描述】:

这类似于这里已经存在的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>

【问题讨论】:

    标签: dojo


    【解决方案1】:

    我正在创建我的模板化自定义小部件,其中包含 BorderContainers 和周围的 div(因为我无法让顶级 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 的回答)我需要将任何来自 dijit 的 resize 调用转发到“内部”边界容器。所以我所做的是在我的小部件中实现resize 方法("bc" 是 BorderContainer 小部件,通过data-dojo-attach-point 引入,如上面的代码所示):

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

    你瞧:一切正常。

    (我使用的是 dojo 1.9,但这应该适用于 dojo >= 1.7)

    【讨论】:

    • 嗨奥利弗,感谢分享。我遇到了同样的问题并尝试了您的解决方案。但是,没有调用我在小部件上创建的调整大小功能。你必须以某种方式连接它,还是继承一个特定的类(我正在继承 _WidgetBase、_TemplatedMixin、_WidgetsInTemplateMixin)。谢谢!
    • @Simon:抱歉,回复晚了……但不,我也只是继承了 _WidgetBase、_TemplatedMixin 和 _WidgetsInTemplateMixin。你startup()你的小部件了吗?
    【解决方案2】:

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

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

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

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

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

    顺便说一句,我使用的是 1.8.3。

    【讨论】:

      【解决方案3】:

      子类化 BorderContainer 而不是 _Widget 作为suggested by skython 似乎可以解决大多数问题。最初绘制小部件时,仍然存在一些小故障,例如未绘制某些边框,因此我通过startup() 方法在子小部件上调用了resize()。注意立即从启动方法调用 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);
      },
      

      【讨论】:

        【解决方案4】:

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

        【讨论】:

        • 优秀 - 如果它是一个模板化的小部件,它可能是您从模板的顶部元素继承的规则,以便它会做出相应的反应。
        • @unludo 你是怎么做到的?
        【解决方案5】:

        小部件的构造和布局在 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】:

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

          // 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;
              }
            };
          }); 
          

          【讨论】:

          • 你检查@skython 的答案了吗?它适用于我的模板小部件,它是 überkool :)
          【解决方案7】:

          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 部分完成的(因此调整大小最初不起作用)

          您可以尝试在这里切换顺序,但我认为最好完全删除启动方法并将 main 更改为

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

          【讨论】:

          • 抱歉延迟回复。我一直无法回应。无论如何,您的提示很有帮助,但它仍然不起作用。我将编辑我上面的帖子。 Dojo 正在渲染小部件,但它们完全没有格式化。
          • +1 感谢您的回复missingno。我想出了一个办法并在这里发布。
          【解决方案8】:

          您可能需要在自己的 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 所提到的,您可能不希望在小部件启动期间清空&lt;body&gt; 并替换它,作为一般可重用性的事情。

          【讨论】:

          • 嗨,布法罗,很抱歉延迟回复。我通常不会花那么长时间来回复。 Dojo 正在渲染小部件,但它们看起来不一样。我将编辑我的原始帖子。
          • +1 以获得有用的回复。我在 dojo 网站上阅读了一个 dojo 贡献者的帖子,他说使用小部件模板创建布局不是完成的事情,而且效果不佳。可悲的是,他没有说什么是正确的方式,所以我以编程方式创建了布局,它醒了。种。
          猜你喜欢
          • 2011-03-07
          • 2014-07-27
          • 1970-01-01
          • 2012-03-07
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-12-15
          • 1970-01-01
          相关资源
          最近更新 更多