javascript 关闭 Backbone.Marionette.ItemView 的 div wrap
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14656068/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Turning off div wrap for Backbone.Marionette.ItemView
提问by mrk
I'm looking at the Angry Cats Backbone/Marionette tutorial posts here
我正在查看 Angry Cats Backbone/Marionette 教程帖子
http://davidsulc.com/blog/2012/04/15/a-simple-backbone-marionette-tutorial/
http://davidsulc.com/blog/2012/04/15/a-simple-backbone-marionette-tutorial/
http://davidsulc.com/blog/2012/04/22/a-simple-backbone-marionette-tutorial-part-2/
http://davidsulc.com/blog/2012/04/22/a-simple-backbone-marionette-tutorial-part-2/
and I came upon the same question/need posted here:
我遇到了同样的问题/需要张贴在这里:
Backbone.js turning off wrap by div in render
But I can only get that to work for Backbone.Views, not Backbone.Marionette.ItemViews.
但我只能让它为 Backbone.Views 工作,而不是 Backbone.Marionette.ItemViews。
For example, from the simple backbone marionette tutorial links above, take AngryCatView:
例如,从上面的简单骨干牵线木偶教程链接,取 AngryCatView:
AngryCatView = Backbone.Marionette.ItemView.extend({
template: "#angry_cat-template",
tagName: 'tr',
className: 'angry_cat',
...
});
The template, #angry_cat-template
, looks like this:
模板#angry_cat-template
看起来像这样:
<script type="text/template" id="angry_cat-template">
<td><%= rank %></td>
<td><%= votes %></td>
<td><%= name %></td>
...
</script>
What I don't like, is that the AngryCatView needs to have
我不喜欢的是 AngryCatView 需要有
tagName: 'tr',
className: 'angry_cat',
-- if I take tagName
out, then angry_cat-template
gets wrapped by a <div>
.
-- 如果我取tagName
出来,angry_cat-template
就会被一个<div>
.
What I would like is to specify the HTML in one place (the angry_cat-template) and not have most HTML (all the <td>
tags) in angry_cat-template and a little HTML (the <tr>
tag) in AngryCatView. I would like to write this in angry_cat-template:
我想要的是在一个地方(anger_cat-template)指定 HTML,并且在anger_cat-template 中没有大多数 HTML(所有<td>
标签),在 AngryCatView 中没有一点 HTML(<tr>
标签)。我想在anger_cat-template中写这个:
<script type="text/template" id="angry_cat-template">
<tr class="angry_cat">
<td><%= rank %></td>
<td><%= votes %></td>
<td><%= name %></td>
...
</tr>
</script>
It just feels cleaner to me but I've been mucking around with Derik Bailey's answer in "Backbone.js turning off wrap by div in render" and can't get it to work for Backbone.Marionette.
它只是让我感觉更干净,但我一直在思考 Derik Bailey 在“Backbone.js 关闭渲染中的 div 包装”中的回答,并且无法让它为 Backbone.Marionette 工作。
Any ideas?
有任何想法吗?
回答by bejonbee
2014/02/18 — updated to accommodate the improvements noted by @vaughan and @Thom-Nichols in the comments
2014/02/18 — 更新以适应@vaughan 和@Thom-Nichols 在评论中指出的改进
In many of my itemView/layouts I do this:
在我的许多 itemView/布局中,我都是这样做的:
var Layout = Backbone.Marionette.Layout.extend({
...
onRender: function () {
// Get rid of that pesky wrapping-div.
// Assumes 1 child element present in template.
this.$el = this.$el.children();
// Unwrap the element to prevent infinitely
// nesting elements during re-render.
this.$el.unwrap();
this.setElement(this.$el);
}
...
});
The above code only works when the wrapper div contains a single element, which is how I design my templates.
上面的代码仅在包装器 div 包含单个元素时才有效,这就是我设计模板的方式。
In your case .children()
will return <tr class="angry_cat">
, so this should work perfect.
在你的情况下.children()
会返回<tr class="angry_cat">
,所以这应该很完美。
I agree, it does keep the templates much cleaner.
我同意,它确实使模板更干净。
One thing to note:
需要注意的一件事:
This technique does not force only 1 child element. It blindly grabs .children()
so if you've incorrectly built the template to return more than one element, like the first template example with 3 <td>
elements, it won't work well.
此技术不会仅强制使用 1 个子元素。它盲目地抓取,.children()
因此如果您错误地构建模板以返回多个元素,例如第一个具有 3 个<td>
元素的模板示例,它将无法正常工作。
It requires your template to return a single element, as you have in the second template with the root <tr>
element.
它要求您的模板返回单个元素,就像您在带有根<tr>
元素的第二个模板中一样。
Of course it could be written to test for this if need be.
当然,如果需要,可以编写它来测试这一点。
Here is a working example for the curious: http://codepen.io/somethingkindawierd/pen/txnpE
回答by Tres
While I'm sure there's a way to hack the internals of render
to get it to behave the way you'd like, taking this approach means you'll be fighting the conventions of Backbone and Marionette through the whole development process. ItemView
needs to have an associated $el
, and by convention, it's a div
unless you specify a tagName
.
虽然我确信有一种方法可以破解 的内部结构render
以使其按照您想要的方式运行,但采用这种方法意味着您将在整个开发过程中与 Backbone 和 Marionette 的约定作斗争。ItemView
需要有一个关联的$el
,按照惯例,div
除非您指定一个tagName
.
I empathize -- especially in the case of Layouts and Regions, it appears to be impossible to stop Backbone from generating an extra element. I'd recommend accepting the convention while you learn the rest of the framework and only then deciding if it's worth hacking render
to behave differently (or to just choose a different framework).
我深有同感——尤其是在布局和区域的情况下,似乎不可能阻止 Backbone 生成额外的元素。我建议您在学习框架的其余部分时接受约定,然后才决定是否值得render
改变行为(或仅选择不同的框架)。
回答by vaughan
This solution works for re-rendering. You need to override render
.
此解决方案适用于重新渲染。您需要覆盖render
.
onRender
tricks won't work for re-render. They will cause nesting on every re-render.
onRender
技巧对重新渲染不起作用。它们会在每次重新渲染时造成嵌套。
BM.ItemView::render = ->
@isClosed = false
@triggerMethod "before:render", this
@triggerMethod "item:before:render", this
data = @serializeData()
data = @mixinTemplateHelpers(data)
template = @getTemplate()
html = Marionette.Renderer.render(template, data)
#@$el.html html
$newEl = $ html
@$el.replaceWith $newEl
@setElement $newEl
@bindUIElements()
@triggerMethod "render", this
@triggerMethod "item:rendered", this
this
回答by Sam Samskies
Wouldn't it be cleaner to use vanilla JS instead of jQuery to accomplish this?
使用 vanilla JS 而不是 jQuery 来完成这个不是更干净吗?
var Layout = Backbone.Marionette.LayoutView.extend({
...
onRender: function () {
this.setElement(this.el.innerHTML);
}
...
});
回答by hqcasanova
For IE9+ you could just use firstElementChildand childElementCount:
对于 IE9+,您可以只使用firstElementChild和childElementCount:
var Layout = Backbone.Marionette.LayoutView.extend({
...
onRender: function () {
if (this.el.childElementCount == 1) {
this.setElement(this.el.firstElementChild);
}
}
...
});
There is a good reason why Marionette automatically inserts the wrapper DIV. It's only when your template consists of just one element when you can drop it. Hence the test for number of child elements.
Marionette 自动插入包装器 DIV 是有充分理由的。只有当您的模板仅包含一个元素时,您才可以删除它。因此测试子元素的数量。
Another option is to use the attachElContentmethod present in every Marionette view. Its default implementation means re-renders of the view will overwrite the root element's inner HTML. This ultimately gives rise to the infinite nesting mentioned in bejonbee's answer.
另一种选择是使用每个 Marionette 视图中存在的attachElContent方法。它的默认实现意味着重新渲染视图将覆盖根元素的内部 HTML。这最终导致了 bejonbee 的回答中提到的无限嵌套。
If you would rather not overwrite onRender and/or require a pure-JS solution, the following code might be just what you want:
如果您不想覆盖 onRender 和/或需要纯 JS 解决方案,以下代码可能正是您想要的:
var Layout = Backbone.Marionette.LayoutView.extend({
...
attachElContent: function (html) {
var parentEl = this.el.parentElement;
var oldEl;
//View already attached to the DOM => re-render case => prevents
//recursive nesting by considering template's top element as the
//view's when re-rendering
if (parentEl) {
oldEl = this.el;
this.setElement(html); //gets new element from parsed html
parentEl.replaceChild(this.el, oldEl); //updates the dom with the new element
return this;
//View hasn't been attached to the DOM yet => first render
// => gets rid of wrapper DIV if only one child
} else {
Marionette.ItemView.prototype.attachElContent.call(this, html);
if (this.el.childElementCount == 1) {
this.setElement(this.el.firstElementChild);
}
return this;
}
}
...
});
Note that for re-rendering to work, the code assumes a template with a single child that contains all markup.
请注意,为了重新渲染工作,代码假定模板具有包含所有标记的单个子项。