简体   繁体   English

在父模板外部渲染ember组件

[英]Rendering ember component outside parent template

Imagine the following situation. 想象一下以下情况。 I have a sidebar positioned absolutely and then some more stuff positioned absolutely within that sidebar. 我有一个绝对定位的侧边栏,然后在侧边栏中放置了一些更多的东西。 In that sidebar I have a button, which shows a menu, the template looks like this: 在那个侧边栏我有一个按钮,显示一个菜单,模板看起来像这样:

<button>Click me</button>
{{#if shouldDisplayMenu}}
    {{view App.MyMenu}}
{{/if}}

What I like about this solution and want to keep is that the menu in the template is defined right next to the button, making for nice maintainability. 我喜欢这个解决方案并希望保留的是模板中的菜单是在按钮旁边定义的,因此具有良好的可维护性。

The problem is that I want the menu to be positioned relative to the viewport, ie rendered to document.body and positioned using position absolute. 问题是我希望菜单相对于视口定位,即渲染到document.body并使用position绝对定位。 This way it will render into the sidebar and cause a scrollbar to be visible because I have already reset positioning context via position relative in one of the parent elements. 这样它将呈现到侧边栏并导致滚动条可见,因为我已经通过其中一个父元素中的位置相对重置了定位上下文。

Is there any way I can keep {{view App.MyMenu}} where it is now, but have it render to body (perhaps using outlets or some other mechanism)? 有什么方法可以保持{{view App.MyMenu}}现在的位置,但让它呈现给身体(可能使用插座或其他机制)? What is the recommended pattern for a situation like this? 这种情况的推荐模式是什么?

There are plenty of ways to render views in ember with related context. 有很多方法可以在具有相关上下文的ember呈现视图。 I present four approaches (i think the first is more likely what you are looking for) : 我提出了四种方法(我认为第一种方法更可能是你想要的)

1. If the view is required to be placed somewhere out of a handlebars template, it is possible to use jQuery to place the rendered content wherever it is required to be. 1.如果需要将视图放置在把手模板之外的某个位置,则可以使用jQuery将呈现的内容放置在需要的位置。

(since the replacement of the view element is happening after didInsertElement it is probably required to also add styles to not show the element eg display:none , and show it after it has been repositioned) (因为在didInsertElement之后更换视图元素,可能还需要添加样式以不显示元素,例如display:none ,并在重新定位后显示它)

Example http://emberjs.jsbin.com/gotabore/1/edit 示例 http://emberjs.jsbin.com/gotabore/1/edit

2. Use {{render}} helper to render the view in place if that place is somewhere in another template. 2.如果该位置位于另一个模板中的某个位置,请使用{{render}}帮助器将视图渲染到位。 Although i'm not certain about the context requirements, this helper is pretty flexible ( http://emberjs.com/guides/templates/rendering-with-helpers/#toc_the-code-render-code-helper ). 虽然我不确定上下文要求,但这个帮助器非常灵活( http://emberjs.com/guides/templates/rendering-with-helpers/#toc_the-code-render-code-helper )。

Example http://emberjs.jsbin.com/xibayava/1/edit 示例 http://emberjs.jsbin.com/xibayava/1/edit

3. Use {{outlet}} helper to render the view based on what is specified within the visited route . 3.使用{{outlet}}帮助程序根据访问route指定的内容呈现视图。 ( http://emberjs.com/guides/routing/rendering-a-template/ ) http://emberjs.com/guides/routing/rendering-a-template/

Example http://emberjs.jsbin.com/tiyuqenu/1/edit 示例 http://emberjs.jsbin.com/tiyuqenu/1/edit

4. Use a ContainerView to push a view programmatically anywhere it is required to be. 4.使用ContainerView以编程方式将视图推送到任何需要的位置。

Example http://emberjs.jsbin.com/yoyujeqi/1/edit 示例 http://emberjs.jsbin.com/yoyujeqi/1/edit


UPDATE for approach 4: for versions equal or greater than 1.8.x , to avoid the error mentioned in http://emberjs.com/guides/deprecations/#toc_global-lookup-of-views , it is possible to specify a property associated to the ContainerView as shown in the following example 方法4的更新: 对于等于或大于1.8.x的版本,为了避免http://emberjs.com/guides/deprecations/#toc_global-lookup-of-views中提到的错误,可以指定关联的属性到ContainerView ,如下例所示

http://emberjs.jsbin.com/difayakeki/1/edit?html,js,output http://emberjs.jsbin.com/difayakeki/1/edit?html,js,output


related code 相关代码

approach 1 方法1

hbs HBS

<script type="text/x-handlebars">
    <h2> Welcome to Ember.js</h2>

    {{outlet}}
  </script>

  <script type="text/x-handlebars" data-template-name="index">
    This is index<br/>
    {{view App.TestView}}
  </script>
  <script type="text/x-handlebars" data-template-name="test">
    This is the test view<br/>
    <b>{{myProp}}</b>
  </script>

  <div id="a-div" style="background-color:lightgray">
    This is a div somewhere,<br/>
  </div>

js JS

App = Ember.Application.create();

App.Router.map(function() {
  // put your routes here
});

App.IndexController = Ember.Controller.extend({
  myProp:"index controller prop"
});

App.IndexView = Ember.View.extend({
  placeTestViewSomewhere:function(){

    var theTestView = this.$(".my-test-view").detach();
    $("#a-div").append(theTestView);

  }.on("didInsertElement")
});

App.TestView = Ember.View.extend({
  templateName:"test",
  classNames:["my-test-view"]
});

approach 2 方法2

hbs HBS

<script type="text/x-handlebars">
    <h2> Welcome to Ember.js</h2>

    {{outlet}}
  </script>

  <script type="text/x-handlebars" data-template-name="index">
    This is index<br/>

    <div style="background-color:lightgray">
    This is a div in index template with render helper,<br/>
    {{render "test"}}
  </div>
  </script>
  <script type="text/x-handlebars" data-template-name="test">
    This is the test view<br/>
    <b>{{myProp}}</b>
  </script>

js JS

App.IndexView = Ember.View.extend({
  placeTestViewSomewhere:function(){

//     var theTestView = this.$(".my-test-view").detach();
//     $("#a-div").append(theTestView);

  }.on("didInsertElement")
});

App.TestController = Ember.Controller.extend({
  myProp:"test controller prop"
});

App.TestView = Ember.View.extend({
  templateName:"test"
});

approach 3 方法3

hbs HBS

<script type="text/x-handlebars">
    <h2> Welcome to Ember.js</h2>

    {{outlet}}
    <div style="background-color:lightgray">
    This is a div in application template with outlet helper,<br/>
    {{outlet "test-outlet"}}
  </div>
  </script>

  <script type="text/x-handlebars" data-template-name="index">
    This is index<br/>

  </script>
  <script type="text/x-handlebars" data-template-name="test">
    This is the test view<br/>
    <b>{{myProp}}</b>
  </script>

js JS

App.IndexRoute = Ember.Route.extend({
  renderTemplate: function() {
    this.render("index");
    this.render('test', {   // the template to render
      into: 'application',                // the template to render into
      outlet: 'test-outlet'             // the name of the outlet in that template
    });
  }
});

App.IndexView = Ember.View.extend({
  placeTestViewSomewhere:function(){

//     var theTestView = this.$(".my-test-view").detach();
//     $("#a-div").append(theTestView);

  }.on("didInsertElement")
});

App.TestController = Ember.Controller.extend({
  myProp:"test controller prop"
});

App.TestView = Ember.View.extend({
  templateName:"test"
});

approach 4 方法4

hbs HBS

<script type="text/x-handlebars">
    <h2> Welcome to Ember.js</h2>

    {{outlet}}
    <div style="background-color:lightgray">
    This is a div in application template with view helper and a view container,<br/>
    {{view Ember.ContainerView viewName="my-menu-container"}}
  </div>

  </div>
  </script>

  <script type="text/x-handlebars" data-template-name="index">
    This is index<br/>
  </script>
  <script type="text/x-handlebars" data-template-name="test">
    This is the test view<br/>
    <b>{{myProp}}</b>
  </script>

js JS

App.IndexController = Ember.Controller.extend({
  myProp:"index controller prop"
});

App.IndexView = Ember.View.extend({
  placeTestViewSomewhere:function(){

    var theTestView = App.TestView.create({});
    theTestView.set("context",this.get("context"));
    this.get("parentView.my-menu-container").pushObject(theTestView);

  }.on("didInsertElement")
});


App.TestView = Ember.View.extend({
  templateName:"test"
});

UPDATE for approach 4: 方法4的更新:

js JS

App.ApplicationView = Em.View.extend({
  containerView:Em.ContainerView
});

hbs HBS

{{view view.containerView viewName="my-menu-container"}}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM