1. 程式人生 > >JS前端資料多條件篩選

JS前端資料多條件篩選

JS前端資料多條件篩選

有時候也會需要在前端進行資料篩選,增強互動體驗。當資料可用的篩選條件較多時,把邏輯寫死會給後期維護帶來很大麻煩。下面是我自己寫的一個簡單的篩選器,篩選條件可以根據資料包含的欄位動態設定。

仿照京東的篩選條件,這裡就取價格區間和品牌作為測試。

程式碼

程式碼中主要使用js的過濾器Array.prototype.filter,該方法會對陣列元素進行遍歷檢查,返回一個符合檢查條件的新陣列,不會改變原陣列。

// 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]

有了這個方法,篩選資料方便了很多,下面先定義一個商品類。

// 定義商品類
function Product(name, brand, price) {
    this.name = name;  // 名稱
    this.brand = brand;   // 品牌
    this.price = price;  // 價格
}

建立一個過濾器物件,把所有過濾資料的方法放在裡面。為了能自動適配不同的篩選條件,將篩選條件分為兩個大類,一個是區間型別rangesFilter

,如:品牌、記憶體等;一個是選擇型別choosesFilter,如:價格、螢幕尺寸等。

不同大類同時篩選時,進行的是與邏輯,每個大類在上一個大類篩選結果上進行篩選。比如我要篩選2000-5000塊的華為手機,先呼叫rangesFilter篩選products並返回結果result1,然後用choosesFilter篩選result1並返回結果resulte2

當然,如果還有其它大類,不一定是與邏輯,再另行處理。

// 商品篩選器
const ProductFilters = {
    /**
     * 區間型別篩選
     * @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) { } }

區間型別的篩選,程式碼如下。

// 區間型別條件結構
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 {
            /**
             * 迴圈多個區間條件,
             * 每種區間型別應該只有一個,
             * 比如價格區間不會有1000-2000和4000-6000同時需要的情況
             */
            for (let range of ranges) {
                // 多個不同型別區間是與邏輯,可以直接賦值給自身
                products = products.filter(function (item) {
                    return item[range.type] >= range.low && item[range.type] <= range.high;
                });
            }
            return products;
        }
    }

選擇型別篩選:

// 選擇型別條件結構
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 {
            /**
             * 選擇型別條件是或邏輯,使用陣列連線concat
             */
            for (let choice of chooses) {
                tmpProducts = tmpProducts.concat(products.filter(function (item) {
                    return item[choice.type].indexOf(choice.value) !== -1;
                }));
            }
        }
        return tmpProducts;
    }

定義一個執行函式doFilter()

function doFilter(products, conditions) {
    // 根據條件迴圈呼叫篩選器裡的方法
    for (key in conditions) {
        // 判斷是否有需要的過濾方法
        if (ProductFilters.hasOwnProperty(key + 'Filter') && typeof ProductFilters[key + 'Filter'] === 'function') {
            products = ProductFilters[key + 'Filter'](products, Conditions[key]);
        }
    }
    return products;
}
// 將兩種大類的篩選條件放在同一個物件裡
let Conditions = {
    ranges: [
        {
            type: 'price',
            low: 3000,
            high: 6000
        }
    ],
    chooses: [
        {
            type: 'brand',
            value: '華為'
        }
    ]
}

測試

建立10個商品資料,以及篩選條件

// 商品陣列
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: '蘋果'
        }
    ]
}

呼叫函式

let result = doFilter(products, Conditions);
console.log(result);

輸出

image.png

程式碼的擴充套件性和可維護性都很好,只要保證篩選條件中的type欄位在商品資料中一致都可以篩選,比如將篩選條件改為

let Conditions = {
    ranges: [
        {
            type: 'price',
            low: 3000,
            high: 6000
        }
    ],
    chooses: [
        {
            type: 'name',
            value: 'iPhone'
        }
    ]
}

輸出

image.png

搜尋匹配等一些地方也需要優化,是否區分大小寫、是完全匹配還是模糊匹配等。