【ADD】button新增防抖节流模式+附带案例

This commit is contained in:
zhengliming
2023-12-10 12:46:45 +08:00
parent 0564dcd88a
commit 733e71862a
3 changed files with 376 additions and 293 deletions

View File

@@ -14,7 +14,7 @@
<demo-title title="大小"> <demo-title title="大小">
<view> <view>
<tn-button size="sm" margin="10rpx 10rpx">按钮</tn-button> <tn-button size="sm" margin="10rpx 10rpx" >按钮</tn-button>
<tn-button margin="10rpx 10rpx">按钮</tn-button> <tn-button margin="10rpx 10rpx">按钮</tn-button>
<tn-button size="lg" margin="10rpx 10rpx">按钮</tn-button> <tn-button size="lg" margin="10rpx 10rpx">按钮</tn-button>
<tn-button width="150rpx" height="100rpx" :fontSize="40" margin="10rpx 10rpx">按钮</tn-button> <tn-button width="150rpx" height="100rpx" :fontSize="40" margin="10rpx 10rpx">按钮</tn-button>
@@ -78,6 +78,11 @@
<tn-button :disabled="true" width="100%" height="100rpx" margin="10rpx 0">按钮</tn-button> <tn-button :disabled="true" width="100%" height="100rpx" margin="10rpx 0">按钮</tn-button>
</demo-title> </demo-title>
<demo-title title="防抖节流(默认间隔200ms,这里用1s)">
<tn-button width="100%" height="100rpx" margin="10rpx 0" @click="say('点击了防抖')" :blockTime="1000" scene="debounce">防抖模式</tn-button>
<tn-button width="100%" height="100rpx" margin="10rpx 0" @click="say('点击了节流')" :blockTime="1000" scene="throttle">节流模式</tn-button>
</demo-title>
<view class="tn-padding-bottom-lg"></view> <view class="tn-padding-bottom-lg"></view>
</view> </view>
@@ -97,6 +102,10 @@
} }
}, },
methods: { methods: {
say(msg){
this.$tn.message.toast(msg)
},
} }
} }
</script> </script>

View File

@@ -1,302 +1,348 @@
<template> <template>
<button <button class="tn-btn-class tn-btn" :class="[
class="tn-btn-class tn-btn"
:class="[
buttonClass, buttonClass,
backgroundColorClass, backgroundColorClass,
fontColorClass fontColorClass
]" ]" :style="[buttonStyle]" hover-class="tn-hover" :loading="loading" :disabled="disabled" :form-type="formType"
:style="[buttonStyle]" :open-type="openType" @getuserinfo="handleGetUserInfo" @getphonenumber="handleGetPhoneNumber"
hover-class="tn-hover" @contact="handleContact" @error="handleError" @tap="handleClick">
:loading="loading" <slot></slot>
:disabled="disabled" </button>
:form-type="formType"
:open-type="openType"
@getuserinfo="handleGetUserInfo"
@getphonenumber="handleGetPhoneNumber"
@contact="handleContact"
@error="handleError"
@tap="handleClick"
>
<slot></slot>
</button>
</template> </template>
<script> <script>
import componentsColorMixin from '../../libs/mixin/components_color.js' import componentsColorMixin from '../../libs/mixin/components_color.js'
export default { import {
mixins: [componentsColorMixin], debounceFun,
name: "tn-button", throttleFun
// 解决再微信小程序种自定义按钮无法触发bindsubmit } from '../../libs/function/applyEven.js'
behaviors: ['wx://form-field-button'], let spanTime = 200;
props: { export default {
// 按钮索引,用于区分多个按钮 mixins: [componentsColorMixin],
index: { name: "tn-button",
type: [Number, String], // 解决再微信小程序种自定义按钮无法触发bindsubmit
default: 0 behaviors: ['wx://form-field-button'],
}, props: {
// 按钮形状 default 默认 round 圆角 icon 图标按钮 // 按钮索引,用于区分多个按钮
shape: { index: {
type: String, type: [Number, String],
default: 'default' default: 0
}, },
// 是否加阴影 // 按钮形状 default 默认 round 圆角 icon 图标按钮
shadow: { shape: {
type: Boolean, type: String,
default: false default: 'default'
}, },
// 宽度 rpx或% // 是否加阴影
width: { shadow: {
type: String, type: Boolean,
default: 'auto' default: false
}, },
// 度 rpx或% // 度 rpx或%
height: { width: {
type: String, type: String,
default: '' default: 'auto'
}, },
// 按钮的尺寸 sm lg // 高度 rpx或%
size: { height: {
type: String, type: String,
default: '' default: ''
}, },
// 字体是否加粗 // 按钮的尺寸 sm lg
fontBold: { size: {
type: Boolean, type: String,
default: false default: ''
}, },
padding: { // 字体是否加粗
type: String, fontBold: {
default: '0 30rpx' type: Boolean,
}, default: false
// 外边距 与css的margin参数用法相同 },
margin: { padding: {
type: String, type: String,
default: '' default: '0 30rpx'
}, },
// 是否镂空 // 外边距 与css的margin参数用法相同
plain: { margin: {
type: Boolean, type: String,
default: false default: ''
}, },
// 当plain=true时是否显示边框 // 是否镂空
border: { plain: {
type: Boolean, type: Boolean,
default: true default: false
}, },
// 当plain=true时是否加粗显示边框 // 当plain=true时是否显示边框
borderBold: { border: {
type: Boolean, type: Boolean,
default: false default: true
}, },
// 是否禁用 // 当plain=true时是否加粗显示边框
disabled: { borderBold: {
type: Boolean, type: Boolean,
default: false default: false
}, },
// 是否显示加载图标 // 是否禁用
loading: { disabled: {
type: Boolean, type: Boolean,
default: false default: false
}, },
// 触发form表单的事件类型 // 是否显示加载图标
formType: { loading: {
type: String, type: Boolean,
default: '' default: false
}, },
// 开放能力 // 触发form表单的事件类型
openType: { formType: {
type: String, type: String,
default: '' default: ''
}, },
// 是否阻止重复点击(默认间隔是200ms) // 开放能力
blockRepeatClick: { openType: {
type: Boolean, type: String,
default: false default: ''
} },
}, // 是否阻止重复点击(默认间隔是200ms)
computed: { blockRepeatClick: {
// 根据不同的参数动态生成class type: Boolean,
buttonClass() { default: false
let clazz = '' },
// 按钮形状 //场景如果开启blockRepeatClick这里无效none 不开启防抖节流模式debounce :防抖模式 throttle节流模式
switch (this.shape) { scene:{
case 'icon': type: String,
case 'round': default: 'none'
clazz += ' tn-round' },
break // 防抖节流间隔时间(毫秒)
} blockTime:{
type: Number,
default: 200
}
},
computed: {
// 根据不同的参数动态生成class
buttonClass() {
let clazz = ''
// 按钮形状
switch (this.shape) {
case 'icon':
case 'round':
clazz += ' tn-round'
break
}
// 阴影 // 阴影
if (this.shadow) { if (this.shadow) {
if (this.backgroundColorClass !== '' && this.backgroundColorClass.indexOf('tn-bg') != -1) { if (this.backgroundColorClass !== '' && this.backgroundColorClass.indexOf('tn-bg') != -1) {
const color = this.backgroundColor.slice(this.backgroundColor.lastIndexOf('-') + 1) const color = this.backgroundColor.slice(this.backgroundColor.lastIndexOf('-') + 1)
clazz += ` tn-shadow-${color}` clazz += ` tn-shadow-${color}`
} else { } else {
clazz += ' tn-shadow-blur' clazz += ' tn-shadow-blur'
} }
} }
// 字体加粗 // 字体加粗
if (this.fontBold) { if (this.fontBold) {
clazz += ' tn-text-bold' clazz += ' tn-text-bold'
} }
// 设置为镂空并且设置镂空便可才进行设置 // 设置为镂空并且设置镂空便可才进行设置
if (this.plain) { if (this.plain) {
clazz += ' tn-btn--plain' clazz += ' tn-btn--plain'
if (this.border) { if (this.border) {
clazz += ' tn-border-solid' clazz += ' tn-border-solid'
if (this.borderBold) { if (this.borderBold) {
clazz += ' tn-bold-border' clazz += ' tn-bold-border'
} }
if (this.backgroundColor !== '' && this.backgroundColor.includes('tn-bg')) { if (this.backgroundColor !== '' && this.backgroundColor.includes('tn-bg')) {
const color = this.backgroundColor.slice(this.backgroundColor.lastIndexOf('-') + 1) const color = this.backgroundColor.slice(this.backgroundColor.lastIndexOf('-') + 1)
clazz += ` tn-border-${color}` clazz += ` tn-border-${color}`
} }
} }
} }
return clazz return clazz
}, },
// 按钮的样式 // 按钮的样式
buttonStyle() { buttonStyle() {
let style = {} let style = {}
switch(this.size) { switch (this.size) {
case 'sm': case 'sm':
style.padding = '0 20rpx' style.padding = '0 20rpx'
style.fontSize = '22rpx' style.fontSize = '22rpx'
style.height = this.height || '48rpx' style.height = this.height || '48rpx'
break break
case 'lg': case 'lg':
style.padding = '0 40rpx' style.padding = '0 40rpx'
style.fontSize = '32rpx' style.fontSize = '32rpx'
style.height = this.height || '80rpx' style.height = this.height || '80rpx'
break break
default : default:
style.padding = '0 30rpx' style.padding = '0 30rpx'
style.fontSize = '28rpx' style.fontSize = '28rpx'
style.height = this.height || '64rpx' style.height = this.height || '64rpx'
} }
// 是否手动设置了内边距 // 是否手动设置了内边距
if (this.padding) { if (this.padding) {
style.padding = this.padding style.padding = this.padding
} }
// 是否手动设置外边距 // 是否手动设置外边距
if (this.margin) { if (this.margin) {
style.margin = this.margin style.margin = this.margin
} }
// 是否手动设置了字体大小 // 是否手动设置了字体大小
if (this.fontSize) { if (this.fontSize) {
style.fontSize = this.fontSize + this.fontUnit style.fontSize = this.fontSize + this.fontUnit
} }
style.width = this.shape === 'icon' ? style.height : this.width style.width = this.shape === 'icon' ? style.height : this.width
style.padding = this.shape === 'icon' ? '0' : style.padding style.padding = this.shape === 'icon' ? '0' : style.padding
if (this.fontColorStyle) { if (this.fontColorStyle) {
style.color = this.fontColorStyle style.color = this.fontColorStyle
} }
if (!this.backgroundColorClass) { if (!this.backgroundColorClass) {
if (this.plain) { if (this.plain) {
style.borderColor = this.backgroundColorStyle || '#080808' style.borderColor = this.backgroundColorStyle || '#080808'
} else { } else {
style.backgroundColor = this.backgroundColorStyle || '#FFFFFF' style.backgroundColor = this.backgroundColorStyle || '#FFFFFF'
} }
} }
// 设置阴影 // 设置阴影
if (this.shadow && !this.backgroundColorClass) { if (this.shadow && !this.backgroundColorClass) {
if (this.backgroundColorStyle.indexOf('#') != -1) { if (this.backgroundColorStyle.indexOf('#') != -1) {
style.boxShadow = `6rpx 6rpx 8rpx ${(this.backgroundColorStyle || '#000000')}10` style.boxShadow = `6rpx 6rpx 8rpx ${(this.backgroundColorStyle || '#000000')}10`
} else if (this.backgroundColorStyle.indexOf('rgb') != -1 || this.backgroundColorStyle.indexOf('rgba') != -1 || !this.backgroundColorStyle) { } else if (this.backgroundColorStyle.indexOf('rgb') != -1 || this.backgroundColorStyle.indexOf(
style.boxShadow = `6rpx 6rpx 8rpx ${(this.backgroundColorStyle || 'rgba(0, 0, 0, 0.1)')}` 'rgba') != -1 || !this.backgroundColorStyle) {
} style.boxShadow = `6rpx 6rpx 8rpx ${(this.backgroundColorStyle || 'rgba(0, 0, 0, 0.1)')}`
}
} }
return style return style
}, },
}, },
data() { data() {
return { return {
// 上次点击的时间
clickTime: 0, }
// 两次点击防抖的间隔时间 },
clickIntervalTime: 200 watch:{
} //支持动态修改时间,但是这里是没有做撤销上一次的方法,毕竟这种场景非常少
}, //这里只是防止用户使用时复用了组件,有场景时长要求二次变动,而做的优化
methods: { blockTime:{
// 按钮点击事件 handler(newVal,oldVal){
handleClick() { this.initScene();
if (this.disabled) { }
return },
} },
if (this.blockRepeatClick) { mounted() {
const nowTime = new Date().getTime() this.initScene()
if (nowTime - this.clickTime <= this.clickIntervalTime) { },
return methods: {
} initScene(){
this.clickTime = nowTime // 动态传入blockTime需要重新初始化,参数
setTimeout(() => { //防抖模式
this.clickTime = 0 this.debounceClick=debounceFun(function() {
}, this.clickIntervalTime) this.emitClick();
} }, this.blockTime);
this.$emit('click', { //节流模式
index: Number(this.index) this.throttleClick=throttleFun(function() {
}) this.emitClick();
// 兼容tap事件 }, this.blockTime);
this.$emit('tap', { },
index: Number(this.index) //防抖模式
}) debounceClick:debounceFun(function() {
}, this.emitClick();
handleGetUserInfo({ detail = {} } = {}) { }, spanTime),
this.$emit('getuserinfo', detail); //节流模式
}, throttleClick:throttleFun(function() {
handleContact({ detail = {} } = {}) { this.emitClick();
this.$emit('contact', detail); }, spanTime),
}, emitClick() {
handleGetPhoneNumber({ detail = {} } = {}) { //触发事件
this.$emit('getphonenumber', detail); this.$emit('click', {
}, index: Number(this.index)
handleError({ detail = {} } = {}) { })
this.$emit('error', detail); // 兼容tap事件
}, this.$emit('tap', {
index: Number(this.index)
})
},
// 按钮点击事件
handleClick() {
if (this.disabled) {
return
}
//兼容旧的
if (this.blockRepeatClick) {
this.throttleClick();
return;
}
//普通模式,触发多少次就回调多少次
if(this.scene === 'none'){
this.emitClick();
}else if(this.scene == 'debounce'){
//防抖模式
this.debounceClick();
}else{
//节流模式
this.throttleClick();
}
},
handleGetUserInfo({
detail = {}
} = {}) {
this.$emit('getuserinfo', detail);
},
handleContact({
detail = {}
} = {}) {
this.$emit('contact', detail);
},
handleGetPhoneNumber({
detail = {}
} = {}) {
this.$emit('getphonenumber', detail);
},
handleError({
detail = {}
} = {}) {
this.$emit('error', detail);
},
} }
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.tn-btn {
position: relative;
display: inline-flex;
align-items: center;
justify-content: center;
box-sizing: border-box;
line-height: 1;
text-align: center;
text-decoration: none;
overflow: visible;
transform: translate(0rpx, 0rpx);
// background-color: $tn-mai
border-radius: 12rpx;
// color: $tn-font-color;
margin: 0;
.tn-btn { &--plain {
position: relative; background-color: transparent !important;
display: inline-flex; background-image: none;
align-items: center;
justify-content: center;
box-sizing: border-box;
line-height: 1;
text-align: center;
text-decoration: none;
overflow: visible;
transform: translate(0rpx, 0rpx);
// background-color: $tn-mai
border-radius: 12rpx;
// color: $tn-font-color;
margin: 0;
&--plain {
background-color: transparent !important;
background-image: none;
&.tn-round {
border-radius: 1000rpx !important;
}
}
}
&.tn-round {
border-radius: 1000rpx !important;
}
}
}
</style> </style>

View File

@@ -0,0 +1,28 @@
//防抖
export function debounceFun(func, delay=500) {
//定时器
let timer;
return function(...args) {
// 清除之前设置的定时器
clearTimeout(timer);
timer = setTimeout(() => {
func.apply(this, args);
}, delay);
};
}
//节流
export function throttleFun(func, delay=500) {
//定时器
let timer = null;
return function(...args) {
if(!timer){
timer = setTimeout(() => {
//执行前清空
timer = null;
console.log("执行了")
func.apply(this, args);
}, delay);
}
};
}