2

これは初心者にとっては単純な問題ですが、これまでのところ、自分のニーズに合った解決策は見当たりません。基本的に私はとでシンプルなメニューを手に入れましulli。2つの要件があります。

Req1: 1つをクリックするliと、新しいクラスが取得されます.active

Req2:メニュー項目は動的です。つまり、(他のボタンを使用して)任意のメニュー項目を追加または削除できるはずです。

これを行うには2つの方法があります。

方法1:MenuItemとしての各MenuViewのトラバース

私はこのようなもので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の1つのビュー

MenuItemCollectionを作成し、代わりにそのコレクションにMenuViewを使用します。elMenuViewのはul(の代わりにli)になります。HTMLは次のようになりますid

<ul>
    <li id="leftmenu-one">one</li>
    <li id="leftmenu-two">two</li>
    <li id="leftmenu-three">three</li>
</ul>

次に、クリックイベントが検出されたら、次の2つのことを行います。

2a。.activeのすべてのクラスを削除しますul li

2b。DOMに.activeクラスを追加しますe.target

プロ: 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;
        }
    });

http://jsfiddle.net/Kf3SS/のコメント付きの完全に機能する js フィドル

于 2012-10-16T10:15:36.003 に答える
1

コード コメント付きの JSFiddle デモ

ビューには、避けたいと思われる DOM トラバーサルが少しあります...この例は非常に小さいため、ユーザー エクスペリエンスを台無しにすることはありませんが、ベスト プラクティスであり、すべての優れた機能です。

これはあなたにとって良い出発点/例になるはずです。

変数設定

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

MenuItemModel

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

MenuItemView (<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 に答える