vue项目 解决有多个el-select需要联动时,调用混乱
痛点:写一堆 handleA/handleB/handleC 重复代码、层级越多越乱;切换、回显两套逻辑分开维护容易出错。
核心思路:用 watch 监听选中值,统一触发下级数据加载 ,所有联动逻辑收敛一处,不用在每个 @change 写业务。
整体设计
- 下拉选中值统一放在
form对象; - 每一级选项数组、loading统一命名规范;
watch监听上级选中值自动刷新下级,清空下级值;- 抽通用异步加载方法,loading、异常处理;
- change 只做一件事:赋值(甚至可以不写 change,v-model 自动触发 watch);
- 编辑回显串行执行,复用同一套加载逻辑,无重复代码。
- html
html
<!-- A一级 -->
<el-select
v-model="form.a"
placeholder="请选择A"
:loading="loading.a"
>
<el-option v-for="item in opt.a" :key="item.id" :label="item.name" :value="item.id"/>
</el-select>
<!-- B二级依赖A -->
<el-select
v-model="form.b"
placeholder="请选择B"
:loading="loading.b"
:disabled="!form.a || opt.b.length === 0"
>
<el-option v-for="item in opt.b" :key="item.id" :label="item.name" :value="item.id"/>
</el-select>
<!-- C三级依赖B -->
<el-select
v-model="form.c"
placeholder="请选择C"
:loading="loading.c"
:disabled="!form.b || opt.c.length === 0"
>
<el-option v-for="item in opt.c" :key="item.id" :label="item.name" :value="item.id"/>
</el-select>
- data
js
data() {
return {
form: {
a: "",
b: "",
c: ""
},
// 各级下拉选项
opt: {
a: [],
b: [],
c: []
},
// 加载状态,防止重复请求
loading: {
a: false,
b: false,
c: false
},
// 层级顺序,用于批量清空下级
levelList: ["a", "b", "c"]
}
},
created() {
// 初始化加载一级A
this.getList("a")
}
- methods
js
methods: {
/**
* 通用请求下拉数据
* @param level 当前层级 a/b/c
* @param parentVal 上级选中值
*/
async getList(level, parentVal = null) {
// 接口映射,新增层级只在这里加一行
const apiMap = {
a: this.$api.getAList,
b: this.$api.getBList,
c: this.$api.getCList
}
const api = apiMap[level]
if (!api) return
this.loading[level] = true
try {
let res
if (level === "a") {
// 一级无父参数
res = await api()
} else {
// 二级/三级带上级ID请求
res = await api({ parentId: parentVal })
}
this.opt[level] = res.data || []
} catch (err) {
console.error(`${level}下拉请求失败`, err)
this.opt[level] = []
} finally {
this.loading[level] = false
}
},
/**
* 清空当前层级之后所有下级的值和选项
* @param level 当前操作层级
*/
clearChild(level) {
const index = this.levelList.indexOf(level)
if (index === -1) return
// 遍历下级全部清空
for (let i = index + 1; i < this.levelList.length; i++) {
const key = this.levelList[i]
this.form[key] = ""
this.opt[key] = []
}
// 清除表单校验红提示
this.$refs.form?.clearValidate()
},
/**
* 编辑回显入口,串行加载下级数据
*/
async setEditRow(row) {
const { a, b, c } = row
// 赋值A,watch自动清空并请求B
this.form.a = a
await this.$nextTick()
await this.getList("b", a)
// 赋值B,watch自动清空并请求C
this.form.b = b
await this.$nextTick()
await this.getList("c", b)
this.form.c = c
}
}
- watch
js
watch: {
"form.a"(val) {
// 切换A,清空B、C
this.clearChild("a")
if (!val) return
// 请求B列表
this.getList("b", val)
},
"form.b"(val) {
// 切换B,清空C
this.clearChild("b")
if (!val) return
// 请求C列表
this.getList("c", val)
}
}