2

这对初学者来说是一个简单的问题,但到目前为止我还没有看到适合我需要的解决方案。基本上我有一个简单的菜单ulli。有2个要求:

Req1:当点击一个时,li将获得新的类.active

Req2:菜单项是动态的,这意味着我应该能够添加或删除任何菜单项(通过使用其他按钮)。

两种方法可以做到这一点:

方法一:将每个MenuView作为MenuItem进行遍历

我有一个类似这样的 MenuView

el:  $('li'),

events: {
  "click" : "highlight"
},

highlight: function(e) {
  thisParent = $(e.target).parent();
  thisParent.siblings('.active').removeClass('active');
  thisParent.addClass('active');
},

优点:容易。这就是我现在所拥有的。

缺点:对 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。删除所有.activeul li

2b。.active类添加到e.targetDOM

Pro:解耦html设计

缺点:更多的代码。

问题:我想大多数人会说方法 1不好。但是有没有更好的方法3、4、5...?如何处理添加新菜单项?

4

3 回答 3

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/上发表评论

于 2012-10-16T10:15:36.003 回答
1

带有代码注释的 JSFiddle 演示

在你的视图中有一些你最想避免的 DOM 遍历......因为这个例子太小了,它不会破坏用户体验,但它是一个最佳实践和所有的好东西。

我认为这对你来说应该是一个很好的起点/例子。

变量设置

var MenuView
,   MenuItemView
,   MenuItemModel
,   menu          //MenuView Instance
,   menuItem      //MenuItemView Instance
;

菜单项模型

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

菜单视图 (<ul>)

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;    
    }
});

菜单项视图 (<li>)

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);
于 2012-10-16T09:17:23.390 回答
0

我希望这对你有帮助。使用这个 jquery

$("ul li").click(function() {
$("ul li").removeClass("active");
$(this).addClass("active");
});

演示链接

于 2012-10-16T06:27:16.660 回答