Backbone.js集合排序与过滤 #

一、排序基础 #

1.1 comparator属性 #

comparator 定义集合的排序规则:

javascript
var User = Backbone.Model.extend({});

var Users = Backbone.Collection.extend({
    model: User,
    comparator: 'name'
});

var users = new Users([
    { id: 1, name: '王五' },
    { id: 2, name: '张三' },
    { id: 3, name: '李四' }
]);

users.each(function(user) {
    console.log(user.get('name'));
});

1.2 字符串comparator #

javascript
var Users = Backbone.Collection.extend({
    model: User,
    comparator: 'age'
});

var users = new Users([
    { name: '张三', age: 30 },
    { name: '李四', age: 25 },
    { name: '王五', age: 28 }
]);

users.each(function(user) {
    console.log(user.get('name'), user.get('age'));
});

1.3 函数comparator #

javascript
var Users = Backbone.Collection.extend({
    model: User,
    comparator: function(user) {
        return user.get('age');
    }
});

1.4 复杂排序 #

javascript
var Users = Backbone.Collection.extend({
    model: User,
    comparator: function(user) {
        return -user.get('age');
    }
});

var users = new Users([
    { name: '张三', age: 30 },
    { name: '李四', age: 25 },
    { name: '王五', age: 28 }
]);

users.each(function(user) {
    console.log(user.get('name'), user.get('age'));
});

1.5 多字段排序 #

javascript
var Users = Backbone.Collection.extend({
    model: User,
    comparator: function(user) {
        return user.get('lastName') + ' ' + user.get('firstName');
    }
});

var users = new Users([
    { firstName: '三', lastName: '张' },
    { firstName: '四', lastName: '李' },
    { firstName: '五', lastName: '张' }
]);

1.6 排序函数(两个参数) #

javascript
var Users = Backbone.Collection.extend({
    model: User,
    comparator: function(user1, user2) {
        var priority1 = user1.get('priority');
        var priority2 = user2.get('priority');
        
        if (priority1 === priority2) {
            return user1.get('name').localeCompare(user2.get('name'));
        }
        
        return priority1 - priority2;
    }
});

var users = new Users([
    { name: '任务A', priority: 1 },
    { name: '任务B', priority: 2 },
    { name: '任务C', priority: 1 }
]);

二、排序操作 #

2.1 sort方法 #

javascript
var users = new Users([
    { name: '王五', age: 28 },
    { name: '张三', age: 30 },
    { name: '李四', age: 25 }
]);

users.comparator = 'age';
users.sort();

users.each(function(user) {
    console.log(user.get('name'), user.get('age'));
});

2.2 动态排序 #

javascript
var Users = Backbone.Collection.extend({
    model: User,
    
    sortByField: function(field, order) {
        order = order || 'asc';
        
        this.comparator = function(user) {
            var value = user.get(field);
            return order === 'desc' ? -value : value;
        };
        
        this.sort();
    }
});

var users = new Users([
    { name: '张三', age: 30 },
    { name: '李四', age: 25 },
    { name: '王五', age: 28 }
]);

users.sortByField('age', 'desc');

2.3 静默排序 #

javascript
users.sort({ silent: true });

2.4 禁止自动排序 #

javascript
var users = new Users();

users.add({ name: '王五' }, { sort: false });
users.add({ name: '张三' }, { sort: false });
users.add({ name: '李四' }, { sort: false });

users.comparator = 'name';
users.sort();

2.5 sort事件 #

javascript
var users = new Users();

users.on('sort', function(collection, options) {
    console.log('集合已排序');
});

users.comparator = 'name';
users.sort();

三、过滤基础 #

3.1 filter方法 #

javascript
var users = new Users([
    { name: '张三', age: 25, active: true },
    { name: '李四', age: 30, active: false },
    { name: '王五', age: 25, active: true }
]);

var activeUsers = users.filter(function(user) {
    return user.get('active');
});

console.log(activeUsers.length);

3.2 where方法 #

javascript
var users = new Users([
    { name: '张三', age: 25, role: 'user' },
    { name: '李四', age: 30, role: 'admin' },
    { name: '王五', age: 25, role: 'user' }
]);

var result = users.where({ age: 25, role: 'user' });
console.log(result.length);

3.3 findWhere方法 #

javascript
var users = new Users([
    { name: '张三', age: 25 },
    { name: '李四', age: 30 }
]);

var user = users.findWhere({ age: 25 });
console.log(user.get('name'));

3.4 find方法 #

javascript
var users = new Users([
    { name: '张三', age: 25 },
    { name: '李四', age: 30 },
    { name: '王五', age: 25 }
]);

var user = users.find(function(user) {
    return user.get('age') > 25;
});

console.log(user.get('name'));

3.5 reject方法 #

javascript
var users = new Users([
    { name: '张三', age: 25 },
    { name: '李四', age: 30 },
    { name: '王五', age: 25 }
]);

var olderUsers = users.reject(function(user) {
    return user.get('age') < 30;
});

console.log(olderUsers.length);

四、高级过滤 #

4.1 复合条件过滤 #

javascript
var Users = Backbone.Collection.extend({
    model: User,
    
    filterBy: function(criteria) {
        return this.filter(function(user) {
            for (var key in criteria) {
                if (user.get(key) !== criteria[key]) {
                    return false;
                }
            }
            return true;
        });
    }
});

var users = new Users([
    { name: '张三', age: 25, role: 'user' },
    { name: '李四', age: 30, role: 'admin' },
    { name: '王五', age: 25, role: 'user' }
]);

var result = users.filterBy({ age: 25, role: 'user' });
console.log(result.length);

4.2 范围过滤 #

javascript
var Users = Backbone.Collection.extend({
    model: User,
    
    filterByAgeRange: function(min, max) {
        return this.filter(function(user) {
            var age = user.get('age');
            return age >= min && age <= max;
        });
    }
});

var users = new Users([
    { name: '张三', age: 25 },
    { name: '李四', age: 30 },
    { name: '王五', age: 35 }
]);

var result = users.filterByAgeRange(25, 30);
console.log(result.length);

4.3 搜索过滤 #

javascript
var Users = Backbone.Collection.extend({
    model: User,
    
    search: function(query) {
        query = query.toLowerCase();
        
        return this.filter(function(user) {
            var name = user.get('name').toLowerCase();
            var email = user.get('email').toLowerCase();
            
            return name.indexOf(query) !== -1 || 
                   email.indexOf(query) !== -1;
        });
    }
});

var users = new Users([
    { name: '张三', email: 'zhangsan@example.com' },
    { name: '李四', email: 'lisi@example.com' },
    { name: '王五', email: 'wangwu@example.com' }
]);

var result = users.search('张');
console.log(result.length);

4.4 正则过滤 #

javascript
var Users = Backbone.Collection.extend({
    model: User,
    
    filterByPattern: function(field, pattern) {
        var regex = new RegExp(pattern, 'i');
        
        return this.filter(function(user) {
            return regex.test(user.get(field));
        });
    }
});

var users = new Users([
    { name: '张三', email: 'zhangsan@example.com' },
    { name: '李四', email: 'lisi@test.com' }
]);

var result = users.filterByPattern('email', '@example\\.com$');
console.log(result.length);

五、分组与统计 #

5.1 groupBy方法 #

javascript
var users = new Users([
    { name: '张三', age: 25 },
    { name: '李四', age: 30 },
    { name: '王五', age: 25 }
]);

var grouped = users.groupBy(function(user) {
    return user.get('age');
});

console.log(grouped[25].length);
console.log(grouped[30].length);

5.2 countBy方法 #

javascript
var users = new Users([
    { name: '张三', role: 'user' },
    { name: '李四', role: 'admin' },
    { name: '王五', role: 'user' }
]);

var counts = users.countBy(function(user) {
    return user.get('role');
});

console.log(counts);

5.3 partition方法 #

javascript
var users = new Users([
    { name: '张三', active: true },
    { name: '李四', active: false },
    { name: '王五', active: true }
]);

var partitioned = users.partition(function(user) {
    return user.get('active');
});

console.log('活跃:', partitioned[0].length);
console.log('非活跃:', partitioned[1].length);

六、实用示例 #

6.1 可排序集合 #

javascript
var SortableCollection = Backbone.Collection.extend({
    sortField: null,
    sortOrder: 'asc',
    
    setSort: function(field, order) {
        this.sortField = field;
        this.sortOrder = order || 'asc';
        
        this.comparator = function(model) {
            var value = model.get(field);
            
            if (typeof value === 'string') {
                value = value.toLowerCase();
            }
            
            return this.sortOrder === 'desc' ? -value : value;
        }.bind(this);
        
        this.sort();
    },
    
    toggleSort: function(field) {
        if (this.sortField === field) {
            this.sortOrder = this.sortOrder === 'asc' ? 'desc' : 'asc';
        } else {
            this.sortField = field;
            this.sortOrder = 'asc';
        }
        
        this.setSort(field, this.sortOrder);
    }
});

6.2 可过滤集合 #

javascript
var FilterableCollection = Backbone.Collection.extend({
    filters: {},
    
    setFilter: function(key, value) {
        if (value === null || value === undefined) {
            delete this.filters[key];
        } else {
            this.filters[key] = value;
        }
        
        this.trigger('filter', this.getFiltered());
    },
    
    clearFilters: function() {
        this.filters = {};
        this.trigger('filter', this.models);
    },
    
    getFiltered: function() {
        var self = this;
        
        return this.filter(function(model) {
            for (var key in self.filters) {
                if (model.get(key) !== self.filters[key]) {
                    return false;
                }
            }
            return true;
        });
    }
});

6.3 分页集合 #

javascript
var PagedCollection = Backbone.Collection.extend({
    page: 1,
    perPage: 10,
    
    getPage: function() {
        var start = (this.page - 1) * this.perPage;
        var end = start + this.perPage;
        
        return this.slice(start, end);
    },
    
    setPage: function(page) {
        this.page = page;
        this.trigger('page:change', this.page);
    },
    
    totalPages: function() {
        return Math.ceil(this.length / this.perPage);
    },
    
    hasNext: function() {
        return this.page < this.totalPages();
    },
    
    hasPrev: function() {
        return this.page > 1;
    },
    
    nextPage: function() {
        if (this.hasNext()) {
            this.setPage(this.page + 1);
        }
    },
    
    prevPage: function() {
        if (this.hasPrev()) {
            this.setPage(this.page - 1);
        }
    }
});

6.4 搜索集合 #

javascript
var SearchableCollection = Backbone.Collection.extend({
    searchQuery: '',
    searchFields: ['name', 'email'],
    
    search: function(query) {
        this.searchQuery = query.toLowerCase();
        this.trigger('search', this.getSearchResults());
    },
    
    getSearchResults: function() {
        if (!this.searchQuery) {
            return this.models;
        }
        
        var self = this;
        
        return this.filter(function(model) {
            return self.searchFields.some(function(field) {
                var value = model.get(field);
                if (value) {
                    return value.toLowerCase().indexOf(self.searchQuery) !== -1;
                }
                return false;
            });
        });
    },
    
    clearSearch: function() {
        this.searchQuery = '';
        this.trigger('search', this.models);
    }
});

七、总结 #

7.1 排序方法 #

方法 说明
comparator 定义排序规则
sort(options) 执行排序
sortBy(field) 按字段排序

7.2 过滤方法 #

方法 说明
filter(predicate) 过滤模型
where(attrs) 条件过滤
findWhere(attrs) 查找第一个匹配
find(predicate) 查找第一个满足条件的
reject(predicate) 反向过滤

7.3 最佳实践 #

  1. 使用 comparator 实现默认排序
  2. 使用函数形式实现复杂排序
  3. 封装通用的过滤方法
  4. 使用事件通知过滤结果变化
  5. 考虑性能,避免频繁排序
最后更新:2026-03-28