这对初学者来说是一个简单的问题,但到目前为止我还没有看到符合我需要的解决方案。基本上我得到了一个包含ul
和li
的简单菜单。有2个要求:
要求1:点击其中一个时,li
将获得新的课程.active
。
Req2:菜单项是动态的,这意味着我应该可以添加或删除任何菜单项(通过使用其他按钮)。
2种方式可以做到这一点:
方法1:将每个MenuView转换为MenuItem
我有一个类似这样的MenuView
el: $('li'),
events: {
"click" : "highlight"
},
highlight: function(e) {
thisParent = $(e.target).parent();
thisParent.siblings('.active').removeClass('active');
thisParent.addClass('active');
},
亲:很简单。这就是我现在所拥有的。
Con:依赖于html结构。如果它改为div
而不是多层,该怎么办?
方法2:MenuCollection的一个视图
创建一个MenuItemCollection并使用MenuView代替该集合。 MenuView的el
将为ul
(而不是li
)。 HTML将显示为单独的id
:
<ul>
<li id="leftmenu-one">one</li>
<li id="leftmenu-two">two</li>
<li id="leftmenu-three">three</li>
</ul>
然后当检测到点击事件时,做两件事:
2a。删除.active
ul li
课程
2b。将.active
类添加到e.target
DOM
Pro:解耦html设计
Con:更多代码。
问题:我想大多数人会说方法1 很糟糕。但是有方法3,4,5 ......哪个更好?如何处理添加新菜单项?
答案 0 :(得分:8)
创建菜单项模型
var MenuItem = Backbone.Model.extend({
title: 'Default Title',
isSelected: false
});
和项集合,它将侦听任何模型选择更改事件
var MenuItemCollection = Backbone.Collection.extend({
model: MenuItem,
initialize: function() {
this.on('change:isSelected', this.onSelectedChanged, this);
},
onSelectedChanged: function(model) {
this.each(function(model) {
if (model.get('isSelected') === true && !model.hasChanged('isSelected')) {
model.set({isSelected: false});
}
});
}
});
之后为菜单项
创建一个视图 var MenuItemView = Backbone.View.extend({
tagName: 'li',
events: {
'click' : 'highlight'
},
initialize: function() {
_.bindAll(this);
this.model.on('change:isSelected', this.onSelectedChanged);
},
render: function() {
this.$el.text(this.model.get('title'));
return this;
},
onSelectedChanged: function() {
if (this.model.get('isSelected') === true) {
this.$el.addClass('active');
}
else {
this.$el.removeClass('active');
}
},
highlight: function() {
this.model.set({isSelected: true});
}
});
和菜单本身就像
var MenuView = Backbone.View.extend({
tagName: 'ul',
initialize: function() {
_.bindAll(this);
},
render: function() {
this.collection.each(function(model) {
var item = new MenuItemView({model: model});
this.$el.append(item.render().el);
}, this);
return this;
}
});
完整工作的js在http://jsfiddle.net/Kf3SS/
处提出评论答案 1 :(得分:1)
JSFiddle Demo w/ code comments
您的视图中有一些DOM遍历,您最可能想要避免...因为这个示例非常小,它不会破坏用户体验,但它是最佳实践和所有好东西。
我认为这应该是一个很好的起点/例子。
var MenuView
, MenuItemView
, MenuItemModel
, menu //MenuView Instance
, menuItem //MenuItemView Instance
;
MenuItemModel = Backbone.Model.extend({
'defaults': {
'url': undefined
, 'text': undefined
}
});
MenuView = Backbone.View.extend({
'tagName': 'ul'
, 'id': 'MenuView'
, 'menuItems': []
, 'activeButton': undefined
, 'initialize': function ( menuObjJSON, parent ) {
var menuItem;
for ( menuItemIndex in menuObjJSON ) {
this.addMenuItem( new MenuItemModel(menuObjJSON[menuItemIndex]) )
}
this.render(parent);
}
, 'render': function ( parent ) {
$(parent).append(this.$el);
}
, 'addMenuItem': function ( model ) {
var menuItem = new MenuItemView({
'model': model,
'parentElement': this.$el
});
menuItem.on('changeActive', this.setActiveButton, this);
this.menuItems.push( menuItem );
return menuItem;
}
, 'removeMenuItem': function ( identifier ) {
var i, menuItem, length = this.menuItems.length, menuItemsCopy;
for (i = 0; i < length; i++) {
if ( this.menuItems[i] ) {
menuItemView = this.menuItems[i];
if ( menuItemView.model.get('text').toLowerCase() === identifier.toLowerCase()
|| menuItemView.model.get('url').toLowerCase() === identifier.toLowerCase() )
{
menuItemView.destroy();
debugger;
menuItemsEnd = this.menuItems.slice(i+1, length);
this.menuItems = [].concat(this.menuItems.slice(0,i), menuItemsEnd);
return true;
}
}
}
return false; //if menu item not found
}
, 'setActiveButton': function ( activeMenuItem ) {
if ( this.activeButton ) {
this.activeButton.removeHighlight();
}
this.activeButton = activeMenuItem;
}
});
MenuItemView = Backbone.View.extend({
'tagName': 'li'
, 'className': 'menuItem'
, 'events': {
'click a': 'highlight'
}
, 'initialize': function ( options ) {
this.render(options.model, options.parentElement);
}
, 'render': function ( model, parentElement ) {
this.$el.append("<a href='" + model.get('url')+ "'>" + model.get('text') + "</a>");
parentElement.append(this.$el);
}
, 'highlight': function ( event ) {
if ( !this.$el.hasClass('active') ) {
this.trigger('changeActive', this);
this.$el.addClass('active');
}
}
, 'removeHighlight': function () {
this.$el.removeClass('active');
}
, 'destroy': function () {
this.unbind('click a');
this.remove(); //unbind from DOM, remove DOM events
}
});
menu = new MenuView([
{'url': '#home', 'text': 'Home'}
, {'url': '#catpics', 'text': 'Cat Pics'}
, {'url': '#dogpics', 'text': 'Dog Pics'}
, {'url': '#about', 'text': 'About Us'}
], $('body'));
setTimeout(function(){
menu.addMenuItem({'url': '#contact', 'text': 'Contact Us'});
}, 1000);
setTimeout(function(){
menu.addMenuItem({'url': '#Login', 'text': 'Log In'});
}, 2000);
setTimeout(function(){
menu.addMenuItem({'url': '#W3bm4573r', 'text': 'W3bm4573r'});
}, 3000);
setTimeout(function(){
menu.addMenuItem({'url': '#something', 'text': 'Something'});
}, 4000);
setTimeout(function(){
menu.removeMenuItem('#contact');
}, 5000);
setTimeout(function(){
menu.removeMenuItem('about us');
}, 5000);
setTimeout(function(){
menu.removeMenuItem('#SOMETHING');
}, 5000);
答案 2 :(得分:0)
我希望这可能对你有所帮助。使用这个jquery
$("ul li").click(function() {
$("ul li").removeClass("active");
$(this).addClass("active");
});
<强> Demo Link 强>