最近在使用vue+iview做一個(gè)后臺(tái)管理系統(tǒng),在做表格部分時(shí)發(fā)現(xiàn)iview的表格并不支持搜索,不過(guò)iview易于拓展,可以很方便的拓展出表格搜索功能,比如在iview-admin就存在可搜索表格,但是功能比較基礎(chǔ),而且沒有封裝為單獨(dú)組件,接下來(lái)我們就一步步的實(shí)現(xiàn)一個(gè)支持下拉選擇指定列進(jìn)行搜索的表格搜索組件。完整代碼:https://github.com/shawpo/vue-iview-tableSearch
首先我們可以來(lái)看下iview-admin表格搜索的實(shí)現(xiàn),以示例中按姓名搜索為例,其實(shí)現(xiàn)實(shí)現(xiàn)了按姓名搜索。
// 關(guān)鍵代碼
<template>
......
<Input
v-model="searchConName1"
icon="search"
@on-change="handleSearch1"
placeholder="請(qǐng)輸入姓名搜索..."
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>
- 首先簡(jiǎn)單說(shuō)明下這個(gè)示例的實(shí)現(xiàn)流程:將input輸出框的on-change事件與組件的handleSearch1方法綁定,在輸入框內(nèi)容發(fā)生變化時(shí)運(yùn)行handleSearch1 方法。而handleSearch1方法則將表格的初始數(shù)據(jù)數(shù)據(jù)(this.data1)與搜索條件對(duì)象(將搜索列與搜索內(nèi)容拼裝成對(duì)象形式后)傳遞給search方法執(zhí)行搜索,并將表格數(shù)據(jù)設(shè)置search方法返回搜索結(jié)果。
- 接下來(lái)是代碼的說(shuō)明,從handleSearch1方法開始,其首先將原始的表格數(shù)據(jù)賦值給data1,以保障每次搜索都是從原始表格數(shù)據(jù)中搜索,將搜索列與搜索內(nèi)容拼裝成對(duì)象形式作為搜索條件,將然后將data1以及搜索條件對(duì)象傳遞給search方法,這里的'name'為表格數(shù)據(jù)中對(duì)應(yīng)列內(nèi)容的字段名。接下來(lái)就是重要的search方法了,可以看出這個(gè)方法是支持多條件(多列)搜索的,其首先對(duì)搜索條件對(duì)象進(jìn)行了遍歷,當(dāng)對(duì)象的一個(gè)屬性的值不沒空時(shí)(則說(shuō)明這個(gè)屬性可以作為搜索的一個(gè)條件),通過(guò)函數(shù)filter對(duì)dataClone進(jìn)行過(guò)濾,并將過(guò)濾結(jié)果賦值給dataClone以用于下一個(gè)循環(huán),循環(huán)完畢后,所有的搜索條件都執(zhí)行完畢,dataClone即為搜索結(jié)果,將其返回即可。
接下來(lái)我們就對(duì)這個(gè)簡(jiǎn)單的搜索進(jìn)行拓展以支持下拉選擇指定列進(jìn)行搜索并封裝為單獨(dú)組件,想要支持這一功能,我們首先需要列名以及表格數(shù)據(jù)中對(duì)應(yīng)列內(nèi)容的字段名等信息,而創(chuàng)建iview表格的所需的列配置參數(shù)(columns)中就包含這些信息,因此可以很方便的開發(fā)出適用于iview表格的搜索組件。
- 首先是UI部分
這非常簡(jiǎn)單,我們可以使用iview提供的復(fù)合型輸入框輕松實(shí)現(xiàn)
<Input
placeholder="請(qǐng)選擇列名并輸入內(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ù)
同樣非常簡(jiǎn)單,父組件使用時(shí)將iview表格的columns參數(shù)對(duì)應(yīng)的對(duì)象數(shù)組(父組件可對(duì)數(shù)組進(jìn)行處理,過(guò)濾不需要支持搜索的列)傳遞過(guò)來(lái)即可。
// 關(guān)鍵代碼
......
<table-search
......
:searchColumns="searchColumns"
>
</table-search>
......
computed: {
searchColumns: function () {
// 過(guò)濾不需要支持搜索的列,這里過(guò)濾掉了“狀態(tài)”列
return this.menusColumns.filter( (d) => {
return d['key'] && d['key'] != 'status'
})
}
},
......
- 表格數(shù)據(jù)
要實(shí)現(xiàn)搜索,當(dāng)然需要表格數(shù)據(jù),與上面iview-admin的示例不同的是,我們將表單搜索封裝成了單獨(dú)組件,因此我們需要從父組件獲取表格數(shù)據(jù),并在完成搜索之后,將父組件的表格數(shù)據(jù)更新為搜索結(jié)果的數(shù)據(jù)。我們可以很容易的想到:使用.sync修飾符從父組件中將表格數(shù)據(jù)傳遞過(guò)來(lái),像上面一樣克隆數(shù)據(jù),執(zhí)行搜索,然后通過(guò)觸發(fā)事件將父組件的表格數(shù)據(jù)更新為搜索結(jié)果的數(shù)據(jù)即可。沒錯(cuò),確實(shí)是這樣的,整個(gè)流程很簡(jiǎn)單,但是這里存在一個(gè)問(wèn)題,父組件的表格數(shù)據(jù)通常是從服務(wù)器中獲取的,存在異步操作。我們需要當(dāng)服務(wù)器端完成異步操作之后再對(duì)其進(jìn)行克隆,否則若克隆的表格數(shù)據(jù)為空,無(wú)論如何搜索得到值都為空。
// 父組件
<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í)行搜索
這一過(guò)程與iview-admin的示例非常相似,不同的是要執(zhí)行搜索的列來(lái)自于用戶在下拉選擇中的輸入,因此我們需要獲取用戶輸入并將其處理為搜索條件對(duì)象傳遞給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)為對(duì)象
var res = this.search(this.tableDataClone, argumentObj) // 執(zhí)行搜索,獲取搜索結(jié)果
this.$emit('update:tableData', res) // 更新表格數(shù)據(jù)為搜索結(jié)果
}
},
結(jié)束