315 lines
11 KiB
Plaintext
315 lines
11 KiB
Plaintext
<template>
|
||
<!-- #ifdef APP-ANDROID || APP-IOS || APP-HARMONY -->
|
||
<view class="l-button"
|
||
ref="rootRef"
|
||
:class="classes"
|
||
:hover-class="disabled || loading || color != null ? '': hoverClass ?? 'l-button--hover'"
|
||
:style="[styles, lStyle]"
|
||
:hover-start-time="hoverStartTime"
|
||
:hover-stay-time="hoverStayTime"
|
||
:data-disabled="disabled||loading"
|
||
@tap.stop="handleTap" >
|
||
<l-loading class="l-button__loading" :color="loadingColor" v-if="loading"></l-loading>
|
||
<l-icon class="l-button__icon" :size="innerIconSize" :color="loadingColor" v-if="icon" :name="icon"></l-icon>
|
||
<text class="l-button__content" :class="gapClass" ref="buttonTextRef" :style="[contentStyle]">
|
||
<slot>{{content}}</slot>
|
||
</text>
|
||
<button
|
||
class="l-button__button"
|
||
hover-class="none"
|
||
v-if="formType != null || openType != null"
|
||
@agreeprivacyauthorization="agreeprivacyauthorization"
|
||
:disabled="disabled || loading"
|
||
:form-type="disabled || loading ? '' : formType"
|
||
:open-type="disabled || loading ? '' : openType" >
|
||
</button>
|
||
</view>
|
||
<!-- #endif -->
|
||
<!-- #ifndef APP-ANDROID || APP-IOS || APP-HARMONY -->
|
||
<button class="l-button l-class"
|
||
:id="lId"
|
||
:style="[styles, lStyle]"
|
||
:class="[
|
||
'l-button--' + size,
|
||
'l-button--' + type,
|
||
'l-button--' + shape,
|
||
'l-button--' + computedVariant,
|
||
{
|
||
'l-button--ghost': ghost,
|
||
'l-button--block': block,
|
||
'l-button--disabled': disabled,
|
||
'l-button--loading': loading,
|
||
}
|
||
]"
|
||
:form-type="disabled || loading ? '' : formType"
|
||
:open-type="disabled || loading ? '' : openType"
|
||
:hover-stop-propagation="hoverStopPropagation"
|
||
:hover-start-time="hoverStartTime"
|
||
:hover-stay-time="hoverStayTime" :lang="lang"
|
||
:session-from="sessionFrom"
|
||
:hover-class="hoverClasses"
|
||
:send-message-title="sendMessageTitle"
|
||
:send-message-path="sendMessagePath"
|
||
:send-message-img="sendMessageImg"
|
||
:app-parameter="appParameter"
|
||
:show-message-card="showMessageCard"
|
||
@tap.stop="handleTap"
|
||
@getuserinfo="getuserinfo"
|
||
@contact="contact"
|
||
@getphonenumber="getphonenumber"
|
||
@error="error"
|
||
@opensetting="opensetting"
|
||
@launchapp="launchapp"
|
||
@chooseavatar="chooseavatar"
|
||
@agreeprivacyauthorization="agreeprivacyauthorization"
|
||
:aria-label="ariaLabel"
|
||
:data-disabled="disabled||loading">
|
||
<view class="l-button__loading" v-if="loading">
|
||
<l-loading inheritColor></l-loading>
|
||
</view>
|
||
|
||
<l-icon class="l-button__icon" v-if="icon" :name="icon"></l-icon>
|
||
<view class="l-button__content" v-if="content || $slots.default" :style="[contentStyle]" :class="[gapClass]">
|
||
<slot>{{content}}</slot>
|
||
</view>
|
||
</button>
|
||
<!-- #endif -->
|
||
</template>
|
||
<script lang="uts" setup>
|
||
/**
|
||
* Button 按钮组件
|
||
* @description 提供丰富的按钮样式和交互功能,支持多种形态和平台特性
|
||
* <br> 插件类型:LButtonComponentPublicInstance
|
||
* @tutorial https://ext.dcloud.net.cn/plugin?name=lime-button
|
||
*
|
||
* @property {string} ariaLabel 无障碍标签(用于屏幕阅读器)
|
||
* @property {boolean} block 块级布局(占满父容器宽度)
|
||
* @property {boolean} disabled 禁用状态
|
||
* @property {boolean} ghost 幽灵模式(透明背景+边框)
|
||
* @property {string} icon 左侧图标名称/路径
|
||
* @property {string} iconSize 图标尺寸(支持CSS单位)
|
||
* @property {boolean} loading 加载状态(显示加载动画)
|
||
* @property {UTSJSONObject} loadingProps 加载动画配置
|
||
* @property {'rectangle' | 'square' | 'round' | 'circle'} shape 按钮形状
|
||
* @value rectangle 长方形(默认)
|
||
* @value square 正方形
|
||
* @value round 圆角矩形
|
||
* @value circle 圆形
|
||
* @property {SizeEnum} size 按钮尺寸
|
||
* @value mini 小号
|
||
* @value small 小号
|
||
* @value medium 中号(默认)
|
||
* @value large 大号
|
||
* @property {string} suffix 右侧附加内容(图标/文本)
|
||
* @property {'default' | 'primary' | 'danger' | 'warning' | 'success' | 'info'} type 色彩类型
|
||
* @value default
|
||
* @value primary
|
||
* @value danger
|
||
* @value warning
|
||
* @value success
|
||
* @value info
|
||
* @property {'solid' | 'outline' | 'text' | 'light' | 'dashed'} variant 样式变体
|
||
* @value solid
|
||
* @value outline
|
||
* @value text
|
||
* @value light
|
||
* @value dashed
|
||
* @property {string} radius 自定义圆角(覆盖shape设置)
|
||
* @property {string} fontSize 文字字号(支持CSS单位)
|
||
* @property {string} textColor 文字颜色(支持CSS颜色值)
|
||
* @property {string} color 主色(背景/边框色)
|
||
*
|
||
* @platform 微信小程序
|
||
* @property {string} formType 表单类型(submit/reset)
|
||
* @property {string} openType 开放能力(contact/share等)
|
||
* @property {string} lang 用户信息语言(zh_CN/zh_TW/en)
|
||
* @property {string} sessionFrom 会话来源(contact模式有效)
|
||
* @property {string} sendMessageTitle 消息卡片标题(contact模式有效)
|
||
* @property {string} sendMessagePath 消息跳转路径(contact模式有效)
|
||
* @property {string} sendMessageImg 消息卡片图片(contact模式有效)
|
||
* @property {string} appParameter APP启动参数(launchApp模式)
|
||
* @property {boolean} showMessageCard 显示消息卡片提示
|
||
*
|
||
* @property {string} hoverClass 点击态样式类(默认:button-hover)
|
||
* @property {boolean} hoverStopPropagation 阻止祖先点击态
|
||
* @property {number} hoverStartTime 点击态延迟(默认:20ms)
|
||
* @property {number} hoverStayTime 点击态保留时间(默认:70ms)
|
||
* @event {Function} click 点击事件(禁用状态下不触发)
|
||
* @event {Function} getuserinfo 用户信息授权回调
|
||
* @event {Function} contact 客服会话回调
|
||
* @event {Function} agreeprivacyauthorization
|
||
* @event {Function} chooseavatar
|
||
* @event {Function} getphonenumber
|
||
* @event {Function} error
|
||
* @event {Function} opensetting
|
||
* @event {Function} launchapp
|
||
*/
|
||
|
||
import { ButtonProps } from './type'
|
||
// #ifdef APP
|
||
import { getCssVariableColor } from './utils'
|
||
// #endif
|
||
defineOptions({
|
||
behaviors: ['wx://form-field-button']
|
||
})
|
||
|
||
const emit = defineEmits(['click','agreeprivacyauthorization', 'chooseavatar', 'getuserinfo','contact', 'getphonenumber', 'error', 'opensetting', 'launchapp'])
|
||
const props = withDefaults(defineProps<ButtonProps>(), {
|
||
block: false,
|
||
disabled: false,
|
||
ghost: false,
|
||
loading: false,
|
||
shape: 'rectangle',
|
||
size: 'medium',
|
||
type: 'default',
|
||
// hoverClass: '',
|
||
hoverStopPropagation: false,
|
||
hoverStartTime: 20,
|
||
hoverStayTime: 70,
|
||
lang: 'en',
|
||
sessionFrom: '',
|
||
sendMessageTitle: '',
|
||
sendMessagePath: '',
|
||
sendMessageImg: '',
|
||
appParameter: '',
|
||
showMessageCard: false
|
||
// variant: 'solid'
|
||
})
|
||
|
||
|
||
const instance = getCurrentInstance()
|
||
// const rootRef = ref<UniElement|null>(null)
|
||
const buttonTextRef = ref<UniTextElement|null>(null)
|
||
const hasContent = computed(():boolean => {
|
||
return props.content != null || instance?.proxy?.$slots?.['default'] != null
|
||
})
|
||
const variant = computed(():string => props.variant ?? (props.color != null ? 'solid' : (props.type == 'default' ? 'outline': 'solid')))
|
||
const classes = computed(():Map<string, any>=>{
|
||
const cls = new Map<string, any>()
|
||
const name = 'l-button'
|
||
cls.set(`${name}--${props.size}`, true)
|
||
cls.set(`${name}--${props.type}`, true)
|
||
cls.set(`${name}--${variant.value}`, true)
|
||
cls.set(`${name}--${props.shape}`, true)
|
||
cls.set(`${name}--disabled`, props.disabled)
|
||
cls.set(`${name}--loading`, props.loading)
|
||
cls.set(`${name}--ghost`, props.ghost)
|
||
cls.set(`${name}--block`, props.block)
|
||
|
||
return cls
|
||
})
|
||
|
||
const styles = computed(():Map<string, any>=>{
|
||
const style = new Map<string, any>()
|
||
// #ifndef APP
|
||
if(props.gap) {
|
||
style.set('--l-button-gap', props.gap)
|
||
}
|
||
// #endif
|
||
if(props.radius != null) {
|
||
style.set('border-radius', props.radius!)
|
||
}
|
||
if(props.color != null) {
|
||
if(variant.value == 'solid') {
|
||
style.set('background', props.color!)
|
||
} else if(['outline', 'dashed'].includes(variant.value)) {
|
||
// #ifdef APP
|
||
style.set('border-color', props.color!)
|
||
// #endif
|
||
// #ifndef APP
|
||
style.set('--l-button-default-border-color', props.color!)
|
||
style.set('--l-button-border-color', props.color!)
|
||
// #endif
|
||
}
|
||
|
||
}
|
||
return style
|
||
})
|
||
|
||
const sizes = new Map<string, string>([
|
||
// #ifdef APP-ANDROID || APP-IOS || APP-HARMONY
|
||
['mini', '16px'],
|
||
['small', '18px'],
|
||
['medium', '18px'],
|
||
['large', '24px'],
|
||
// #endif
|
||
])
|
||
const innerIconSize = computed(():string|null=> {
|
||
return props.iconSize ?? props.fontSize ?? sizes.get(props.size)
|
||
})
|
||
const colors = new Map<string, string>([
|
||
// #ifdef APP-ANDROID || APP-IOS || APP-HARMONY
|
||
// ['default', 'rgba(0,0,0,0.88)'],
|
||
// ['primary', '#3283ff'],
|
||
// ['danger', '#FF4D4F'],
|
||
// ['warning', '#ffb400'],
|
||
// ['success', '#34c471'],
|
||
// ['info', '#3283ff'],
|
||
// #endif
|
||
])
|
||
const loadingColor = computed(():string|null => {
|
||
// #ifdef APP
|
||
console.log(`111props.textColor ?? (variant.value == 'solid' ? 'white' : getCssVariableColor(buttonTextRef.value)) ?? ''`, props.textColor ?? (variant.value == 'solid' ? 'white' : getCssVariableColor(buttonTextRef.value)) ?? '')
|
||
return props.textColor ?? (variant.value == 'solid' ? 'white' : getCssVariableColor(buttonTextRef.value)) ?? ''//colors.get(props.type))
|
||
// #endif
|
||
// #ifndef APP
|
||
return props.textColor ?? (variant.value == 'solid' ? 'white' : colors.get(props.type))
|
||
// #endif
|
||
})
|
||
|
||
const gapClass = computed((): string => {
|
||
return props.loading || props.icon != null ? 'gap' : ''
|
||
})
|
||
const contentStyle = computed(():Map<string, any> => {
|
||
const style = new Map<string, any>()
|
||
if(props.gap != null && (props.loading || props.icon != null)) {
|
||
style.set('margin-left', props.gap!)
|
||
}
|
||
if(props.textColor != null || props.color != null && variant.value != 'solid') {
|
||
style.set('color', (props.textColor ?? props.color)!)
|
||
}
|
||
if(props.fontSize != null) {
|
||
style.set('font-size', props.fontSize!)
|
||
}
|
||
return style
|
||
})
|
||
// #ifndef APP
|
||
const hoverClasses = computed(():string => {
|
||
return props.disabled || props.loading ? '' : (props.hoverClass || `l-button--hover`)
|
||
})
|
||
const computedVariant = computed(():string => props.variant ?? (props.color ? 'solid' : (props.type == 'default' ? 'outline': 'solid')))
|
||
// #endif
|
||
const getuserinfo = (e: UniEvent) => {
|
||
emit('getuserinfo', e);
|
||
}
|
||
const contact = (e: UniEvent) => {
|
||
emit('contact', e);
|
||
}
|
||
const getphonenumber = (e: UniEvent) => {
|
||
emit('getphonenumber', e);
|
||
}
|
||
const error = (e: UniEvent) => {
|
||
emit('error', e);
|
||
}
|
||
const opensetting = (e: UniEvent) => {
|
||
emit('opensetting', e);
|
||
}
|
||
const launchapp = (e: UniEvent) => {
|
||
emit('launchapp', e);
|
||
}
|
||
const chooseavatar = (e: UniEvent) => {
|
||
emit('chooseavatar', e);
|
||
}
|
||
const agreeprivacyauthorization = (e: UniEvent) => {
|
||
emit('agreeprivacyauthorization', e);
|
||
}
|
||
const handleTap = (e: UniPointerEvent)=>{
|
||
if (props.disabled || props.loading) return;
|
||
emit('click', e);
|
||
}
|
||
|
||
|
||
</script>
|
||
<style lang="scss">
|
||
@import './index-u';
|
||
</style> |