vue-element-admin的v-waves指令失效问题解决(与@click冲突导致水波纹失效)
Bug report(问题描述)当用户给一个元素(如按钮元素)添加v-waves指令后,如果用户再给元素添加一个click事件句柄,而且这个句柄在执行时触发了组件的更新,那么按钮的“波动”效果就会失效。Steps to reproduce(问题复现步骤)我用vue-element-admin项目master分支代码中的 src/views/table/complex-table.vue 页面中的一
Bug report(问题描述)
当用户给一个元素(如按钮元素)添加v-waves
指令后,如果用户再给元素添加一个click
事件句柄,而且这个句柄在执行时触发了组件的更新,那么按钮的“波动”效果就会失效。
Steps to reproduce(问题复现步骤)
我用 vue-element-admin
项目 master
分支代码中的 src/views/table/complex-table.vue 页面中的一个search
按钮作为示例,因为此处就有这个bug
。
- 给按钮元素添加
v-waves
指令:
<el-button v-waves class="filter-item" type="primary" icon="el-icon-search" @click="handleFilter">
Search
</el-button>
- 给按钮元素添加一个
click
事件句柄handleFilter
:
handleFilter() {
this.listQuery.page = 1
this.getList()
},
getList() {
this.listLoading = true // 触发更新
fetchList(this.listQuery).then(response => {
this.list = response.data.items
this.total = response.data.total
// Just to simulate the time of the request
setTimeout(() => {
this.listLoading = false
}, 1.5 * 1000)
})
}
其中 this.listLoading = true 语句触发了页面组件的更新。
- 页面组件的更新触发了
v-waves
指令的update
hook:Vue
文档对自定义指令的钩子函数的描述如下:
update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。
文档说当所在组件的 VNode
更新时调用自定义指令的update
钩子,而我所遇到的情况有所不同。
this.listLoading = true 语句触发的是页面组件的更新,按理说el-button
组件没有资格更新,但事实是v-waves
指令的update
钩子确实被触发了。
忽略这件事情,我们来看v-waves
指令的update
钩子的定义:
update(el, binding) {
el.removeEventListener('click', el[context].removeHandle, false)
el.addEventListener('click', handleClick(el, binding), false)
},
如上所示,第一句删除了按钮元素之前添加的click
事件监听器,从而导致事件监听器从始至终都没有执行,“波动”效果当然也不会出现了。
Screenshot or Gif(截图或动态图)
其中第一次点击未出现“波动”效果,因为它触发了页面更新;而第二次点击没有触发更新,所以出现了“波动”效果。
Link to minimal reproduction(最小可在线还原demo)
vue-element-admin
项目 master
分支中的 src/views/table/complex-table.vue 页面中的 Search
按钮。
My Suggestion
回顾一下发生bug
的整个过程:
- 用户触发按钮的点击事件。
click
事件是一个宏任务源,它发布了两个宏任务:@click
的handler
和v-waves
指令的handler
; @click
的handler
先执行,而它触发了页面组件的更新。页面组件的更新是一个微任务源,它发布了一个更新组件的微任务。由于微任务会在事件循环的末尾执行完,所以会先进行组件的更新,然后才执行v-waves
指令的click handler
;- 页面组件更新时触发了
v-waves
指令的update
钩子,在update
钩子中删除了之前添加的click
事件监听器。
所以,我们只要先执行v-waves
指令的click handler
,再删除click
事件监听器就行了。
一个简单的方法是延迟到一个宏任务中删除监听器:
update(el, binding) {
const removeHandler = el[context].removeHandle
setTimeout(_ => {
el.removeEventListener('click', removeHandler, false)
})
el.addEventListener('click', handleClick(el, binding), false)
},
转载自:https://github.com/panjiachen/vue-element-admin/issues/2785
更多推荐
所有评论(0)