针对按钮以及非按钮元素防止连续点击的处理方法
使用方法
- 可参考文档看
v-focus
例子 - 对普通 DOM 元素进行底层操作的时候可用到自定义指令,它们可以用于操纵DOM、响应事件和修改元素样式等操作
- 一般在nuxt脚手架的配置文件
nuxt.config.js
中配置plugins
,在plugins/plugins.js
中引入import '@/utils/directives';
,utils/directives.js
中使用Vue.directive
设置全局自定义指令 - 创建基本步骤:
1 | // directive-name 是自定义指令的名称 |
- 应用自定义指令:
1 | <div v-directive-name></div> |
工作场景
- 各函数区别可参考文档-自定义指令-钩子函数
- 期望实现效果:点击按钮要立即执行点击事件
- 处理方式:直接从样式上做限制简单,按钮控制disabled 属性,非按钮则控制CSS3 pointer-events 属性
v-preventReClick
只是防止按钮被连续点击,只控制disable
3s,不是防抖- 比直接对按钮的事件函数用防抖效果要好,直接用防抖则还得额外在页面处理按钮的loading或者disabled展示给用户看?
- 如果做防抖,则还要考虑改写原本的点击事件,比如
@click='func'
改为v-xxx-click='func'
,很麻烦,干脆直接改样式,如果有需要防抖的还是对事件处理函数使用防抖处理
- 注意:
- 使用了addEventListener的,需要加一个 unbind 钩子函数在指令解绑时清除事件监听器,可确保在组件销毁或指令解绑时,移除按钮的事件监听器,避免潜在的内存泄漏问题
防止按钮重复点击(不是防抖)
- 为防止按钮重复点击,增加
v-preventReClick
指令 - 参考
1 | // 创建全局指令 用于防止按钮重复点击 |
1 | <!-- 使用v-preventReClick --> |
- 出现问题:对于button可以使用disabled属性让其不触发,但有些按钮是用 div / span 等这种实现的,disabled属性并不能阻止div的onclick事件,此时可使用
v-pointerReClick
- 解决:设置样式
pointer-events: none
,该样式会将元素设置为不接收鼠标事件,包括点击事件
对非按钮元素点击事件加防抖命令
- CSS3 pointer-events 属性设置元素是否对鼠标事件做出反应
1 | // 用于防止按钮重复点击 可作用于div/span |
1 | <!-- 使用v-pointerReClick --> |
- 出现问题:
- 由于设置为
pointer-events:none
后,相当于该元素已经不存在了,那么这种情况的点击会不会穿透导致点击到它的外层呢? - 结果是肯定的,设置
pointer-events:none
后,点击了子节点是无效的,但同时相当于点击了其父节点
- 由于设置为
- 解决方法:设置修饰符阻止冒泡?行不通,只能在父元素中查子元素pointerEvents未none时return出点击函数,不好做自定义指令,直接用封装的节流函数处理childClick比较方便。如果实在要做,可在自定义指令中使用节流(注意:如果做防抖节流的自定义指令,则还要改写原本的点击事件,比如**
@click='func'
改为v-xxx-click='func'
**,再加上样式控制) - 复杂的解决:只能在父元素中查子元素pointerEvents未none时return出点击函数,不好做自定义指令
1 | parentClick() { |
- 可以放弃自定义指令,直接用封装的节流函数处理childClick,样式另外写
1 | childClick: _.throttle(function(){ |
- 最终解决:自定义指令中使用节流(注意:如果做防抖节流的自定义指令,则还要改写原本的点击事件,比如
@click='func'
改为v-xxx-click='func'
,再加上样式控制)
1 | Vue.directive("throttle-click", { |
1 | .pointer { |
1 | <div @click="parentClick"> |
- 用lodash中节流则event不太好传:
1 | // 能用lodash中节流 |
binding.value()调用组件函数
- 在 Vue 的自定义指令中,通过 binding.value() 可以直接调用指令绑定的处理函数,而不需要使用 this 关键字
- 在指令的 bind 钩子函数中,binding.value 表示指令绑定的值,通常是一个函数。通过调用 binding.value(),就可以直接触发该函数。
- 这是因为在 Vue 的指令系统中,binding.value 属性被设置为绑定指令时提供的值。当你在模板中使用指令时,可以将一个函数作为指令的值传递,并在自定义指令中通过 binding.value() 调用该函数。
- 需要注意的是,通过 binding.value() 调用的函数,其上下文(this)可能会发生变化。如果需要在函数内部使用特定的上下文,可以使用 Function.prototype.bind() 方法来绑定函数的执行上下文
1 | binding.value.bind(context)(); // context 是你希望绑定的执行上下文 |
区分修饰符prevent和stop
- prevent是阻止默认事件
- stop是阻止事件传播