最近在使用vue+iview做一個后臺管理系統(tǒng),在做表格部分時發(fā)現(xiàn)iview的表格并不支持搜索,不過iview易于拓展,可以很方便的拓展出表格搜索功能,比如在iview-admin就存在可搜索表格,但是功能比較基礎(chǔ),而且沒有封裝為單獨組件,接下來我們就一步步的實現(xiàn)一個支持下拉選擇指定列進行搜索的表格搜索組件。完整代碼:https://github.com/shawpo/vue-iview-tableSearch

首先我們可以來看下iview-admin表格搜索的實現(xiàn),以示例中按姓名搜索為例,其實現(xiàn)實現(xiàn)了按姓名搜索。

// 關(guān)鍵代碼
<template>
......
<Input
v-model="searchConName1"
icon="search"
@on-change="handleSearch1"
placeholder="請輸入姓名搜索..."
style="width: 200px"
/>
......
</template>
<script>
......
export default {
......
methods: {
......
search (data, argumentObj) {
let res = data;
let dataClone = data;
for (let argu in argumentObj) {
if (argumentObj[argu].length > 0) {
res = dataClone.filter(d => {
return d[argu].indexOf(argumentObj[argu]) > -1;
});
dataClone = res;
}
}
return res;
},
handleSearch1 () {
this.data1 = this.initTable1;
this.data1 = this.search(this.data1, {name: this.searchConName1});
},
......
},
......
};
</script>
- 首先簡單說明下這個示例的實現(xiàn)流程:將input輸出框的on-change事件與組件的handleSearch1方法綁定,在輸入框內(nèi)容發(fā)生變化時運行handleSearch1 方法。而handleSearch1方法則將表格的初始數(shù)據(jù)數(shù)據(jù)(this.data1)與搜索條件對象(將搜索列與搜索內(nèi)容拼裝成對象形式后)傳遞給search方法執(zhí)行搜索,并將表格數(shù)據(jù)設(shè)置search方法返回搜索結(jié)果。
- 接下來是代碼的說明,從handleSearch1方法開始,其首先將原始的表格數(shù)據(jù)賦值給data1,以保障每次搜索都是從原始表格數(shù)據(jù)中搜索,將搜索列與搜索內(nèi)容拼裝成對象形式作為搜索條件,將然后將data1以及搜索條件對象傳遞給search方法,這里的'name'為表格數(shù)據(jù)中對應(yīng)列內(nèi)容的字段名。接下來就是重要的search方法了,可以看出這個方法是支持多條件(多列)搜索的,其首先對搜索條件對象進行了遍歷,當(dāng)對象的一個屬性的值不沒空時(則說明這個屬性可以作為搜索的一個條件),通過函數(shù)filter對dataClone進行過濾,并將過濾結(jié)果賦值給dataClone以用于下一個循環(huán),循環(huán)完畢后,所有的搜索條件都執(zhí)行完畢,dataClone即為搜索結(jié)果,將其返回即可。
接下來我們就對這個簡單的搜索進行拓展以支持下拉選擇指定列進行搜索并封裝為單獨組件,想要支持這一功能,我們首先需要列名以及表格數(shù)據(jù)中對應(yīng)列內(nèi)容的字段名等信息,而創(chuàng)建iview表格的所需的列配置參數(shù)(columns)中就包含這些信息,因此可以很方便的開發(fā)出適用于iview表格的搜索組件。
- 首先是UI部分
這非常簡單,我們可以使用iview提供的復(fù)合型輸入框輕松實現(xiàn)
<Input
placeholder="請選擇列名并輸入內(nèi)容..."
v-model="searchContent"
@on-change="handleSearch">
<Select slot="prepend" style="width: 80px" v-model="searchColumn">
<Option
v-for="column in searchColumns"
:value="column.key"
:key="column.key">
{{column.title}}
</Option>
</Select>
</Input>
- 完成了UI部分之后就需要為UI提供數(shù)據(jù)完成數(shù)據(jù)綁定,首先是為下拉選擇器提供數(shù)據(jù)
同樣非常簡單,父組件使用時將iview表格的columns參數(shù)對應(yīng)的對象數(shù)組(父組件可對數(shù)組進行處理,過濾不需要支持搜索的列)傳遞過來即可。
// 關(guān)鍵代碼
......
<table-search
......
:searchColumns="searchColumns"
>
</table-search>
......
computed: {
searchColumns: function () {
// 過濾不需要支持搜索的列,這里過濾掉了“狀態(tài)”列
return this.menusColumns.filter( (d) => {
return d['key'] && d['key'] != 'status'
})
}
},
......
- 表格數(shù)據(jù)
要實現(xiàn)搜索,當(dāng)然需要表格數(shù)據(jù),與上面iview-admin的示例不同的是,我們將表單搜索封裝成了單獨組件,因此我們需要從父組件獲取表格數(shù)據(jù),并在完成搜索之后,將父組件的表格數(shù)據(jù)更新為搜索結(jié)果的數(shù)據(jù)。我們可以很容易的想到:使用.sync修飾符從父組件中將表格數(shù)據(jù)傳遞過來,像上面一樣克隆數(shù)據(jù),執(zhí)行搜索,然后通過觸發(fā)事件將父組件的表格數(shù)據(jù)更新為搜索結(jié)果的數(shù)據(jù)即可。沒錯,確實是這樣的,整個流程很簡單,但是這里存在一個問題,父組件的表格數(shù)據(jù)通常是從服務(wù)器中獲取的,存在異步操作。我們需要當(dāng)服務(wù)器端完成異步操作之后再對其進行克隆,否則若克隆的表格數(shù)據(jù)為空,無論如何搜索得到值都為空。
// 父組件
<table-search
:tableData.sync="menusData"
:searchColumns="searchColumns"
>
</table-search>
watch: {
// 因父組件表格數(shù)據(jù)通常存在異步操作
// 需監(jiān)聽props以得到正確的數(shù)據(jù)
tableData: function (newTableData) {
if (newTableData.length > 0 && this.tableDataClone.length == 0) {
this.tableDataClone = newTableData
}
}
}
- 執(zhí)行搜索
這一過程與iview-admin的示例非常相似,不同的是要執(zhí)行搜索的列來自于用戶在下拉選擇中的輸入,因此我們需要獲取用戶輸入并將其處理為搜索條件對象傳遞給search方法執(zhí)行搜索,而搜索完成后我們需要更新父組件表格數(shù)據(jù)。
methods: {
// 表格搜索函數(shù),可支持多列搜索
search: function (data, argumentObj) {
let res = data;
let dataClone = data;
for (let argu in argumentObj) {
if (argumentObj[argu].length > 0) {
res = dataClone.filter(d => {
return d[argu].indexOf(argumentObj[argu]) > -1;
});
dataClone = res;
}
}
return res;
},
handleSearch: function () {
var argumentObjStr = '{"' + this.searchColumn + '": "' + this.searchContent + '"}' // 拼接json
var argumentObj = JSON.parse(argumentObjStr) // 轉(zhuǎn)為對象
var res = this.search(this.tableDataClone, argumentObj) // 執(zhí)行搜索,獲取搜索結(jié)果
this.$emit('update:tableData', res) // 更新表格數(shù)據(jù)為搜索結(jié)果
}
},
結(jié)束