You've already forked template-MP
195 lines
3.9 KiB
Vue
195 lines
3.9 KiB
Vue
<template>
|
|
<view
|
|
class="custom-button"
|
|
:class="[`custom-button--${type}`, `custom-button--${size}`, { 'custom-button--disabled': disabled, 'custom-button--loading': loading }]"
|
|
@click="handleClick"
|
|
>
|
|
<view class="custom-button__loading" v-if="loading">
|
|
<u-loading-icon mode="circle" size="20" color="#fff" />
|
|
</view>
|
|
<view class="custom-button__content">
|
|
<slot></slot>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, onBeforeUnmount } from 'vue'
|
|
|
|
// 定义props
|
|
const props = defineProps({
|
|
// 按钮类型
|
|
type: {
|
|
type: String,
|
|
default: 'primary', // primary, secondary, danger, ghost
|
|
validator: (value) => ['primary', 'secondary', 'danger', 'ghost'].includes(value)
|
|
},
|
|
// 按钮大小
|
|
size: {
|
|
type: String,
|
|
default: 'medium', // small, medium, large
|
|
validator: (value) => ['small', 'medium', 'large'].includes(value)
|
|
},
|
|
// 是否禁用
|
|
disabled: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
// 是否加载中
|
|
loading: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
// 防抖时间(毫秒)
|
|
debounce: {
|
|
type: Number,
|
|
default: 0
|
|
}
|
|
})
|
|
|
|
// 定义emits
|
|
const emit = defineEmits(['click'])
|
|
|
|
// 防抖定时器
|
|
const debounceTimer = ref(null)
|
|
|
|
/**
|
|
* 处理点击事件
|
|
* @param {Event} e 点击事件对象
|
|
*/
|
|
function handleClick(e) {
|
|
// 如果禁用或加载中,不处理点击
|
|
if (props.disabled || props.loading) {
|
|
return
|
|
}
|
|
|
|
// 如果设置了防抖
|
|
if (props.debounce > 0) {
|
|
if (debounceTimer.value) {
|
|
clearTimeout(debounceTimer.value)
|
|
}
|
|
|
|
debounceTimer.value = setTimeout(() => {
|
|
emit('click', e)
|
|
debounceTimer.value = null
|
|
}, props.debounce)
|
|
} else {
|
|
emit('click', e)
|
|
}
|
|
}
|
|
|
|
// 组件卸载前清除定时器
|
|
onBeforeUnmount(() => {
|
|
if (debounceTimer.value) {
|
|
clearTimeout(debounceTimer.value)
|
|
debounceTimer.value = null
|
|
}
|
|
})
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.custom-button {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
border-radius: 8rpx;
|
|
font-weight: 500;
|
|
text-align: center;
|
|
vertical-align: middle;
|
|
cursor: pointer;
|
|
transition: all 0.2s;
|
|
user-select: none;
|
|
border: 1rpx solid transparent;
|
|
position: relative;
|
|
overflow: hidden;
|
|
|
|
// 主要按钮
|
|
&--primary {
|
|
color: #fff;
|
|
background-color: #1890ff;
|
|
border-color: #1890ff;
|
|
|
|
&:not(.custom-button--disabled):active {
|
|
background-color: #40a9ff;
|
|
border-color: #40a9ff;
|
|
}
|
|
}
|
|
|
|
// 次要按钮
|
|
&--secondary {
|
|
color: #333;
|
|
background-color: #f5f5f5;
|
|
border-color: #d9d9d9;
|
|
|
|
&:not(.custom-button--disabled):active {
|
|
background-color: #e6e6e6;
|
|
border-color: #bfbfbf;
|
|
}
|
|
}
|
|
|
|
// 危险按钮
|
|
&--danger {
|
|
color: #fff;
|
|
background-color: #ff4d4f;
|
|
border-color: #ff4d4f;
|
|
|
|
&:not(.custom-button--disabled):active {
|
|
background-color: #ff7875;
|
|
border-color: #ff7875;
|
|
}
|
|
}
|
|
|
|
// 幽灵按钮
|
|
&--ghost {
|
|
color: #1890ff;
|
|
background-color: transparent;
|
|
border-color: #1890ff;
|
|
|
|
&:not(.custom-button--disabled):active {
|
|
color: #40a9ff;
|
|
border-color: #40a9ff;
|
|
}
|
|
}
|
|
|
|
// 禁用状态
|
|
&--disabled {
|
|
cursor: not-allowed;
|
|
opacity: 0.6;
|
|
}
|
|
|
|
// 加载状态
|
|
&--loading {
|
|
cursor: not-allowed;
|
|
}
|
|
|
|
// 小尺寸
|
|
&--small {
|
|
height: 56rpx;
|
|
padding: 0 24rpx;
|
|
font-size: 24rpx;
|
|
}
|
|
|
|
// 中等尺寸
|
|
&--medium {
|
|
height: 72rpx;
|
|
padding: 0 32rpx;
|
|
font-size: 28rpx;
|
|
}
|
|
|
|
// 大尺寸
|
|
&--large {
|
|
height: 88rpx;
|
|
padding: 0 40rpx;
|
|
font-size: 32rpx;
|
|
}
|
|
|
|
&__loading {
|
|
margin-right: 16rpx;
|
|
}
|
|
|
|
&__content {
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
}
|
|
</style> |