一般来说全局搜索都是由后端负责逻辑的,由于最近想尝试下新的方向,就学着用vue来实现搜索,而后端接口只负责返回所有数据。该功能为在表格里面,搜索符合条件的字段,并重新渲染el-table的 :data=tableData,强行使符合条件的device被渲染出来。重点部门在代码每个method都有注释。
对于搜索框,我采用了el-autocomplete来实现,template的代码如下:
<template>
<div class="handle-box">
<el-autocomplete
v-model="select_word"
clearable
placeholder="筛选关键词"
class="handle-input mr10"
:fetch-suggestions="querySearchAsync"
:trigger-on-focus="false"></el-autocomplete>
<el-button type="primary" icon="search" @click="search">搜索</el-button>
<el-button type="success" @click="reset">重置</el-button>
</div>
</template>
script方面的代码如下:
export default {
data() {
return {
select_word: '',
searchList: [],
timeout: null,
search_result: ''
}
},
mounted() {
this.searchList = this.loadAll()
},
methods: {
// 异步查询
querySearchAsync(queryString, cb) {
var searchList = this.searchList;
var results = queryString ? searchList.filter(this.createFilter(queryString)) : searchList;
this.search_result = results
clearTimeout(this.timeout);
this.timeout = setTimeout(() => {
cb(results);
}, 1);
},
// el-autocomplete只接受value作绑定,所以后端返回数据的时候用value绑定设备的名字,
//后面做全局搜索的时候,不管输入什么,只会出来相应的设备的名字,
//但是该设备绑定其他的信息也可以被搜索到
createFilter(queryString) {
return (select_word) => {
return (select_word.value.toLowerCase().indexOf(queryString.toLowerCase()) === 0 ||
select_word.param.toLowerCase().indexOf(queryString.toLowerCase()) === 0 ||
select_word.no_device.toLowerCase().indexOf(queryString.toLowerCase()) === 0 ||
select_word.name.toLowerCase().indexOf(queryString.toLowerCase()) === 0 ||
select_word.amount.toLowerCase().indexOf(queryString.toLowerCase()) === 0 ||
select_word.unit.toLowerCase().indexOf(queryString.toLowerCase()) === 0 ||
select_word.addr.toLowerCase().indexOf(queryString.toLowerCase()) === 0 ||
select_word.supplier.toLowerCase().indexOf(queryString.toLowerCase()) === 0 );
}
},
loadAll() {
// 直接从后端获取所有数据,return device_list,在mounted阶段让searchList等于这个返回列表
const url = api.get_hardware_all.url
let device_list = []
axios.get(url).then(resp => {
for(let i = 0; i < resp.data.info_list.length; i += 1) {
device_list.push(resp.data.info_list[i])
}
})
return device_list
},
//点击搜索的时候,直接在最后让table data等于这个符合条件的table list,这样el-table渲染的时候就直接只显示出符合条件的选项
search() {
this.is_search = true;
let search_table = []
for (let i = 0; i < this.search_result.length; i += 1) {
const table_data = {
no_device: this.search_result[i].no_device,
name: this.search_result[i].name,
device: this.search_result[i].value,
param: this.search_result[i].param,
amount: this.search_result[i].amount,
unit: this.search_result[i].unit,
addr: this.search_result[i].addr,
supplier: this.search_result[i].supplier
}
search_table.push(table_data)
}
this.tableData = search_table
}
}
}
后端的代码如下:
@hardware_blueprint.route('/get_hardware_all', methods=['GET'])
def get_hardware_all():
try:
devices = db.session.query(Device).all()
info_list = []
ret = status_code.SUCCESS
for i in devices:
info_dict = {
'no_device': i.no_device,
'name': i.name,
'value': i.device,
'param': i.param,
'amount': i.amount,
'unit': i.unit,
'addr': i.addr,
'supplier': i.supplier
}
info_list.append(info_dict)
ret.update({'info_list': info_list})
db.session.close()
return jsonify(ret)
except Exception as e:
print e
return jsonify(status_code.DEVICE_QUERY_ERROR)
这样做的好处是,当在搜索框输想搜的字段时,会远程搜索联想出符合条件(即所有有该字段的设备的名字)出来,可以进行单个搜素,也可以进行全部模糊搜索出所有设备。
而在这里如果不点击联想出来的选项进行直接搜索,就可以获得所有有该字段的选项出来。
模糊搜索
模糊搜索我用el-select组件,后端代码都是一样的,区别就在前端的变化上面:
<div class="handle-box">
<el-select
v-model="select_word"
filterable
clearable
remote
reserve-keyword
placeholder="请输入关键词"
:remote-method="remoteMethod"
:loading="loading">
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
<el-button type="primary" icon="search" @click="search">搜索</el-button>
<el-button type="success" @click="reset">重置</el-button>
</div>
<script>
export default {
data() {
return {
searchList: [],
search_result: '',
options: [],
value: [],
list: [],
loading: false
}
},
mounted() {
this.searchList = this.loadAll()
},
methods: {
reset() {
this.reload()
},
loadAll() {
const url = api.get_hardware_all.url
let device_list = []
axios.get(url).then(resp => {
for(let i = 0; i < resp.data.info_list.length; i += 1) {
device_list.push(resp.data.info_list[i])
}
})
return device_list
},
},
remoteMethod(query) {
if (query !== '') {
this.loading = true;
setTimeout(() => {
this.loading = false;
this.options = this.list.filter(item => {
return item.name.toLowerCase().indexOf(query.toLowerCase()) > -1 ||
item.amount.toLowerCase().indexOf(query.toLowerCase()) > -1 ||
item.addr.toLowerCase().indexOf(query.toLowerCase()) > -1 ||
item.value.toLowerCase().indexOf(query.toLowerCase()) > -1 ||
item.param.toLowerCase().indexOf(query.toLowerCase()) > -1 ||
item.supplier.toLowerCase().indexOf(query.toLowerCase()) > -1 ||
item.unit.toLowerCase().indexOf(query.toLowerCase()) > -1 ||
item.no_device.toLowerCase().indexOf(query.toLowerCase()) > -1;
});
}, 200);
} else {
this.options = [];
}
},
search() {
this.is_search = true;
let search_table = []
for (let i = 0; i < this.options.length; i += 1) {
const table_data = {
no_device: this.options[i].no_device,
name: this.options[i].name,
device: this.options[i].value,
param: this.options[i].param,
amount: this.options[i].amount,
unit: this.options[i].unit,
addr: this.options[i].addr,
supplier: this.options[i].supplier
}
search_table.push(table_data)
}
this.tableData = search_table
}
}
</script>
核心代码差不多都是一样的,只是组建的使用方法不同而已,所以就不做多讲了。
下图是搜索2600后,下方弹框符合条件的搜索选项
当点击搜索后(换了一个搜索条件)就把所有符合条件的选项都渲染在列表里面了。