Vue.js中通过$on方法触发事件时DOM不更新的问题排查
看起来你遇到的问题挺典型的:通过EventBus的currentSong事件触发fetchAlbum时,获取的数据没法更新到DOM,但直接在mounted里调用方法就完全正常。结合你的代码和描述,我来梳理几个可能的原因和对应的解决方案:
1. 先排查fetchAlbum的参数传递问题
你在事件回调里调用了this.fetchAlbum(data),但你的fetchAlbum方法并没有定义接收参数。如果data里包含了请求专辑需要的ID,那你得先把这个ID赋值给组件的this.id,再调用fetchAlbum——不然请求用的还是原来的this.id,返回的数据可能不是你想要的,自然看起来没更新:
Event.$on('currentSong', (data) => { // 假设data里包含专辑ID字段,比如data.albumId this.id = data.albumId; this.fetchAlbum(); })
如果data本身就是专辑ID,那就直接this.id = data再调用方法就行。
2. 调整EventBus事件的触发顺序
你在mounted里先执行了Event.$emit('requestCurrentTrack'),之后才注册currentSong的监听。如果requestCurrentTrack的处理是同步触发currentSong事件,那此时你的组件还没完成监听注册,事件会直接丢失,fetchAlbum根本没被调用。
解决方法很简单,先注册监听,再触发请求:
mounted(){ // 先注册监听事件 Event.$on('currentSong', (data) => { this.id = data; this.fetchAlbum(); }); // 再触发请求事件 Event.$emit('requestCurrentTrack'); this.fetchAlbum(); },
3. 确保Vue能检测到数据变化(响应式排查)
虽然你直接赋值this.tracks = response.data[0]和this.album = response.data[1][0]通常能被Vue的响应式系统捕捉到,但如果返回的数据是非响应式的对象/数组(比如来自原生JS对象或者第三方库),可以试试用Vue.set或者重新创建数组/对象来强制触发响应:
import Vue from 'vue'; methods:{ fetchAlbum(){ axios.get('/api/album/'+this.id).then((response)=>{ // 用Vue.set更新对象,确保响应式 Vue.set(this, 'album', response.data[1][0]); // 重新创建数组,强制触发响应式更新 this.tracks = [...response.data[0]]; this.artistName = ... }) } }
要是还不行,可以尝试在数据更新后手动触发强制更新(这个是排查用的应急方案,不推荐作为常规写法):
axios.get('/api/album/'+this.id).then((response)=>{ this.album = response.data[1][0]; this.tracks = response.data[0]; this.artistName = ... // 手动触发组件更新 this.$forceUpdate(); })
4. 确认回调的this指向(虽然你写法没问题,但可以排查)
你用了箭头函数(data) => this.fetchAlbum(data),已经确保了this指向组件实例,这个问题应该不存在,但如果是普通函数的话就会出问题——这条可以作为最后的排查项。
建议先从调整事件注册顺序和参数传递开始排查,这两个是最常见的原因。如果还是不行,再尝试响应式相关的解决方案。
内容的提问来源于stack exchange,提问作者Hamid Hosseini

