2

少し背景

ツイート/行がクリック時に展開され、より多くの情報が表示されるフィードのようなTwitterを作成しようとしています。

データはJSONファイルから取得されます(バックエンドからフロントエンドに送信されます)。バックボーンを使用して、フロントエンドでデータをレンダリングします。

フィードに10行が表示され、各行にいくつかの情報が表示されたら、行をクリックすると/ divが展開され、より多くの情報が表示されます。説明フィールドにはかなりの量のテキストが含まれているため、JavaScriptの省略記号を適用しています。短い説明は複数行である必要があるため、Javascript省略記号を使用します(CSS省略記号は複数行で機能するとは思わないでください)。

  1. 説明テキストを切り捨てるプラグインを作成し、クリックすると省略記号を削除して完全な説明に置き換えます(行が展開されるため)。

  2. (切り捨てられる前に)完全な説明を配列に保存するプラグインを作成しました。

問題

私のアイデアは、クリックされた行のインデックス(currentTarget)を(配列に)保存された行のインデックスと比較し、省略記号のテキストを完全な説明に置き換えてから、divをjQueryanimateで展開することでした。

バックボーンの「クリックイベント」からインデックスを取得する方法があるかどうかわかりません(配列に保存されているインデックスと比較するため)?

これにアプローチするより良い方法があるかどうか私に知らせてください。

前もって感謝します

これが私のコードです:

元のテキスト関数を切り捨てて保存する

/**
 * Plugins
 */
var arr = [];

$.fn.truncate = function(){
    return this.each(function(index,element){
        var elementText = $(element).text();
        if(elementText.length > 165){
            var truncated = elementText.trim().substring(0, 165).split(" ").slice(0, -1).join(" ") + "…";
        }
        $(element).text(truncated);
    });
};

$.fn.getText = function(){
    return this.each(function(index,element){
        arr.push({
            i: index,
            v: $(element).text()
        });
    });
};

バックボーンモデルとコレクション

/**
 * Model
 */
var Task = Backbone.Model.extend();

/**
 * Collections
 */
var RecentTasksList = Backbone.Collection.extend({
    model: Task,
    url: 'json/recentTasks.json'
});

バックボーンビュー

/**
 * Views
 */
var RecentTasksView = Backbone.View.extend({
    el: '.taskList',
    template: _.template($('#recentTasksTemplate').html()),
    render: function(){
        _.each(this.model.models, function(data){
            this.$el.append(this.template(data.toJSON()));
        }, this);

        $('.description').getText();
        $('.description').truncate();

        return this;
    }
});

var FullTaskView = Backbone.View.extend({
    el: '.taskContainer',
    events: {
        'click .task': 'showFullDetails'
    },
    showFullDetails: function(e){
        var eTarget = $(e.currentTarget);
        var $desc = $('.description');

        if(eTarget.hasClass('expanded')){
            eTarget.animate({
                'height': '80px'
            },
            function(){
                eTarget.removeClass('expanded');
            });
        }
        else{
            console.log($(eTarget).find($desc).html());

            eTarget.animate({
                //doesn't work lesser IE 8
                'height': eTarget[0].scrollHeight
            },
            function(){
                eTarget.addClass('expanded');
            });     
        }
    }
});

var AppView = Backbone.View.extend({
    el: 'body',
    initialize: function(){
        //Recent Tasks
        var recentTasksList = new RecentTasksList();
        var recentTasksView = new RecentTasksView({
            model: recentTasksList
        });
        recentTasksList.bind('reset', function(){
            recentTasksView.render();
        });
        recentTasksList.fetch();

        //Full Task Details
        var fullTaskView = new FullTaskView();
    }
});

var appView = new AppView();

アンダースコアテンプレート

<script id="recentTasksTemplate" type="text/template">
    <div class="task clearfix">
        <div class="image">
            <img src="<%= image %>" />
        </div>
        <div class="details">
            <h3 class="title"><%= title %></h3>
            <div class="description">
                <%= description %>
            </div>
        </div>
    <div>
</script>

HTML

<div class="taskContainer">
    <div class="taskList"></div>
</div>

編集

最後の質問です。ページにタブを追加しました(同様の召喚状)。同じ種類の情報がクリック時に表示されます(同じテンプレートを使用しています)。たとえば、RecentTaskとPopularTaskがあります。クリックイベントを含むタブのビューを作成しました。毎回モデルをインスタンス化してデータを表示およびフェッチする必要がありますか、それともすでに初期化されているデータを再利用できますか?

2番目のタブの新しいビューを作成しました。サーバーからJSONファイルを取得する:

var PopularTasksList = Backbone.Collection.extend({
    model: Task,
    url: 'json/popularTasks.json'
});

var PopularTasksView = Backbone.View.extend({
    el: '.taskList',
    render: function(){
        $('.taskList').empty();
        _.each(this.model.models, function(model){
            var taskView = new TaskView({model: model});
            this.$el.append(taskView.render().el);
        }, this);
        return this;
    }
});

次に、クリック時に正しいタスクを表示するタブビューを作成しました。

var TabsView = Backbone.View.extend({
            el: 'body',
            events:{
                'click .tabRecent': 'fetchDataRecentTasks',
                'click .tabPopular': 'fetchDataPopularTasks'
            },
            fetchDataRecentTasks: function(){
                var recentTasksList = new RecentTasksList();
                var recentTasksView = new RecentTasksView({
                    model: recentTasksList
                });
                recentTasksList.bind('reset', function(){
                    recentTasksView.render();
                });
                recentTasksList.fetch();
            },
            fetchDataPopularTasks: function(){
                var popularTasksList = new PopularTasksList();
                var popularTasksView = new PopularTasksView({
                    model: popularTasksList
                });     
                popularTasksList.bind('reset', function(){
                    popularTasksView.render();
                });
                popularTasksList.fetch();
            }
        });
4

1 に答える 1

2

個々のタスクに対して新しいビューを作成する必要があると思います。次に、そのビューでクリックを処理できるため、タスクモデルにアクセスでき、そのビューのDOMにも非常に簡単にアクセスできます。

次に、FullTask​​ViewとjQueryプラグインを取り除くことができます。

 /**
 * Model
 */
var Task = Backbone.Model.extend({
    getShortDescription: function(){
       var desc = this.get('description');
       if(desc.length > 165){
        return desc.trim().substring(0, 165).split(" ").slice(0, -1).join(" ") + "…";
       }
       return desc;
    }
});

新しいTaskViewを追加し、RecentTasksViewを変更してそれらを作成/レンダリングします。

/**
 * Views
 */

var TaskView = Backbone.View.extend({
    template: _.template($('#recentTasksTemplate').html()),
    events: {
       'click': 'showFullDetails'
    },
    render: function(){
        // pass the model json, plus the short description to the template
        this.$el.html(this.template({
            data: this.model.toJSON(), 
            shortDesc: this.model.getShortDescription()
            }));

        return this;
    },
    showFullDetails: function(){
       // change text, show/hide, animate here
       // In the view, this.$() will only match elements within this view.

       // if expand...
       this.$('.description').html(this.model.get('description'));

       // if hide...
       this.$('.description').html(this.model.getShortDescription());
    }
});
var RecentTasksView = Backbone.View.extend({
    el: '.taskList',
    render: function(){
        _.each(this.model.models, function(model){
            // create a view for each task, render and append it
            var taskView = new TaskView({model: model});
            this.$el.append(taskView.render().el);
        }, this);

        return this;
    }
});

渡された新しいデータを使用するようにテンプレートを変更します。

// access the model stuff with data.title, etc. 
<script id="recentTasksTemplate" type="text/template">
    <div class="task clearfix">
        <div class="image">
            <img src="<%= data.image %>" />
        </div>
        <div class="details">
            <h3 class="title"><%= data.title %></h3>
            <div class="description">
                <%= shortDesc %>
            </div>
        </div>
    <div>
</script>

編集:

バックボーンビューはDOM要素を管理することを目的としているため、各タスクを独自のビューインスタンスにすることをお勧めします。これにより、クリックに基づいてテキストを展開および変更することが容易になります。また、ビューの外部にDOM要素内のコードを変更しないようにすることをお勧めします。そのため、各タスクビュー内でその操作を行うことをお勧めします。

これは、TodoサンプルのTodoViewに似ています。

http://backbonejs.org/docs/todos.html

http://backbonejs.org/examples/todos/index.html

テンプレート関数は、任意のjavascriptオブジェクト(プロパティだけでなく関数を持つオブジェクトでも)に渡すことができます。技術的にはモデルの一部ではないデータを表示したいので、そのdataオブジェクトを渡すことは、必要なものをテンプレートに取り込むための単なる方法です。

于 2013-02-19T03:19:30.023 に答える