问题描述
当前端使用 ajax
提交一个表单时,因网络缓慢等原因导致数据没有及时返回数据,导致用户没有得到正确的提示,以为未点中提交按钮,进而在此点击提交按钮,进行提交数据(多半会重复多次点击)
解决方法
- 禁用按钮,并添加
loading
提示 - 移除点击事件
- 结合
vue
使用
常规点击请求代码
这里自己封装一个函数来模仿 ajax
请求1 2 3 4 5 6 7 8 9 10
| function ajax() { return new Promise((resolve, reject) => { setTimeout(() => { let res = parseInt(Math.random() * 10) % 2 res === 0 ? resolve(1) : reject(2) }, 2000) }) }
|
理想状态下,点击按钮应返回数据,但因为网络缓慢,所以模拟数据回来要 2s1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| <button id="btn">点击</button> <script> var num = 0
function ajax() { return new Promise((resolve, reject) => { setTimeout(() => { let res = parseInt(Math.random() * 10) % 2 res === 0 ? resolve(1) : reject(2) }, 3000) }) }
const btn = document.getElementById('btn') btn.addEventListener('click', function() { ajax().then(res=> { console.log('数据回来了'); }).catch(e=>{ console.log('数据请求有问题呀'); }) console.log(++num); })
</script>
|
结果,作为新用户的我看到数据没有显示出来,以为没点中按钮,于是又多点了几下按钮。
解决方案
禁用按钮,添加提示 loading
代码思路:将当前点击按钮禁用,并将按钮展示文本信息进行修改
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| <button id="btn">点击</button> <p>0次</p> <script> var num = 0
function ajax() { return new Promise((resolve, reject) => { setTimeout(() => { let res = parseInt(Math.random() * 10) % 2 res === 0 ? resolve(1) : reject(2) }, 3000) }) }
const btn = document.getElementById('btn') var handleClick = function () { btn.setAttribute('disabled', true) btn.innerText = 'loading...'
num++ document.querySelector('p').innerText = `${num} 次`
ajax() .then((res) => { console.log('点击成功: ' + res) }) .catch((e) => { console.log('点击失败: ' + e) }) .finally(() => { btn.removeAttribute('disabled') btn.innerText = '点击' }) } btn.addEventListener('click', handleClick) </script>
|
移除按钮点击事件
换个思路,不妨可以直接将点击事件移除,这样用户也同样不会触发多次点击事件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| <button id="btn">点击</button> <p>0次</p> <script> var num = 0
function ajax() { return new Promise((resolve, reject) => { setTimeout(() => { let res = parseInt(Math.random() * 10) % 2 res === 0 ? resolve(1) : reject(2) }, 3000) }) }
const btn = document.getElementById('btn') var handleClick = function () { btn.removeEventListener('click', handleClick) btn.innerText = '加载中...'
num++ document.querySelector('p').innerText = `${num} 次`
ajax() .then((res) => { console.log('点击成功: ' + res) }) .catch((e) => { console.log('点击失败: ' + e) }) .finally(() => { btn.addEventListener('click', handleClick) btn.innerText = '点击' }) } btn.addEventListener('click', handleClick) </script>
|
以上两种方法结合使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| <button id="btn">点击</button> <p></p> <script> var num = 0
function ajax() { return new Promise((resolve, reject) => { setTimeout(() => { let res = parseInt(Math.random() * 10) % 2 res === 0 ? resolve(1) : reject(2) }, 3000) }) }
const btn = document.getElementById('btn') var handleClick = function () { btn.removeEventListener('click', handleClick) btn.setAttribute('disabled', true) btn.innerText = '加载中...'
num++ document.querySelector('p').innerText = `${num} 次`
ajax() .then((res) => { console.log('点击成功: ' + res) }) .catch((e) => { console.log('点击失败: ' + e) }) .finally(() => { btn.addEventListener('click', handleClick) btn.removeAttribute('disabled') btn.innerText = '点击' }) } btn.addEventListener('click', handleClick) </script>
|
结合vue来使用
这里只是做了一个小的demo来解释下思路,多数情况下会用axios,可选择在封装axios请求时,进行封装这个操作。网上还有一些案例使用了指令来封装,思路有很多。
这里没有使用移除点击事件,可自行选择添加。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>防止用户同一时间内点击多次按钮,发送多次无效数据</title> </head> <body> <div id="root"> <button @click="handleClick" ref="btn">点击</button> <p></p> </div>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.11/vue.min.js"></script> <script> new Vue({ el: '#root', methods: { ajax(button) { let text = '' if (button && button instanceof HTMLElement) { text = button.innerText || '' button.setAttribute('disabled', true) button.innerText = 'loading...' } return new Promise((resolve, reject) => { setTimeout(() => { let res = parseInt(Math.random() * 10) % 2 res === 0 ? resolve(1) : reject(2) }, 1000) }) .then((res) => { if (button) { button.removeAttribute('disabled') button.innerText = text } return res }) .catch((e) => { if (button) { button.removeAttribute('disabled') button.innerText = text } throw e }) }, handleClick() { this.ajax(this.$refs.btn) .then((res) => { console.log('点击成功: ' + res) }) .catch((e) => { console.log('点击失败: ' + e) }) }, }, }) </script> </body> </html>
|