下拉框这个组件用的地方非常多,普通用法就是将数据列表一次性查询渲染,在列表里面直接本地搜索,优点是可缓存、速度快,但在某些场合并不适用,比如要在下拉框中选择一所中国的学校,幼儿园/小学/初中/高中/大学加起来总共31万条数据,一次性不可能在下拉框渲染,缺点有:会卡顿、查询返回全量数据中大部分是不必要的数据。
所以远程搜索这个功能就比较适用这个场景。
- Iview Select组件的简单介绍
- 后端编写学校搜索接口
- 前端编写调用搜索接口的相关方法
- Select组件触发远程搜索
- 编辑时对已选择的数据设置默认值(1个和多个)
一、Iview Select组件的简单介绍
Iview Select组件官方文档:https://v4.iviewui.com/components/select
二、后端编写学校搜索接口
接口说明:参数stage表示学段,取值的含义表示幼儿园、小学、初中、高中、大学,参数keyword表示要搜索的关键字
@GetMapping("/api/v1/school/search")
public Response> searchSchools(@RequestParam("stage") StageEnum stage, @RequestParam("keyword") String keyword) {
return this.success(schoolService.querySchools(stage, keyword));
}
学校信息字段非常多,有30多个,全部都返回是不好的实现,所以这里定义了SchoolVo只返回必要的字段给前端,至于SchoolPo属性虽然很多,但从SQL层实际上查询的也只有需要的字段,其他字段不必返回。
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class SchoolVo {
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long id;
private String name;
private String provinceName;
private String stageName;
}
@Override
public List querySchools(StageEnum stage, String keyword) {
List simplePos = schoolMapper.selectSimpleSchools(stage, keyword);
return JsonUtils.copy(simplePos, SchoolVo.class);
}
@Mapper
public interface SchoolMapper extends BaseMapper {
List selectSimpleSchools(@Param("stage") StageEnum stage, @Param("keyword") String keyword);
}
这里只返回了学校id、学校名称、所在省份名称、学段,匹配使用的模糊搜索,name如果有索引,这里索引会失效,但为了考虑查询性能,这里对整个SQL做了如下优化:
(1)按需查询,网络传输数据量小
(2)使用limit 100取巧,因为该SQL是用来搜索的,如果将搜索到的全部返回,会造成查询慢、传输量大、浪费流量,即便限制500条,渲染到列表也是多余的,这种情况一般是用户搜索的时候,只输入了很少的信息,搜索出来的数据就很多,如果搜索更具体一点的学校名称,查询返回的数据量就会很少了,实际使用中,搜索接口的性能还是可以接受的,毕竟是模糊搜索
三、前端编写调用搜索接口的相关方法
school.searchSchool = (params) => {
return http.get(
'/api/v1/school/search',
params
);
};
export default {school};
代码说明:
Spin组件
:用来在搜索的时候显示加载中的状态
v-model="formData.schoolId"
: 组件与formData.schoolId进行双向绑定
filterable
: 支持关键字过滤
remote
: 支持远程搜索
multiple
: 支持多选
selectedSchool
:当前选中项的中文名称
filter-by-label
:通过名称进行搜索过滤
remote-method
:远程搜索调用的方法,参数是我们输入的内容,而不是双向绑定的schoolId
selectChange
:选中某项时触发该方法,用于设置单选或多选
四、Select组件触发远程搜索
搜索时query是输入的内容,使用setTimeout让搜索间隔500毫秒发起
searchSchool (query) {
console.log('search', query);
if (query) {
this.schoolLoading = true;
setTimeout(() => {
apis.school.searchSchool({'stage': this.selectStage, 'keyword': query}).then(res => {
this.schools = res.body;
}).finally(() => {
this.schoolLoading = false;
});
}, 500);
} else {
this.schools = [];
}
},
五、编辑时对已选择的数据设置默认值(1个和多个)
一般的下拉框设置默认值比较简单,和v-model双向绑定即可默认选中某项,但搜索框默认进来时空的,需要输入内容才会有数据返回,列表才会有数据,所以编辑的时候设置默认值的原理就是对select设置搜索内容》select触发远程搜索》搜索结果默认选中匹配的一项
说明:对this.$refs.school.query设置内容即可触发远程搜索
apis.album.getAlbumModDetail({albumId: albumId}).then(res => {
this.formData = res.body;
// 设置修改的数据
this.formData.schoolId = this.formData.school ? this.formData.school.id : '';
this.$refs.school.query = this.formData.school ? this.formData.school.name : '';
console.log('query=', this.$refs.school.query);
console.log('name=', this.formData.school.name);
});