最近的项目中有这么一个需求
先解释一下需求
顶部是一个多级联动的组件,用来选择学段,年级和科目,同时左侧的教材和知识点的树形结构受到顶部三个字段的影响,随之变动而变动
顶部的联动解决方案是使用 watch 监听,这应该是个很常见的方案,不多赘述
主要是左侧与顶部的联动,因为这是两个组件,首先要解决传值的问题,我的第一想法是vuex,但感觉有点繁琐,后来发现了 一个组件叫做 vue-communication 地址如下
https://www.npmjs.com/package/vue-communication
这个组件主要解决的就是跨组件监听和传值,我查看了文档发现
ok 非常完美
直接上手,具体安装引入和使用可以查看文档,非常简单
mounted() {
var self = this;
this.$sender("watch-SideBar-Tab", "activeSubjectId", function (nv, ov) {
console.log("我是sidebar");
if (nv !== ov) {
getKnowLedgeTree(nv).then((res) => {
res.data.forEach((item) => {
self.$set(item, "icon", "iconfont icon-wenjian");
});
self["_data"]["menuListForKnowledge"] = res.data;
});
}
});
}
这里面要注意一点 this.$sender 的回调中获取不到 this 可以是定义一个变量等于 this
var self = this
因为左侧导航栏的知识点只和顶部的科目有关,所以到这一步确实成功了,知识点的树形结构会随着科目的变化而变化
但是我在对接教材的时候发现,教材是受两个变量的影响除了科目 还有一个年级
这就说明我们需要监听顶部组件的两个变量
但是文档里并没有写可以监听多个变量,我试着将两个变量组合成一个object,但是组件报错,只能接受一个基本类型的数据,不能接受引用类型的数据,我又试着再写一个
this.$sender,同时在顶部组件再写一个 $receiver,组件再次报错,也就是说组件只能监听一个变量?
摸索半天没有摸索出跨组件监听如何监听多个变量的写法
这时我发现组件还有个发送数据的方法,并且可以发送多次
我想了下,既然左侧组件要监听顶部组件中的多个数据,那么我在顶部组件中先对我要监听的多个数据进行监听 (watch)然后,再将值发送给左侧组件不是一个效果吗
ok,直接上手
顶部组件代码
//顶部组件
watch: {
activeStageId: async function (val) {
// console.log(val);
const gradeRes = await this.getGrade(val);
this.gradeList = gradeRes.data.gradeList;
},
activeGradeId: async function (val, ov) { //需要监听的 年级Id
// console.log(val);
// console.log(ov);
const subjectRes = await this.getSubject(val);
this.subjectList = subjectRes.data;
this.$sender('data-SideBar-Tab', //发送数据 (年级id改变)
{graN: this.activeGradeId, graO: ov, sub: this.activeSubjectId})
},
activeSubjectId: async function(val, ov) { //需要监听的 科目Id
// const editionRes = await this.getBookEdition(val)
// const knowLedgeRes = await this.getKnowLedgeTree(val)
this.$sender('data-SideBar-Tab', //发送数据 (科目id改变)
{subN: this.activeSubjectId, subO: ov, gra: this.activeGradeId})
// console.log(knowLedgeRes)
}
},
左侧组件代码
created() {
let self = this;
this.$receiver("data-SideBar-Tab", function (data) {
if (data.graN) {
// console.log(data, '年级修改');
self.getBookEdition(data.sub, data.graN)
//说明年级修改
} else if (data.subN) {
// console.log(data, '科目修改');
//科目修改
getKnowLedgeTree(data.subN).then((res) => {
res.data.forEach((item) => {
self.$set(item, "icon", "iconfont icon-wenjian");
});
self["_data"]["menuListForKnowledge"] = res.data;
});
self.getBookEdition(data.subN, data.gra)
}
});
},
这里还要说明一点,在顶部导航中可以写多个
this.$sender
用来发送多个数据
但是在接受数据的组件中只需要写一次
this.$receiver
这个 receiver 会多次触发,每次触发都会获取到传过来的数据
也就是说年级改变的时候 会触发一次 receiver 获取到新的年级id
科目改变的时候 还会触发一次 receiver 获取到新的科目id
你可以将传过来的数据添加自定义key值用来区分到底传过来的是什么
就像这一段
this.$sender('data-SideBar-Tab', //发送数据
{subN: this.activeSubjectId, subO: ov, gra: this.activeGradeId})
虽然写在created里,但是这个会多次触发,不用担心
拿到数据就可以做接下来的操作了,获取教材树形结构的数据
再说个问题:
有可能只切换学科,不切换年级以及另一种切换年级不切换学科,这种情况不常见,切换年级会自动选择该年级的第一门学科,
按道理各年级的科目id应该是不一致的,但是如果有年级的相同科目的id是相同的话会出现一个问题,我在测试的时候就遇到了
回顾一下我们监听年级和科目id的代码
1.在顶部组件中先监听,一旦改变就发送给左侧组件
2.在左侧组件中接受
现在问题就是如果相同年级切换科目时,我在改变科目的时候,年级id可能出现不会改变的情况,那么左侧组件就获取不到传过来的 年级id,那调试接口的时候可能 年级id 就为undefined,所以我在传值的时候,在科目id改变时将当前的年级id一起传过去,防止年级id没有变化,没变就用当前值,在年级id改变时将当前的科目id也传过去,防止科目id没变化
this.$sender('data-SideBar-Tab', //发送数据 (年级id改变)
{graN: this.activeGradeId, graO: ov, sub: this.activeSubjectId})
// sub 就是当前科目id
this.$sender('data-SideBar-Tab', //发送数据 (科目id改变)
{subN: this.activeSubjectId, subO: ov, gra: this.activeGradeId})
//gra就是当前年级id