需求描述:有时为了方便用户输入,我们会基于数据库中的数据或者用户的历史数据来为用户提供便捷输入的功能。类似于百度的搜索框,你输入关键词后,输入框下回弹出高频搜索或你之前搜索的记录;输入法为我们提供的后续的文字匹配;Excel中,你输入前几个字,也会帮你匹配文件中已经输入的记录。
1.需求分析
首先我们来分析要实现上述效果,需要做的几件事:
1.监听输入框value的结果变化
2.触发函数,根据输入框的value查询匹配结果
3.将匹配结果渲染到列表中,并支持用户通过键盘或者鼠标选择
嗯,也不是很难嘛,和后台交互的接口只需要一个就足够了。
但是、前端需要做这么多事情,是不是有点让你头大!!!
现在,我们可以通过很简单的方式来实现啦,不需要再自己去造轮子了,Vue的组件库已经提供了现成的实现方式。本文以ElementUi为例,来看下如何方便的实现功能。其余UI组件库,也会提供类似的功能,可以去查询对应的官网文档。
2.后端接口
后端仅需提供一个搜索接口,数据库中有如下数据,我们以name字段来作为匹配值。
SQL语句,很简单,就是一条模糊查询的SQL,不过因为使用了前后模糊搜索,索引基本上是废了,如果数据该表数据量非常大,效率会是一个大问题。
SELECT * from supplies where `name` like "%气象%";
还有一点需要注意,返回的结果中需要有value字段,将其中的name字段赋值value字段即可。
3.前端页面
前端页面效果如下图所示,可以通过鼠标、键盘上下键来选择框中的选项。
<template>
<div class="app-container">
<span style="margin-left:120px;margin-right: 20px;width: 100px; display: inline-block;">物资名:</span>
<el-autocomplete
class="inline-input"
v-model="suppliesName"
:fetch-suggestions="querySearchName"
placeholder="请输入内容"
:trigger-on-focus="false"
@select="handleSelect"
style="margin-bottom:30px; width: 15%;"
></el-autocomplete>
<br>
<el-button type="primary" round style="margin-left:280px" @click.native.prevent="commit">添加</el-button>
<el-button type="primary" round style="margin-left:100px" @click.native.prevent="cancel">取消</el-button>
</div>
</template>
上面代码的核心就是el-autocomplete组件,这是一个Element提供的可以辅助输入的输入框,其核心还是一个input,其中的fetch-suggestions用与绑定数据变化后调用的函数,handleSelect用与绑定选中数据触发发的函数。
Vue中的数据定义如下:
data() {
return {
suppliesName: '',
listLoading: true
}
},
核心的querySearchName函数如下,其中的cb(response.data),是将数据返给el-autocomplete组件,组件根据其中的value字段,来渲染出下方的提示框。
querySearchName(queryString, cb){
this.listLoading = true
const queryData = {
name: queryString
}
//此处的调用后端接口按照自己的调用方式写即可
//此处的getSuppliersByName是项目中自己封装的util中的方法
//如果请求方式是post,JSON.stringify(queryData)
//如果请求方式是get,queryData
getSuppliersByName(queryData).then(response => {
console.log("后端返回结果:", response)
//调用 callback 返回匹配结果列表的数据
cb(response.data);
this.listLoading = false
}).catch(function (error) {
console.log(error)
this.listLoading = false
})
},
4.一个完整的demo
下面是这个页面的完整代码,其中的数据为部分数据,后台接口使用js来进行模拟。
<template>
<div class="app-container">
<span style="margin-left:120px;margin-right: 20px;width: 100px; display: inline-block;">物资名:</span>
<el-autocomplete
class="inline-input"
v-model="suppliesName"
:fetch-suggestions="querySearchName"
placeholder="请输入内容"
:trigger-on-focus="false"
@select="handleSelect"
style="margin-bottom:30px; width: 15%;"
></el-autocomplete>
<br>
<el-button type="primary" round style="margin-left:280px" @click.native.prevent="commit">添加</el-button>
<el-button type="primary" round style="margin-left:100px" @click.native.prevent="cancel">取消</el-button>
</div>
</template>
<script>
import {getSuppliersType, getSuppliersByName} from '@/api/supplies'
import {addInOutRecord} from '@/api/record'
import {parseTime} from '@/utils'
import {getTokenByName, getToken} from '@/utils/auth'
import axios from 'axios'
import {Loading} from 'element-ui'
export default {
filters: {
parseTime(timestamp) {
return parseTime(timestamp, null)
}
},
data() {
return {
suppliesName: '',
listLoading: true,
dataList: [
{"id":1,"categoryTypeId":3,"name":"气象雷达","unit":"套","model":"","type":"EQUIPMENT","validPeriod":6,"createTime":"2021-07-04T15:41:19.000+0000","createUserName":"admin","updateTime":"2021-07-11T05:21:47.000+0000","isDeleted":false,"value":"气象雷达"},
{"id":2,"categoryTypeId":3,"name":"自动气象站","unit":null,"model":"","type":"EQUIPMENT","validPeriod":0,"createTime":"2021-07-04T16:00:47.000+0000","createUserName":"admin","updateTime":"2021-07-11T05:12:22.000+0000","isDeleted":false,"value":"自动气象站"},
{"id":6,"categoryTypeId":3,"name":"气象探空仪器","unit":"套","model":"","type":"SUPPLIER","validPeriod":0,"createTime":"2021-07-08T06:23:16.000+0000","createUserName":null,"updateTime":"2021-07-11T05:12:25.000+0000","isDeleted":false,"value":"气象探空仪器"},
{"id":9,"categoryTypeId":3,"name":"气象移动观测设备","unit":"套","model":"","type":"EQUIPMENT","validPeriod":12,"createTime":"2021-07-08T06:23:16.000+0000","createUserName":null,"updateTime":"2021-07-15T14:46:00.000+0000","isDeleted":false,"value":"气象移动观测设备"},
{"id":8,"categoryTypeId":4,"name":"卫星定位测量仪","unit":"套","model":"","type":"EQUIPMENT","validPeriod":24,"createTime":"2021-07-10T17:39:30.000+0000","createUserName":null,"updateTime":"2021-07-10T18:06:45.000+0000","isDeleted":false,"value":"卫星定位测量仪"}
]
}
},
created() {
},
methods: {
querySearchName(queryString, cb){
this.listLoading = true
//存放此次查询结果
let tmpList = []
this.dataList.forEach((item, index) => {
console.log("item.name", item.name)
if(item.name.indexOf(queryString) > -1){
tmpList.push(item)
}
})
console.log("查询返回结果:", tmpList)
// 调用 callback 返回建议列表的数据
cb(tmpList);
this.listLoading = false
},
commit() {
//禁用按钮点击事件
console.log("点击了提交按钮:", this.supplierName)
},
cancel() {
this.$router.go(-1)
},
handleSelect(item) {
console.log("选中了这条记录:", item);
//todo 后续的操作,赋值、查询等
},
}
}
</script>
又到了分隔线以下,本文到此就结束了,本文内容全部都是由博主自己进行整理并结合自身的理解进行总结,如果有什么错误,还请批评指正。
本系列为开发过程中遇到的比较实用的小功能,喜欢的话可以持续关注,如果本文对你有所帮助,还请还请点赞、评论加关注。
有任何疑问,可以评论区留言。