基于JavaScript實(shí)現(xiàn)前端數(shù)據(jù)多條件篩選功能
有時(shí)候也會(huì)需要在前端進(jìn)行數(shù)據(jù)篩選,增強(qiáng)交互體驗(yàn)。當(dāng)數(shù)據(jù)可用的篩選條件較多時(shí),把邏輯寫死會(huì)給后期維護(hù)帶來(lái)很大麻煩。下面是我自己寫的一個(gè)簡(jiǎn)單的篩選器,篩選條件可以根據(jù)數(shù)據(jù)包含的字段動(dòng)態(tài)設(shè)置。
仿照京東的篩選條件,這里就取價(jià)格區(qū)間和品牌作為測(cè)試。

代碼
代碼中主要使用js的過濾器Array.prototype.filter,該方法會(huì)對(duì)數(shù)組元素進(jìn)行遍歷檢查,返回一個(gè)符合檢查條件的新數(shù)組,不會(huì)改變?cè)瓟?shù)組。
// filter()
var foo = [0,1,2,3,4,5,6,7,8,9];
var foo1 = foo.filter(
function(item) {
return item >= 5
}
);
console.log(foo1); // [5, 6, 7, 8, 9]
有了這個(gè)方法,篩選數(shù)據(jù)方便了很多,下面先定義一個(gè)商品類。
// 定義商品類
function Product(name, brand, price) {
this.name = name; // 名稱
this.brand = brand; // 品牌
this.price = price; // 價(jià)格
}
創(chuàng)建一個(gè)過濾器對(duì)象,把所有過濾數(shù)據(jù)的方法放在里面。為了能自動(dòng)適配不同的篩選條件,將篩選條件分為兩個(gè)大類,一個(gè)是區(qū)間類型rangesFilter ,如:品牌、內(nèi)存等;一個(gè)是選擇類型choosesFilter,如:價(jià)格、屏幕尺寸等。
不同大類同時(shí)篩選時(shí),進(jìn)行的是與邏輯,每個(gè)大類在上一個(gè)大類篩選結(jié)果上進(jìn)行篩選。比如我要篩選2000-5000塊的華為手機(jī),先調(diào)用rangesFilter篩選products并返回結(jié)果result1,然后用choosesFilter篩選result1并返回結(jié)果resulte2。
當(dāng)然,如果還有其它大類,不一定是與邏輯,再另行處理。
// 商品篩選器
const ProductFilters = {
/**
* 區(qū)間類型篩選
* @param {array<Product>} products
* @param {array<{type: String, low: number, high: number}>} ranges
*/
rangesFilter: function (products, ranges) { }
/**
* 選擇類型篩選
* @param {array<Product>} products
* @param {array<{type: String, value: String}>} chooses
*/
choosesFilter: function (products, chooses) { }
}
區(qū)間類型的篩選,代碼如下。
// 區(qū)間類型條件結(jié)構(gòu)
ranges: [
{
type: 'price', // 篩選類型/字段
low: 3000, // 最小值
high: 6000 // 最大值
}
]
/**
* @param {array<Product>} products
* @param {array<{type: String, low: number, high: number}>} ranges
*/
rangesFilter: function (products, ranges) {
if (ranges.length === 0) {
return products;
} else {
/**
* 循環(huán)多個(gè)區(qū)間條件,
* 每種區(qū)間類型應(yīng)該只有一個(gè),
* 比如價(jià)格區(qū)間不會(huì)有1000-2000和4000-6000同時(shí)需要的情況
*/
for (let range of ranges) {
// 多個(gè)不同類型區(qū)間是與邏輯,可以直接賦值給自身
products = products.filter(function (item) {
return item[range.type] >= range.low && item[range.type] <= range.high;
});
}
return products;
}
}
選擇類型篩選:
// 選擇類型條件結(jié)構(gòu)
chooses: [
{
type: 'brand',
value: '華為'
},
{
type: 'brand',
value: '蘋果'
}
]
/**
* @param {array<Product>} products
* @param {array<{type: String, value: String}>} chooses
*/
choosesFilter: function (products, chooses) {
let tmpProducts = [];
if (chooses.length === 0) {
tmpProducts = products;
} else {
/**
* 選擇類型條件是或邏輯,使用數(shù)組連接concat
*/
for (let choice of chooses) {
tmpProducts = tmpProducts.concat(products.filter(function (item) {
return item[choice.type].indexOf(choice.value) !== -1;
}));
}
}
return tmpProducts;
}
定義一個(gè)執(zhí)行函數(shù)doFilter()。
function doFilter(products, conditions) {
// 根據(jù)條件循環(huán)調(diào)用篩選器里的方法
for (key in conditions) {
// 判斷是否有需要的過濾方法
if (ProductFilters.hasOwnProperty(key + 'Filter') && typeof ProductFilters[key + 'Filter'] === 'function') {
products = ProductFilters[key + 'Filter'](products, Conditions[key]);
}
}
return products;
}
// 將兩種大類的篩選條件放在同一個(gè)對(duì)象里
let Conditions = {
ranges: [
{
type: 'price',
low: 3000,
high: 6000
}
],
chooses: [
{
type: 'brand',
value: '華為'
}
]
}
測(cè)試
創(chuàng)建10個(gè)商品數(shù)據(jù),以及篩選條件
// 商品數(shù)組
const products = [
new Product('華為榮耀9', '華為', 2299),
new Product('華為P10', '華為', 3488),
new Product('小米MIX2', '小米', 3599),
new Product('小米6', '小米', 2499),
new Product('小米Note3', '小米', 2499),
new Product('iPhone7 32G', '蘋果', 4588),
new Product('iPhone7 Plus 128G', '蘋果', 6388),
new Product('iPhone8', '蘋果', 5888),
new Product('三星Galaxy S8', '三星', 5688),
new Product('三星Galaxy S7 edge', '三星', 3399),
];
// 篩選條件
let Conditions = {
ranges: [
{
type: 'price',
low: 3000,
high: 6000
}
],
chooses: [
{
type: 'brand',
value: '華為'
},
{
type: 'brand',
value: '蘋果'
}
]
}
調(diào)用函數(shù)
let result = doFilter(products, Conditions); console.log(result);
輸出

代碼的擴(kuò)展性和可維護(hù)性都很好,只要保證篩選條件中的type字段在商品數(shù)據(jù)中一致都可以篩選,比如將篩選條件改為
let Conditions = {
ranges: [
{
type: 'price',
low: 3000,
high: 6000
}
],
chooses: [
{
type: 'name',
value: 'iPhone'
}
]
}
輸出

搜索匹配等一些地方也需要優(yōu)化,是否區(qū)分大小寫、是完全匹配還是模糊匹配等。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
使用IE的地址欄來(lái)輔助調(diào)試Web頁(yè)腳本
使用IE的地址欄來(lái)輔助調(diào)試Web頁(yè)腳本...2007-03-03
Javascript 對(duì)象(object)合并操作實(shí)例分析
這篇文章主要介紹了Javascript 對(duì)象(object)合并操作,結(jié)合實(shí)例形式分析了javascript基于jQuery的extend方法、對(duì)象屬性、遍歷賦值等操作實(shí)現(xiàn)對(duì)象合并相關(guān)操作技巧與使用注意事項(xiàng),需要的朋友可以參考下2019-07-07
layui 實(shí)現(xiàn)table翻頁(yè)滾動(dòng)條位置保持不變的例子
今天小編就為大家分享一篇layui 實(shí)現(xiàn)table翻頁(yè)滾動(dòng)條位置保持不變的例子,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來(lái)看看吧2019-09-09
基于JS實(shí)現(xiàn)一個(gè)簡(jiǎn)單的投票demo
這篇文章主要介紹了如何利用JavaScript實(shí)現(xiàn)一個(gè)簡(jiǎn)單的投票demo,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)有一定參考價(jià)值,需要的可以參考一下2022-06-06
教你如何自定義百度分享插件以及bshare分享插件的分享按鈕
在項(xiàng)目中我們常用到百度分享插件或者bshare分享插件,雖然官方都有自定義按鈕的功能,但是畢竟還是只有少數(shù)幾種,我們?nèi)绾蝸?lái)制作有自己特色的分享按鈕呢?2014-06-06
JavaScript 替換所有匹配內(nèi)容及正則替換方法
這篇文章主要介紹了JavaScript 替換所有匹配內(nèi)容,文中給大家提到了使用正則表達(dá)式替換方法,通過實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2020-02-02
JavaScript實(shí)現(xiàn)淺拷貝與深拷貝的方法分析
這篇文章主要介紹了JavaScript實(shí)現(xiàn)淺拷貝與深拷貝的方法,結(jié)合實(shí)例形式總結(jié)分析了JavaScript淺拷貝與深拷貝的定義與使用方法,需要的朋友可以參考下2018-07-07

