3

vue-async-click

 2 years ago
source link: https://dreambo8563.github.io/2022/03/31/vue-async-click/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

vue-async-click

Posted on 2022-03-31

  |   In vue

解决的问题

我们经常遇到 点击 按钮来触发某个异步请求的情况, 比如 提交/确定 等按钮.

但这种情况我们又需要处理一些并发的问题, 防止用户连续频繁的触发异步

其他方案 (只列举几个)

  • 自己设置一个标志位, 来标识是否在请求中, 每次触发后对标志位判断

    缺点是需要额外设置标志位字段,重复性代码.降低代码可读性

  • 对点击触发的异步 进行 throttle 处理

    throttle设置的时间间隔是固定的, 没法估计请求实际使用的时间, 太短还是会连续触发. 太长体验很差

我的方案 async-click 指令

  • vue2:
Vue.directive("async-click", {
// 当被绑定的元素插入到 DOM 中时……
bind: function (el, binding, vnode) {
// 获取 bind 的异步方案名称
const fnName = binding.expression;
// 获取具体方法的引用
const fn = vnode.context && vnode.context[fnName];
if (!fn) {
console.error("async-click 指令需要 binding 一个方法");
}
// 设置内部的标志位
let start = false;
el.addEventListener(
"click",
e => {
// 对其他 click 时间阻止
e && e.stopImmediatePropagation();
if (!start) {
// 第一次点
console.debug("click flag ->", start);
start = true;
// 执行,并获得返回值
const rt = fn();
if (!(rt instanceof Promise)) {
console.error("async-click 指令绑定值错误:返回类型必须为 Promise");
}

console.debug(rt);
//! 此处需要特别注意, 必须是 Promise 完成, 不能再某种情况下永远处于 pending 状态
rt.finally(() => {
// promise 结束后重置标志位
console.debug("finally");
start = false;
});
}
},
true
);
}
});
  • 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>


methods:{
demo() {
console.info("demo start");
return new Promise(resolve => {
setTimeout(() => {
console.info("demo end");
resolve();
}, 3000);
});
}
}

未来可扩展部分:

  • 针对不同的事件
  • 可以带入参数 fn(arg)

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK