select控件的显示问题

前言

在开发的过程中,遇到了这样一个需求:在两个地方需要显示选项,一个是已存储对象的一个固定的属性选项,就好比Student对象的sex属性;另一个是修改界面的下拉框,就好比需要同时显示Student对象的sex属性和Sex枚举类的选项。这个时候就需要想想这两边需要怎么处理才能够同时显示了。

前提条件

我们先说好这个项目的需求背景:

这是一个学生管理系统,能够在列表页面显示每一个学生的性别,点开后可以利用下拉框修改每个学生的性别。

P.S.:此处仅将第一性特征作为判别性别的标准,不考虑政治正确性别。所以在数据库中,仅使用一个int类型进行表示,0表示男,1表示女。

方案一:优先解决固定显示问题(未能完成需求)

由于性别是可选项较少的属性,所以后端直接定义静态变量:

1
2
3
4
public class Sex {
public static final int MALE = 0;
public static final int FEMALE = 1;
}

虽然说这个数字可能不知所云,但起码来说这样使得编码过程中的逻辑清晰,就不需要再查表写代码了。

其实到这一步也还算行。

前端为了方便,直接来一个json

1
2
3
4
{
"0": "男",
"1": "女"
}

到这一步可能就有点爆炸了。

于是我们看看如何在列表中为每一个Student对象显示性别:

1
2
3
4
5
6
7
8
9
10
11
12
13
import { Sex } from '@/assets/sex.json'
export default {
data() {
return {
sex: Sex
}
},
methods: {
showSex(sex) {
return this.sex[sex.toString()]
}
}
}

看起来风平浪静。

在列表中,我们直接上showSex方法:

1
2
3
4
5
<el-table-column label="图像用途" align="center" prop="usage" >
<template slot-scope="scope">
<span>{{ showSex(scope.row.usage) }}</span>
</template>
</el-table-column>

P.S.:需要注意的是,这里用的是RuoYi-Vuevue,所以版本实际上是2.6.12,所以很多语法糖实际上已经标记deprecated了,可能换个版本就会报一堆错。使用这段代码的时候需要注意版本是否对齐。

直到这里,依然没有问题。

但是在select这里爆炸了。

1
2
3
4
<el-select v-model="form.usage" placeholder="请选择性别">
<el-option
v-for="(value, key) in sex" :key="key" :label="value" :value="key"></el-option>
</el-select>

由于这里的json给出来的是类似Python的字典格式,所以这里的v-for只能选择这种写法,而且keyvalue无法调换,一旦调换就会显示NaN。而且,这样写有一个致命的问题:

要么,修改页面无法将传入的0或者1转变为男或者女,要么select的选项与返回值相反。

无论如何,到这一步,是彻底没救了。

方案二:优先解决select显示问题(成功实现需求)

考虑到大量案例都是以valuelabel的形式来显示,所以我们在这里也不再考虑json的写法了,老老实实上数据库。

创建一个新表,这么整:

1
2
3
4
5
6
7
8
9
10
-- MySQL
drop table if exists sex;
create table sex (
option_value int not null comment '选项值',
option_label varchar(50) default '' comment '选项内容',
PRIMARY KEY (option_value)
) engine=innodb charset=gb2312 comment = '选项表';

insert into sex (option_value, option_label) VALUES (0, '男');
insert into sex (option_value, option_label) VALUES (1, '女');

什么mapperservicecontroller都是老生常谈了,不再赘述。

然后给到前端就可以这么整:

1
2
3
4
<el-select v-model="form.usage" placeholder="请选择性别">
<el-option
v-for="item in sex" :key="item.option_value" :label="item.option_label" :value="item.option_value"></el-option>
</el-select>

这下顺眼多了。

经过这么一整,如果传入的数值是0,那么select的选项就是;如果传入的数值是1,那么select的选项就是。这边就简单多了。

那列表呢?

列表就更简单了,这个批量比较少,我们也就不需要整什么map之类的索引,直接全量搜索:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
export default {
data() {
return {
sex: []
}
},
methods: {
initSex() {
// 在这里请求你自己的`controller`接口,并将返回值赋给this.sex
}
// 根据数字查询显示文字
showSex(sex) {
const option = this.sex.find(item => item.value === value)
return option ? option.label : null
}
}
}

于是,列表这边就很简单了:

1
2
3
4
5
<el-table-column label="图像用途" align="center" prop="usage" >
<template slot-scope="scope">
<span>{{ showSex(scope.row.usage) }}</span>
</template>
</el-table-column>

就没什么问题了。