根据索引,如何将Css类添加到Ember的{{#each}}循环中的项目? - Ember.js [英] How to add Css Class to item inside Ember's {{#each}} loop, according to index? - Ember.js
问题描述
html中的菜单项基于Ember的{{each}}循环。
当用户选择一个菜单项时,我想添加这个项目活动类。
如何在Ember的{{each}
根据控制器的条件
Html / Hbs:
code>< UL>
{{#each menuItem in sideMenuItems}}
< li {{bind-attr class =isActive:active-class}} {{action'selectMenuItem'_view.contentIndex}}>
{{menuItem.text}}
< / li>
{{/ each}}
< / ul>
控制器:
code> Ember.ObjectController.extend({
selectedMenuIndex:0,
isActive:function(){
return(this.get('selectedMenuIndex')==??? ;
} .property('???'),
actions:{
selectMenuItem:function(itemIndex){
this.set('selectedMenuIndex' itemIndex);
}
}
})
当用户选择菜单项时,我想添加这个项目活动类。
由于您使用的是Ember 1.5,我将首先向您展示一些旧版本的方法。
最简单的方法是添加标题 isActive
到项目本身,并将其用作css类的条件。您可以为 selectMenuItem
操作中的点击项目设置标志为 true
。如果您的逻辑仅允许单个项目一次处于活动状态,则还必须将任何当前活动的项目的 isActive
标志重置为 false
。
{{#sideMenuItems中的每个菜单项}}
< li {{bind-attr class =menuItem。 isActive:active-class}} {{action'selectMenuItem'_view.contentIndex}}>
{{menuItem.text}}
< / li>
{{/ each}}
控制器:
Ember.ObjectController.extend({
sideMenuItems:// ...您的数组项,每个都包含一个isActive标志
actions:{
selectMenuItem:function(itemIndex){
var items = this.get('sideMenuItems');
items.forEach(function(item,idx){ //通过项目
if(idx === itemIndex){//找到点击的项目并将其设置为活动
Ember.set(item,'isActive',true);
} else {//重置所有其他项目
Ember.set(item,'isActive',false);
}
});
}
}
})
更有效的方法是将当前活动的项目作为单独的变量,这将消除需要迭代 sideMenuItems
数组两次:
Con troller:
Ember.ObjectController.extend({
sideMenuItems:// ...你的数组的项目,每个都包含一个isActive标志
activeMenuItem:null,
actions:{
selectMenuItem:function(itemIndex){
var items = this.get(' sideMenuItems');
var currActive = this.get('activeMenuItem');
var nextActive = items.objectAt(itemIndex);
//如果有一个当前活动的项目,停用它
if(currActive){
Ember.set(currActive,'isActive',false);
}
//如果用户点击当前活动的项目,我们只需重置所选项目
//否则我们更新点击的项目的isActive标志
if(currActive === nextActive){
nextActive = null;
} else {
Ember.set(nextActive,'isActive',true);
}
//将点击的项目设置为当前活动的菜单项
this.set('activeMenuItem',nextActive);
}
})
另一种方法是创建一个自定义组件菜单项
,它呈现您的 li
项目带有/不带类取决于活动索引。
Ember.Component.extend({
//传入
activeIndex:-1,
index:-1,
selectMenuItemAction:'',
// local
tagName:'li',
classNameBindings:['activeClass'],
activeClass:function(){
var idx = this.get('index');
var activeIdx = this.get 'activeIndex');
//如果当前项是活动索引,返回活动类
if(idx === activeIdx){
return'active-class ';
}
//否则返回没有类
return'';
} .property('activeIndex')
操作:{
selectMenuItem:f unction(){
this.sendAction('selectMenuItemAction',this.get('index'));
}
}
})
然后使用它:
{{#sideMenuItems中的每个菜单项}}
{{#menu-item index = _view.contentIndex activeIndex = selectedMenuIndex selectMenuItemAction =selectMenuItem}}
{{menuItem.text}}
{{/ menu-item}}
{{/ each}}
控制器:
Ember.ObjectController .extend({
selectedMenuIndex:0,
actions:{
selectMenuItem:function(itemIndex){
this.set('selectedMenuIndex',itemIndex);
}
}
})
由于使用 _view.contentIndex
是一种黑客,您只需传递实际的菜单项,并比较对象引用而不是索引来确定活动项目:
菜单项组件:
Ember.Component。 extend({
// $ in
activeItem:null,
item:null,
selectMenuItemAction:'',
// local
tagName:'li',
classNameBindings:[' activeClass'],
activeClass:function(){
var item = this.get('item');
var activeItem = this.get('activeItem');
//如果当前项是活动项,返回活动类
if(item === activeItem){
return'active-class';
}
//否则返回没有类
return'';
} .property('activeItem')
动作:{
selectMenuItem:function(){
this.sendAction('selectMenuItemAction',this.get项目'));
}
}
})
然后使用它:
{{#sideMenuItems中的每个菜单项}}
{{#menu-item item = menuItem activeItem = selectedMenuItem selectMenuItemAction =selectMenuItem}}
{{menuItem.text}}
{{/ menu-item}}
{{/ each}}
Ember.ObjectController.extend ({
selectedMenuItem:null,
actions:{
selectMenuItem:function(item){
this.set('selectedMenuItem',item);
}
}
})
这是一个更简单的方法在Ember> 1.13
Ember> 1.13支持内联助手,所以你可以很好地实现这一点。 Ember CLI 1.13还附带 babel ,因此我们可以使用ES6,进一步简化:
控制器:
Ember.Controller.extend({
selectedMenuIndex:0,
menuItems:// ...
actions:{
selectMenuItem(itemIndex){
this.set('selectedMenuIndex',itemIndex);
}
}
});
模板:
code> {{#each menuItems as | item index |}}
< li class ={{active-class index selectedMenuIndex}}{{actionselectMenuItemindex}}>
{{item.text}}
< / li>
{{/ each}}
助手:
activeClass(params){
const [index,active] = params; //使用ES6解构
return(index === active)? 'active-class':'';
}
I have a Ember app with side-menu. The menu items in the html are based on Ember's {{each}} loop. When user select a menu-item I want to add this item active class.
How do I add css class to single item inside Ember's {{each}} According to condition from the controller.
Html/Hbs:
<ul> {{#each menuItem in sideMenuItems}} <li {{bind-attr class="isActive: active-class"}} {{ action 'selectMenuItem' _view.contentIndex }}> {{ menuItem.text }} </li> {{/each}} </ul>
Controller:
Ember.ObjectController.extend({ selectedMenuIndex: 0, isActive: function() { return (this.get('selectedMenuIndex') == ? ? ? ); }.property('???'), actions: { selectMenuItem: function(itemIndex) { this.set('selectedMenuIndex', itemIndex); } } })
解决方案When user select a menu-item I want to add this item active class.
Since you are using Ember 1.5, I will first show you a few ways to achieve this for older versions.
The easiest way to do this is to add a flag
isActive
to the item itself, and use that as the condition for the css class. You can set the flag totrue
for the clicked item in yourselectMenuItem
action. If your logic allows only a single item to be active at a time, you must also reset any currently active item'sisActive
flags tofalse
.{{#each menuItem in sideMenuItems}} <li {{bind-attr class="menuItem.isActive:active-class"}} {{action 'selectMenuItem' _view.contentIndex}}> {{menuItem.text}} </li> {{/each}}
Controller:
Ember.ObjectController.extend({ sideMenuItems: // ... your array of items, each containing an isActive flag actions: { selectMenuItem: function(itemIndex) { var items = this.get('sideMenuItems'); items.forEach(function(item, idx) { // go through the items, if(idx === itemIndex) { // find the clicked item and set it as active Ember.set(item, 'isActive', true); } else { // reset all other items Ember.set(item, 'isActive', false); } }); } } })
A more efficient way would be to store the currently active item as a separate variable, this will remove the need to iterate the
sideMenuItems
array twice:Controller:
Ember.ObjectController.extend({ sideMenuItems: // ... your array of items, each containing an isActive flag activeMenuItem: null, actions: { selectMenuItem: function(itemIndex) { var items = this.get('sideMenuItems'); var currActive = this.get('activeMenuItem'); var nextActive = items.objectAt(itemIndex); // if there is a currently active item, deactivate it if(currActive) { Ember.set(currActive, 'isActive', false); } // if the user clicked on the currently active item, we just reset the selected item // otherwise we update the isActive flag for the clicked item if(currActive === nextActive) { nextActive = null; } else { Ember.set(nextActive, 'isActive', true); } // set the clicked item as the currently active menu item this.set('activeMenuItem', nextActive); } })
Another way would be to create a custom component
menu-item
that renders yourli
item with/without a class depending on the active index.Ember.Component.extend({ // passed in activeIndex: -1, index: -1, selectMenuItemAction: '', // local tagName: 'li', classNameBindings: ['activeClass'], activeClass: function() { var idx = this.get('index'); var activeIdx = this.get('activeIndex'); // if the current item is the active index, return the active class if(idx === activeIdx) { return 'active-class'; } // otherwise return no class return ''; }.property('activeIndex') actions: { selectMenuItem: function() { this.sendAction('selectMenuItemAction', this.get('index')); } } })
And then use it like:
{{#each menuItem in sideMenuItems}} {{#menu-item index=_view.contentIndex activeIndex=selectedMenuIndex selectMenuItemAction="selectMenuItem"}} {{menuItem.text}} {{/menu-item}} {{/each}}
Controller:
Ember.ObjectController.extend({ selectedMenuIndex: 0, actions: { selectMenuItem: function(itemIndex) { this.set('selectedMenuIndex', itemIndex); } } })
Since using
_view.contentIndex
is sort of a hack, you can just pass the actual menu item instead and compare the object references instead of indexes to determine the active item:Menu item component:
Ember.Component.extend({ // passed in activeItem: null, item: null, selectMenuItemAction: '', // local tagName: 'li', classNameBindings: ['activeClass'], activeClass: function() { var item = this.get('item'); var activeItem = this.get('activeItem'); // if the current item is the active item, return the active class if(item === activeItem) { return 'active-class'; } // otherwise return no class return ''; }.property('activeItem') actions: { selectMenuItem: function() { this.sendAction('selectMenuItemAction', this.get('item')); } } })
And then use it like:
{{#each menuItem in sideMenuItems}} {{#menu-item item=menuItem activeItem=selectedMenuItem selectMenuItemAction="selectMenuItem"}} {{menuItem.text}} {{/menu-item}} {{/each}}
Controller:
Ember.ObjectController.extend({ selectedMenuItem: null, actions: { selectMenuItem: function(item) { this.set('selectedMenuItem', item); } } })
Here's a much easier way to do this in Ember > 1.13
Ember > 1.13 supports inline helpers so you can achieve this pretty much how you want it. Ember CLI 1.13 also comes with babel so we can use ES6 as well which allows for further simplifications:
Controller:
Ember.Controller.extend({ selectedMenuIndex: 0, menuItems: // ... actions: { selectMenuItem(itemIndex) { this.set('selectedMenuIndex', itemIndex); } } });
Template:
{{#each menuItems as |item index|}} <li class="{{active-class index selectedMenuIndex}}" {{action "selectMenuItem" index}}> {{item.text}} </li> {{/each}}
Helper:
activeClass(params) { const [ index, active ] = params; // use ES6 destructuring return (index === active) ? 'active-class': ''; }
这篇关于根据索引,如何将Css类添加到Ember的{{#each}}循环中的项目? - Ember.js的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!