uni.showLoading({ title: '加载中',mask:true });//防止连续二次点击
处理后:用uni.hideLoading()清除遮罩层
但只能点击一次,如果不是点击马上跳转的话,或者有检测条件的话,就不能用该方法
以下以封装一个button为例,详细说明异步处理防二次点击的方法,该组件除了防二次点击外,还包含uni-app原生button组件的功能:
<template>
<button
:size="size"
:type="type"
:plain="plain"
:disabled="disabledData"
:loading="loadingData"
:form-type="formType"
:open-type="openType"
:hover-class="hoverClass"
:hover-start-time="hoverStartTime"
:hover-stay-time="hoverStayTime"
:class="className"
:style="optionstyle"
@click="clickButton"
>
<text>{{text}}</text>
</button>
</template>
<script>
export default {
props: {
className: String ,//类名
options: Object, //设置按钮的文字颜色、背景颜色、文字大小、弧度
/* 例如:
:options="{cl:'#666',bc:'#fff',fs:'28',lh:'2.2',bd:'var(--mainColor)',br:'10',pl:'10',pr:'10'}",
cl:文字颜色(默认值#333333),
bc:背景颜色(默认值#ffffff),
fs:文字大小(单位rpx,默认值28),
lh:X倍行距,例如lh:'2.2'就是2.2倍行距(默认值normal),可以传px,如:lh:'44px',lh:'44rpx'
bd:border线颜色,例如:bd:'var(--mainColor)'(border颜色为主题色),当不传bd值时,默认值border=0。当传bd值时,border默认是1px,
bdSet:自定义border线(当有bdSet值时,bd值会失效),例如:bdSet:2px solid var(--mainColor)
br:弧度(默认值0),
pl:padding-left,默认值0,单位:rpx
pr:padding-right,默认值0,单位:rpx
*/
text:{//按钮里的文字,必传
type: String,
default: ''
},
time:{//防二次点击的默认时间,默认单位是毫秒。
type: Number,
default: ''
},
clickBtn:Function,//接收外面的方法,因为存在异步的要求,所以不用this.$emit('clickBtn')来传递值
size: {//按钮的大小:default:默认大小; mini:小尺寸
type: String,
default: 'default'
},
type: {//按钮的样式类型:default:白色; warn:红色; primary:微信小程序为绿色,App、H5、百度小程序、支付宝小程序为蓝色,头条小程序为红色,QQ小程序为浅蓝色
type: String,
default: 'default'
},
plain: {//按钮是否镂空,背景色透明。
type: Boolean,
default: false
},
disabled: {//是否禁用
type: Boolean,
default: false
},
loading: {//名称前是否带 loading 图标
type: Boolean,
default: false
},
formType: {//用于 <form> 组件,点击分别会触发 <form> 组件的 submit/reset 事件
type: String,
default: ''
},
openType: {//开放能力。contact:打开客服会话,share:触发用户转发,getUserInfo:获取用户信息(手机号、头像、昵称等),getPhoneNumber:获取用户手机号,launchApp:打开APP,openSetting:打开授权设置页
type: String,
default: ''
},
hoverClass: {//指定按钮按下去的样式类。当 hover-class="none" 时,没有点击态效果
type: String,
default: 'button-hover'
},
hoverStartTime: {//按住后多久出现点击态,单位毫秒
type: Number,
default: 20
},
hoverStayTime: {//手指松开后点击态保留时间,单位毫秒
type: Number,
default: 70
},
},
data() {
return {
allowClick:true,//记录是否允许点击按钮(防二次点击用)
disabledData:this.disabled,//点击后,异步请求完后,才允许点击
loadingData:this.loading,//
};
},
computed: {
// 由于:style只能绑定一个值(用官方写法,只有最后一个值会生效),所以要将所有值集中处理
optionstyle() {
let optionsArr = []
// 处理按钮里的文字颜色
let color1 = ''
if (this.options&&this.options.cl) {
color1 = `color:${this.options.cl}`
optionsArr.push(color1)
}else{
color1 = "color:#333333"
optionsArr.push(color1)
}
// 处理按钮背景颜色
if(!this.plain){//如果没有设置透明,才显示背景
let backgroundColor1 = ''
if (this.options&&this.options.bc) {
backgroundColor1 = `background-color:${this.options.bc}`
optionsArr.push(backgroundColor1)
}else{
backgroundColor1 = "background-color:#ffffff"
optionsArr.push(backgroundColor1)
}
}
// 处理按钮文字大小
let fontSize1 = ''
if (this.options&&this.options.fs) {
fontSize1 = `font-size:${this.options.fs}rpx`
optionsArr.push(fontSize1)
}else{
fontSize1 = "font-size:28rpx"
optionsArr.push(fontSize1)
}
// 处理行距
let lineHeight1 = ''
if (this.options&&this.options.lh) {
lineHeight1 = `line-height:${this.options.lh}`
optionsArr.push(lineHeight1)
}else{
lineHeight1 = "line-height:normal"
optionsArr.push(lineHeight1)
}
// 处理border线
let border1 = ''
if(this.options&&this.options.bdSet){
border1 = `border:${this.options.bdSet}`
optionsArr.push(border1)
}else if (this.options&&this.options.bd) {
border1 = `border:1px solid ${this.options.bd}`
optionsArr.push(border1)
}else{
border1 = "border:0"
optionsArr.push(border1)
}
// 处理border线弧度
let borderRadius1 = ''
if (this.options&&this.options.br) {
if (this.options.br.indexOf("%")>-1) {
borderRadius1 = `border-radius:${this.options.br}`
}else{
borderRadius1 = `border-radius:${this.options.br}rpx`
}
optionsArr.push(borderRadius1)
}else{
borderRadius1 = "border-radius:0"
optionsArr.push(borderRadius1)
}
// 处理padding-left
let paddingLeft = ''
if (this.options&&this.options.pl) {
paddingLeft = `padding-left:${this.options.pl}rpx`
optionsArr.push(paddingLeft)
}else{
paddingLeft = "padding-left:0"
optionsArr.push(paddingLeft)
}
// 处理padding-left
let paddingRight = ''
if (this.options&&this.options.pr) {
paddingRight = `padding-right:${this.options.pr}rpx`
optionsArr.push(paddingRight)
}else{
paddingRight = "padding-right:0"
optionsArr.push(paddingRight)
}
return optionsArr.toString().replace(/,/g, ';')
},
},
methods: {
async clickButton(){
this.disabledData=true
this.loadingData = true
if(this.time){
await this.clickBtn()
setTimeout(()=>{
this.disabledData=false
this.loadingData = false
},this.time)
}
if(!this.time){
await this.clickBtn()
this.disabledData=false
this.loadingData = false
}
},
}
};
</script>
<style lang="stylus" scoped>
// 备注:rpx传值的话要写在HTML内联里,不然会出现先换算,再拿值,就会rpx值永远也不会根据屏幕大小来换算
// button{
// &[loading]:before {width: 25px;height: 25px;};
// }
</style>
一、有定时器的,如:
HTML里:
底部透明的“搜索”按钮,定时器::time="1000"异步方法完成后再等1秒才能点击按钮,loading时间为:1秒+异步方法的运行时间
<ls-button class="w-auto flex-center" :text="'搜索'" :plain="true" :clickBtn="searchSeller" :time="1000" :options="{cl:'#ffffff',lh:'44px',pr:'10'}"/>
JS里(注意:要用Promise异步处理,来防止重复点击问题--就算是设置了time,也要用Promise异步处理):
searchSeller(){
return new Promise((resolve, reject) => {
appShopList.loadListByPage( this,this.params, {complete(){resolve(true)}} )
})
},
二、没有定时器的,如:
HTML里:
显示灰色字、白色背景、28rpx字体、2.2倍行距、绿色边框、10rpx圆角 的“搜索”按钮
<ls-button :className="'w-100'" :text="'搜索'" :clickBtn="searchSeller" :options={cl:'#666',bc:'#fff',fs:'28',lh:'2.2',bd:'var(--mainColor)',br:'10'}/>
快速点击按钮会重复多次调用接口,防止出现这样的情况
全局定义,方便调用
新建plugins.js
export default {
install (Vue) {
// 防重复点击(指令实现)
Vue.directive('preventReClick', {
inserted (el, binding) {
el.addEventListener('click', () => {
if (!el.disabled) {
el.disabled = true
setTimeout(() => {
el.disabled = false
}, binding.value || 3000)
}
})
}
})
}
}
在main.js引用
import preventReClick from '@/utils/plugins.js';Vue.use(preventReClick);
按钮调用直接加v-preventReClick
<el-button type="prismary" style="width:100%;" @click="handleSubmit" v-preventReClick></el-button>