单击菜单项以在Backbone View中突出显示

时间:2012-10-16 05:39:12

标签: javascript jquery html css backbone.js

这对初学者来说是一个简单的问题,但到目前为止我还没有看到符合我需要的解决方案。基本上我得到了一个包含ulli的简单菜单。有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 ......哪个更好?如何处理添加新菜单项?

3 个答案:

答案 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

MenuItemModel = Backbone.Model.extend({
    'defaults': {
        'url': undefined
    ,   'text': undefined
    }
});

MenuView(&lt; ul&gt;)

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(&lt; li&gt;)

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