knockout.js 中的多个过滤器
Posted
技术标签:
【中文标题】knockout.js 中的多个过滤器【英文标题】:Multiple filters in knockout.js 【发布时间】:2014-04-03 11:31:45 【问题描述】:假设我有电影数组,如果我想按类型过滤,我可以这样做
filtered = ko.computed(function()
var self = this;
if ( ! self.genresFilter() || self.genresFilter() === 'all')
return this.sourceItems();
else
return ko.utils.arrayFilter(self.sourceItems(), function(item)
return app.utils.inArray(item.genre, self.genresFilter());
);
, app.viewModels.games);
但是我目前遇到的问题是,如果我有类型、语言和长度的 html 下拉列表,我如何通过所有或部分过滤器有效地过滤电影,这样我就可以制作 90 分钟的俄罗斯动作片或动作片长度等?
【问题讨论】:
您需要查看所有过滤器选项并应用每个具有值的过滤器。过滤器的顺序无关紧要。我们的想法是从未过滤的结果池中删除所有内容,直到只剩下适合所有过滤器的结果。 【参考方案1】:您需要根据提供的每个过滤器逐步构建过滤列表。至于过滤器本身,它们应该每个都由一个可观察对象表示,或者它们全部都在一个可观察数组中。这很重要,因为它会在您更改过滤器时触发计算更新。
例子:
var filteredList = ko.computed(
var currentList = this.sourceItems();
var currentFilters = this.genresFilters();
ko.utils.arrayForEach(currentFilters, function ()
currentList = ko.utils.arrayFilter(currentList, function(filter)
return app.utils.inArray(filter, currentFilters);
);
);
return currentList;
);
此代码将遍历每个过滤器,获取最新过滤的列表并仅保留满足所有条件的项目。
【讨论】:
【参考方案2】:我知道这是老话题,但我最近遇到了同样的问题,这是我为您的电影模型修改的解决方案。你也可以在这里查看:jsfiddle
var MoviesModel = function(data)
var self = this;
self.Genres = ko.observableArray(data.genres);
self.Genres.unshift("All");
self.filterGenre = ko.observable("All");
self.Languages = ko.observableArray(data.languages);
self.Languages.unshift("All");
self.filterLanguage = ko.observable("All");
self.Lengths = ko.observableArray(data.lengths);
self.Lengths.unshift("All");
self.filterLength = ko.observable("All");
self.movies = ko.observableArray(data.movies);
self.filteredMovies = ko.computed(function()
var filteredArray = ko.utils.arrayFilter(self.movies(), function(item)
return (
(item.genre == self.filterGenre() || self.filterGenre() == "All") &&
(item.language == self.filterLanguage() || self.filterLanguage() == "All") &&
(item.length == self.filterLength() || self.filterLength() == "All")
);
);
return filteredArray;
);
;
var data =
genres: ["Drama", "Horror", "Sci-Fi"],
languages: ["English", "Russian"],
lengths: ["100", "120", "140", "160"],
movies: [
name: "Godfather", genre: "Drama", language: "English", length: "160" ,
name: "The shining", genre: "Horror", language: "English", length: "140",
name: "Stalker", genre: "Sci-Fi", language: "Russian", length: "160" ,
name: "Alien", genre: "Sci-Fi", language: "English", length: "120" ,
name: "Russiam ark", genre: "Drama", language: "Russian", length: "100" ,
name: "Psycho", genre: "Horror", language: "English", length: "120"
]
;
var viewModel = new MoviesModel(data);
ko.applyBindings(viewModel);
table td
padding-right: 20px;
<table>
<thead>
<tr>
<td>Movie name</td>
<td>Genre</td>
<td>Language</td>
<td>Length</td>
</tr>
<tr>
<td></td>
<td>
<select data-bind="options: Genres, value: filterGenre"></select>
</td>
<td>
<select
data-bind="options: Languages, value: filterLanguage"
></select>
</td>
<td>
<select data-bind="options: Lengths, value: filterLength"></select>
</td>
</tr>
</thead>
<tbody data-bind="foreach: filteredMovies">
<tr>
<td data-bind="text: name"></td>
<td data-bind="text: genre"></td>
<td data-bind="text: language "></td>
<td data-bind="text: length"></td>
</tr>
</tbody>
</table>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
【讨论】:
【参考方案3】:过滤结果是针对值的组合,可以通过迭代所有可能的过滤器来完成,应用用户选择的内容,并从结果中删除不适合过滤器的项目。应用过滤器的顺序无关紧要。这些项目必须符合所有标准才能成为有效结果,因此您可以在不符合的情况下立即丢弃它们。
这是一些伪代码。
# item1:
# color: red
# price: 5
# language: EN
# item2:
# color: red
# price: 10
# language: RU
# item3:
# color: green
# price: 7
# language: DE
@items = ( item1, item2, item3 );
foreach filter in @selectedFilters
foreach item in @items
delete item from @items if filter.value != item.<filter.type>
# or <, >, whatever
return @items
【讨论】:
以上是关于knockout.js 中的多个过滤器的主要内容,如果未能解决你的问题,请参考以下文章
将多个输入绑定到可观察数组中的同一变量(Knockout.JS)
Knockout JS 订阅 2 个 observables 的方式是,如果 2 个 observables 中的任何一个发生变化,我只会收到一次通知