對於防止按鈕重複點擊的嘗試

導語:隨着接觸的項目增長,不少項目都是遇到一樣的問題,而每次都是使用一向的手法進行處理。有時候有些方法並非那麼的優雅甚至有些冗餘,因此本身也想開始嘗試不一樣的方法去解決一樣的問題。javascript

我常常在項目中會遇到按鈕重複點擊後引發表單的重複點擊問題。因此針對這個問題,本身嘗試了幾種辦法分別去解決。直接上代碼。前端

1.粗暴簡單辦法

直接定義一個變量,每次點擊事後等全部操做結束後釋放變量。或使用loading防止用戶點擊vue

//* 部分代碼
<script>
export default {
    methods: {
        onSubmit() {
            if (this.lock) return;
            this.lock = true;
            // const load = this.$loading();
            this.$http.create().then((res) => {
                // do something
                this.lock = false;
                // load.close();
            }).catch(() => {
                this.lock = false;
                // load.close();
            })
        }, 
    },
}
</script>
複製代碼

這種辦法簡單粗暴,可是每次須要防止重複點擊的地方,都要去關注lock或者loading的重置,總覺的很囉嗦。也沒辦法好好的抽離出來。(PS:能力有限,本身也沒有想到比較好的辦法在上層優雅的封裝出來)java

2.直接把loading放到http請求中去作,統一封裝方法

//* 部分代碼
...
let load;
http.interceptors.request.use((config) => {
    load = Loading();
    ...
    return config;
}, error => {
    load.close();
    return Promise.reject(error)
});

http.interceptors.response.use((response) => {
    load.close();
    ...
    return response; 
},error => {
    load.close();
    return Promise.reject(error);
});
複製代碼

這種辦法在實際中也用過了一段時間,一開始挺好用的,可是在後面本身弱網測試的時候發現也是會致使重複點擊的狀況。並且在有些時候loading圖並非全部請求都須要,還要去作個是否顯示loading的配置,這樣感受http請求又笨重了,也沒有讓重複點擊功能抽離出來。react

3.裝飾器方法

說到裝飾器,最經典的應用場景就是面向切片編程(AOP),《前端經常使用設計模式(1)--裝飾器(decorator)》juejin.im/post/5cb415… 作出了很棒的理解與應用。得益於ES7和TS,裝飾器在Angular和react中都有不少案例,由於Vue中Class不是必選,因此在Vue中不多看到使用裝飾器的,得益於官方有vue-class-component來使用Class進行建立組件的方法,開始了本身的嘗試之路。編程

lock.js設計模式

export function lock(target, key, desc) {
    const fn = desc.value;
    //* 沒有使用箭頭函數是爲了讓this能指回到vue,這樣就能夠獲取到vue的data,從而作更多的事情,下面會講到
    desc.value = async function() {
        if (this.$lock) return;
        this.$lock = true;
        /** * await fn.apply(this).catch(() => { * this.$lock = false; * }); * this.$lock = false; */
        await fn.apply(this).finally(() => {
            this.$lock = false;
        })
        return target;
    };
}
複製代碼

index.vue微信

<template>
    <!-- do something -->
</template>
<script>
import Vue from 'vue';
import Component from 'vue-class-component';
import { lock } from './lock';

@Component
export default class extends Vue {
    @lock
    async onSubmit() {
        await this.$http.create();
        // do something
    }
}
</script>
複製代碼

感受這樣就徹底抽離了重複點擊的功能(PS:好像是這樣的),也能獨立測試,想在哪裏用就在哪裏用。感受不足的是,裝飾器裏須要讓this從新指回vue才能獲取到vue的data網絡

4.觸類旁通

既然重複點擊能夠從業務代碼中抽離出來,那咱們提交表單的字段驗證也就一樣能夠抽離出來了。(PS:全部UI框架都有成熟的form表單驗證組件,就當我是瞎折騰)app

validate.js

export function validate(target, key, desc) {
  const fn = desc.value;

  desc.value = async function () {
    const {
      name, phone,
    } = this.data;
    
    if (!name) {
      return confirm('請輸入您的姓名');
    }
    if (name.length > 20) {
      return confirm('您的姓名不能超過20個字');
    }
    if (!phone) {
      return confirm('請輸入您的電話');
    }
    if (!((/^\d{11}$/.test(phone)))) {
      return confirm('請輸入11位的電話號碼');
    }
    
    await fn.apply(this);
    return target;
  };
}
複製代碼

index.vue

<template>
    <!-- do something -->
</template>
<script>
import Vue from 'vue';
import Component from 'vue-class-component';
import { validate } from './validate';

@Component
export default class extends Vue {
    data = {
        name: '',
        phone: '',
    }
    
    @validate
    async onSubmit() {
        await this.$http.create();
        // do something
    }
}
</script>
複製代碼

5.防抖方法(補充)

有小夥伴說可使用防抖,我的以爲仍是須要看場景,這裏也就列出防抖的方法。

防抖方法是一個很好限制重複事件頻繁觸發的,常常用在scroll、resize事件上,也能夠嘗試用在重複點擊上面。可是若是點擊事件後須要有異步處理,單單使用防抖方法也會沒辦法限制弱網(PS:吐槽一下成都地鐵上移動常常網絡很差)下重複點擊的狀況。如:防抖時間爲1秒,可是請求花掉了2秒才返回數據給前端進行處理,中間產生了時間差,致使用戶有時間重複點擊。因此我的以爲仍是須要配合其它辦法。一樣列出防抖的列子:

throttle.js

const throttle = function(fn, wait, scope) {
    clearTimeout(throttle.timer);
    throttle.timer = setTimeout(function() {
        fn.apply(scope);
    }, wait);
};
複製代碼

index.vue

<template>
    <!-- do something --> </template>
<script>
export default {
    onSubmit() {
        throttle(() => {
            this.$http.create().then((result) => {
                // do something
            });
        }, 1000);
    },
};
</script>
複製代碼

小結:

本文主要是讓本身,經過某個功能對本身代碼進行review和重實現來提升代碼質量,但願各位大佬多多指點。下面是個人微信號,但願和你們多多交流學習。(添加微信請註明來意謝謝!)

相關文章
相關標籤/搜索