解决的问题
我们经常遇到
点击
按钮来触发某个异步
请求的情况, 比如 提交/确定 等按钮.
但这种情况我们又需要处理一些并发的问题, 防止用户连续频繁的触发异步
其他方案 (只列举几个)
自己设置一个标志位, 来标识是否在请求中, 每次触发后对标志位判断
缺点是需要额外设置标志位字段,重复性代码.降低代码可读性
对点击触发的异步 进行 throttle 处理
throttle设置的时间间隔是固定的, 没法估计请求实际使用的时间, 太短还是会连续触发. 太长体验很差
我的方案 async-click 指令
- vue2:
Vue.directive("async-click", { |
- vue3
app.directive("async-click", {
// 当被绑定的元素插入到 DOM 中时……
created(el, binding) {
// 获取 bind 的异步方案名称
console.debug(binding);
// const fnName = binding;
// 获取具体方法的引用
const fn = binding.value
if (!fn) {
console.error("async-click 指令需要 binding 一个方法");
}
// 设置内部的标志位
let start = false;
el.addEventListener(
"click",
(e: MouseEvent) => {
// 对其他 click 时间阻止
e && e.stopImmediatePropagation();
if (!start) {
// 第一次点
console.debug("click flag ->", start);
start = true;
// 执行,并获得返回值
const rt: Promise<unknown> = fn();
if (!(rt instanceof Promise)) {
console.error("async-click 指令绑定值错误:返回类型必须为 Promise");
}
console.debug(rt);
//! 此处需要特别注意, 必须是 Promise 完成, 不能再某种情况下永远处于 pending 状态
rt.finally(() => {
// promise 结束后重置标志位
console.debug("finally");
start = false;
});
}
},
true
);
}
});
使用侧例子:
`将原来 @click=xxx 的部分替换为 v-async-click=xxx
<van-button
v-async-click="demo"
round
class="pc-submit"
type="primary"
size="normal"
>提交</van-button>
|
未来可扩展部分:
- 针对不同的事件
- 可以带入参数 fn(arg)