1

我正在尝试制作我的第一个主干应用程序,但遇到了一个我无法解决的问题..

我有一个链接列表,每个链接旁边都有一个计数器,当我单击一个链接时,我希望计数器增加 1。(我已经做到了,它正在工作)

接下来,如果计数器值高于上面的链接,我希望我单击的链接在列表中向上移动。

像这样。

  • 第一个链接 (4)
  • 第二个链接 (3)
  • 第三个链接 (3) <-- 如果我单击此链接,我希望它向上移动到第二个链接之上。

我曾尝试使用比较器和 sortBy,但每次我尝试某些东西时,我似乎都无法重新渲染视图,并且链接也会向上移动一个位置。

当主视图初始化时,我确实设法对列表进行了排序。但是在我单击其中一个链接后更新视图和列表位置,我无法弄清楚如何完成。

我的代码:

(function() {

window.App = {
    Models: {},
    Collections: {},
    Views: {}
};
window.template = function(id) {
    return _.template( $('#' + id).html() );
};


//Modellen
App.Models.Task = Backbone.Model.extend({
    defaults: {
        name: 'Foo Bar Baz',
        uri: 'http://www.google.com',
        counter: 0
    },

    validate: function(attr) {
            if ( ! $.trim(attr.name) ) {
                    return 'En opgave kræver en title.';
            };
    }
});

//Collection
App.Collections.Tasks = Backbone.Collection.extend({ 
    model: App.Models.Task,

    comparator: function(task) {
    return task.get('counter');
    },

});



//Singel view
App.Views.TaskView = Backbone.View.extend({
    tagName: 'li',

    template: template('Tasks'),

    initialize: function() {
        this.model.on('change', this.render, this);
        this.model.on('destroy', this.remove, this);

    },

    events: {
    'click .edit' : 'retTask',
    'click .delete' : 'destroy',
    'click .uriLink' : 'addCounter'
    },

    retTask: function() {
        var newTaskNavn = prompt('Hvad skal det nye navn være', this.model.get('name'));

        if ( !newTaskNavn ) return;
        this.model.set('name', newTaskNavn);
    },      

    destroy: function() {
        this.model.destroy();

    },

    addCounter: function(e) {
        e.preventDefault();
        var newCounter = this.model.get('counter');
        this.model.set('counter', newCounter + 1);
    },

    remove: function() {
        this.$el.remove();
    },

    render: function()  {
        this.$el.html(this.template(this.model.toJSON()) );
        return this;
    }
});

//Collection View
App.Views.TasksView = Backbone.View.extend({
    tagName: 'ul',

    initialize: function() {
        this.collection.on('add', this.addOne, this);
        this.render();
    },

    render: function() {
        this.collection.each(this.addOne, this);
        return this;
    },

    addOne: function(task) {
        var taskView = new App.Views.TaskView({ model: task });
        this.$el.append(taskView.render().el);

    }
});

App.Views.AddTask = Backbone.View.extend({
    el: '#addTask',

    initialize: function() {
    },

    events: {
        'submit' : 'submit'
    },

    submit: function(e) {
        e.preventDefault();
        var taskNavn = $(e.currentTarget).find('.navnClass').val(),
             uriNum =  $(e.currentTarget).find('.uriClass').val();

        if ( ! $.trim(taskNavn)) {

            var test =  prompt('opgaven skal have et navn', '');
            if ( ! $.trim(test)) return false;
                taskNavn = test;
        }

        if( uriNum.indexOf( "http://" ) == -1 ) {
                     addedValue = 'http://',
                     uriNum = addedValue + uriNum;
        }

        $(e.currentTarget).find('input[type=text]').val('').focus();
        //var task = new App.Models.Task({ name: taskNavn, uri: uriNum });
        this.collection.add({ name: taskNavn, uri: uriNum });
    }

});


// new tasks collection
var tasks = new App.Collections.Tasks([
{
    name: 'Foo',
    uri: 'www.google.com',
    counter: 3
},
{   
    name: 'Bar',
    uri: 'http://google.com',
    counter: 2
},
{
    name: 'Baz',
    uri: 'http://www.google.com',
    counter: 1
}
]);

 // tasks.comparator = function(task) {
 // return task.get("counter");
 // };  
 tasks.sort();

// new collection view (add)
var addTaskView = new App.Views.AddTask({ collection: tasks});

// new collection view
var tasksView = new App.Views.TasksView({ collection: tasks });
$('.tasks').html(tasksView.el);

})();

我的 HTML :(如果有人想尝试复制场景:)

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>LinkList</title>
</head>
<body>

<h1>Mine opgaver</h1>
<form action="" id="addTask">
    <input class="navnClass" type="text" placeholder="Link name"><input clas s="uriClass" type="text" placeholder="www.url-here.com">
    <button class="nyOpgave">Ny opgave</button><br />

</form>

<div class="tasks">
    <script type="text/template" id="Tasks">
        <span class="linkNavn"><%= name %></span> - <a href="<%= uri %>" class="uriLink" target="_blank"><%= uri %></a> : [<span class="counterClass"><%= counter %></span>] <button class="edit">Edit</button> <button class="delete">Delete</button>
    </script>
</div>
<script src="js/underscore.js"></script>
<script src="http://ajax.cdnjs.com/ajax/libs/json2/20110223/json2.js"></script>
<script src="js/jquery.js"></script>
<script src="js/backbone.js"></script>
<script src="main.js"></script>

</body>
</html>

谁能帮我解决这个问题?

/干杯马塞尔

4

2 回答 2

3

好的,我已经为您创建了应用程序,正如您希望它运行的那样。我将尝试向您解释整个代码、我写的内容以及我写的原因。

首先,看看 JSfiddle:这里

接下来,让我解释一下:

1.这是我的模型,它存储了链接的名称、href、id(在我的示例中没有使用,但它只是为每个模型分配一个唯一的 id 的好习惯),最后是链接的点击次数(模型) .

var myModel = Backbone.Model.extend({
    defaults:{
        'id' : 0,
        'name' : null,
        'link' : '#',
        'clicks' : 0
    }
});

2.这个集合,存储我所有的模型,我添加了一个比较器功能,这样当你将模型添加到集合时,它会对集合进行排序。

注意:我添加了一个-符号以按点击次数的降序对集合进行排序(最大点击次数的链接首先出现)

var myCollection = Backbone.Collection.extend({
        model: myModel,
        comparator: function(item) {
            return -item.get('clicks');
        }
    });

3.现在这是我的主视图,主视图是什么意思?此视图主要呈现您想要显示的列表。这里有漂亮的自我解释代码。有一件事,this.coll.bind('add change',this.render,this)我添加了一个“更改”,因为每当此集合中的任何模型发生更改时,我们都想重新渲染整个列表,当我更改任何链接的计数时会发生这种情况,单击它时,我想重新渲染整个列表。

var myView = Backbone.View.extend({
    el: $("#someElement"),
    tagName : 'ul',

    initialize: function() {
        this.coll = new myCollection();
        this.coll.bind('add change',this.render,this);
    },

    events: {
        "click #add": "add"
    },

    add: function(e){
        e.preventDefault();
        var mod = new myModel();
        var name = $('#name').val();
        var link = $('#link').val();
        mod.set({'id':mod.cid, 'name':name,'link':link});                    
        this.coll.add(mod);

    },

    render : function(){

        $('#list').empty();
        this.coll.sort();
        this.coll.forEach(function(model){
            var listItem = new printView({ model: model});
            $('#list').append(listItem.render().el);
        });
    }
});

4.这是我的子视图,为什么我要做第二个视图,为什么1个视图不够?那么这考虑一个场景,每个链接都有一个删除按钮(例如),当我单击删除按钮时(我只有一个视图)我如何识别要销毁的模型(从集合中删除?),一种可能的方式将 acid与每个模型相关联,然后单击我可以执行 this.coll.getByCid() ,但这不是一个很好的方法,恕我直言,所以我为每个模型创建了一个单独的视图。这个视图呈现每个模型并返回仅此而已。

var printView = Backbone.View.extend({

    tagName: 'li',

    initialize : function(options) {
        _.bindAll(this, "render");                   
    },

    events:{
        "click a": "count"
    },

    render:function(){
        var linkName = this.model.get("name");
        var link= this.model.get("link");
        var clicks = this.model.get("clicks");

        this.$el.append("<a class='link' href='"+link+"'>"+linkName+"</a> ("+clicks+")");

        return this;
    },

    count:function(e){
        e.preventDefault();
        e.stopPropagation();
        var clicks = this.model.get("clicks");
        clicks++;
        this.model.set({'clicks':clicks});
    }

});

5.初始化我的(主)myView

new myView();

注意:我确实相信这个应用程序/代码可以用更好的方式编写,有一些改进,但我的能力和它的工作原理(:p)我认为它可以帮助你。

于 2013-02-08T19:42:56.723 回答
2

集合比较器仅在将新模型添加到集合时执行:它不会在属性更改时更新集合顺序。为了实现这一点,您需要调用collection.sort()

App.Collections.Tasks = Backbone.Collection.extend({ 
    model: App.Models.Task,
    initialize: function() {
        this.on('change:counter', this.sort);
    },
    comparator: function(task) {
        return task.get('counter');
    }
});

在列表视图中,您可以收听集合的sort事件,并重新呈现您的视图:

App.Views.TasksView = Backbone.View.extend({
    tagName: 'ul',

    initialize: function() {
        this.collection.on('add', this.addOne, this);
        this.collection.on('sort', this.render, this);
        this.render();
    },

    render: function() {
        //if there are existing child views, remove them
        if(this.taskViews) {
            _.each(this.taskViews, function(view) {
                view.remove();
            });
        }
        this.taskViews = []; 
        this.collection.each(this.addOne, this);
        return this;
    },

    addOne: function(task) {
        var taskView = new App.Views.TaskView({ model: task });
        this.$el.append(taskView.render().el);

        //keep track of child views
        this.taskViews.push(taskView);
    }
});
于 2013-02-08T13:54:44.803 回答