货无忧
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

537 lines
13 KiB

<template>
<button
:class="rootClass"
:hover-class="disabled || loading ? '' : 'hd-button--active'"
:lang="lang"
:form-type="formType"
:style="rootStyle"
:open-type="disabled || loading ? '' : openType"
@tap="click"
data-eventsync="true"
:app-parameter="appParameter"
:hover-stop-propagation="hoverStopPropagation"
:send-message-title="sendMessageTitle"
send-message-path="sendMessagePath"
:session-from="sessionFrom"
:send-message-img="sendMessageImg"
:show-message-card="showMessageCard"
@getphonenumber="getphonenumber"
@getuserinfo="getuserinfo"
@error="error"
@opensetting="opensetting"
@launchapp="launchapp"
@chooseavatar="chooseAvatar"
>
<template v-if="loading">
<fan-loading :size="loadingSize" :type="loadingType" :color="loadingColor" />
<text v-if="loadingText" class="hd-button-loading-text">
{{ loadingText }}
</text>
</template>
<template v-else>
<hd-icon v-if="icon" size="1.2em" :name="icon" :class-prefix="classPrefix" custom-style="line-height: inherit;" />
<view class="hd-button-text">
<slot />
</view>
</template>
</button>
</template>
<script lang="ts">
export default {
// 将自定义节点设置成虚拟的,更加接近Vue组件的表现,可以去掉微信小程序自定义组件多出的最外层标签
options: {
virtualHost: true
}
}
</script>
<script lang="ts" setup>
import { computed } from 'vue'
import { CommonUtil } from '../..'
type ButtonType = 'default' | 'primary' | 'error' | 'warning' | 'success'
type ButtonSize = 'normal' | 'large' | 'small' | 'mini'
type ButtonShape = 'square' | 'roundsquare' | 'round' // `'square(直角)'` / `'roundsquare(小圆角)'` / `'round(大圆角)'`
type LoadingType = 'flower' | 'circular'
interface Props {
/**
* 按钮类型
*/
type?: ButtonType
/**
* 按钮尺寸
*/
size?: ButtonSize
/**
* 左侧图标名称或图片链接,可选值见 Icon 组件
*/
icon?: string
/**
* 图标类名前缀,同 Icon 组件的 class-prefix 属性
*/
classPrefix?: string
/**
* 是否为朴素按钮
*/
plain?: boolean
/**
* 是否为块级元素
*/
block?: boolean
/**
* 按钮形状
*/
shape?: ButtonShape
/**
* 是否显示为加载状态
*/
loading?: boolean
/**
* 是否细边框
*/
hairLine?: boolean
/**
* 是否禁用按钮
*/
disabled?: boolean
/**
* 加载状态提示文字
*/
loadingText?: string
/**
* 加载图标大小
*/
loadingSize?: string
/**
* 加载状态图标类型
*/
loadingType?: LoadingType
/**
* 按钮颜色,支持传入linear-gradient渐变色
*/
color?: string
/**
* 自定义样式
*/
customStyle?: string
/**
* 开放能力,具体请看uniapp稳定关于button组件部分说明 https://uniapp.dcloud.io/component/button
*/
openType?: string
/**
* 用于 `<form>` 组件,点击分别会触发 `<form>` 组件的 submit/reset 事件 取值为submit(提交表单),reset(重置表单)
*/
formType?: string
/**
* 打开 APP 时,向 APP 传递的参数,open-type=launchApp时有效
* 只微信小程序、QQ小程序有效
*/
appParameter?: string
// 指定是否阻止本节点的祖先节点出现点击态,微信小程序有效
hoverStopPropagation?: boolean
// 指定返回用户信息的语言,zh_CN 简体中文,zh_TW 繁体中文,en 英文。只微信小程序有效
lang?: string
// 会话来源,open-type="contact"时有效。只微信小程序有效
sessionFrom?: string
// 会话内消息卡片标题,open-type="contact"时有效
// 默认当前标题,只微信小程序有效
sendMessageTitle?: string
// 会话内消息卡片点击跳转小程序路径,open-type="contact"时有效
// 默认当前分享路径,只微信小程序有效
sendMessagePath?: string
// 会话内消息卡片图片,open-type="contact"时有效
// 默认当前页面截图,只微信小程序有效
sendMessageImg?: string
// 是否显示会话内消息卡片,设置此参数为 true,用户进入客服会话会在右下角显示"可能要发送的小程序"提示,
// 用户点击后可以快速发送小程序消息,open-type="contact"时有效
showMessageCard?: boolean
}
const props = withDefaults(defineProps<Props>(), {
/**
* 按钮类型
*/
type: 'default',
/**
* 按钮尺寸
*/
size: 'normal',
/**
* 图标类名前缀,同 Icon 组件的 class-prefix 属性
*/
classPrefix: 'fant-icon',
/**
* 是否为朴素按钮
*/
plain: false,
/**
* 是否为块级元素
*/
block: false,
/**
* 按钮形状
*/
shape: 'roundsquare',
/**
* 是否显示为加载状态
*/
loading: false,
/**
* 是否细边框
*/
hairLine: false,
/**
* 是否禁用按钮
*/
disabled: false,
/**
* 加载图标大小
*/
loadingSize: '40rpx',
/**
* 加载状态图标类型
*/
loadingType: 'circular',
/**
* 自定义样式
*/
customStyle: '',
/**
* 开放能力,具体请看uniapp稳定关于button组件部分说明 https://uniapp.dcloud.io/component/button
*/
openType: '',
/**
* 用于 `<form>` 组件,点击分别会触发 `<form>` 组件的 submit/reset 事件 取值为submit(提交表单),reset(重置表单)
*/
formType: '',
/**
* 打开 APP 时,向 APP 传递的参数,open-type=launchApp时有效
* 只微信小程序、QQ小程序有效
*/
appParameter: '',
// 指定是否阻止本节点的祖先节点出现点击态,微信小程序有效
hoverStopPropagation: false,
// 指定返回用户信息的语言,zh_CN 简体中文,zh_TW 繁体中文,en 英文。只微信小程序有效
lang: 'en',
// 会话来源,open-type="contact"时有效。只微信小程序有效
sessionFrom: '',
// 会话内消息卡片标题,open-type="contact"时有效
// 默认当前标题,只微信小程序有效
sendMessageTitle: '',
// 会话内消息卡片点击跳转小程序路径,open-type="contact"时有效
// 默认当前分享路径,只微信小程序有效
sendMessagePath: '',
// 会话内消息卡片图片,open-type="contact"时有效
// 默认当前页面截图,只微信小程序有效
sendMessageImg: '',
// 是否显示会话内消息卡片,设置此参数为 true,用户进入客服会话会在右下角显示"可能要发送的小程序"提示,
// 用户点击后可以快速发送小程序消息,open-type="contact"时有效
showMessageCard: false
})
/**
* 根节点样式
*/
const rootStyle = computed(() => {
if (!props.color) {
return props.customStyle
}
const rootStyle: Record<string, any> = {
color: props.plain ? props.color : '#fff',
background: props.plain ? null : props.color
}
// 背景色为渐变色时隐藏边框
if (props.color.indexOf('gradient') !== -1) {
rootStyle.border = 0
} else {
rootStyle['border-color'] = props.color
}
return CommonUtil.style([rootStyle, props.customStyle])
})
const rootClass = computed(() => {
let rootClass = `hd-button hd-button--${props.type ? props.type : 'default'} hd-button--${props.size ? props.size : 'normal'} hd-button--${
props.shape ? props.shape : 'roundsquare'
}`
if (props.hairLine && props.plain) {
rootClass = `${rootClass} hd-button--hairline hd-hairline--surround`
}
if (props.block) {
rootClass = `${rootClass} hd-button--block`
}
if (props.plain) {
rootClass = `${rootClass} hd-button--plain`
}
if (props.loading) {
rootClass = `${rootClass} hd-button--loading`
}
if (props.disabled) {
rootClass = `${rootClass} hd-button--disabled`
}
if (props.disabled || props.loading) {
rootClass = `${rootClass} hd-button--unavailable`
}
return rootClass
})
/**
* loading动画颜色
*/
const loadingColor = computed(() => {
if (props.plain) {
return props.color ? props.color : '#c9c9c9'
}
if (props.type === 'default') {
return '#c9c9c9'
}
return '#fff'
})
const emit = defineEmits(['click', 'getphonenumber', 'getuserinfo', 'error', 'opensetting', 'launchapp', 'chooseAvatar'])
/**
* 按钮点击事件
* @param event
* @returns
*/
function click(event) {
if (props.disabled || props.loading) {
return
}
// 点击按钮,且按钮状态不为加载或禁用时触发
emit('click', event)
}
// 下面为对接uniapp官方按钮开放能力事件回调的对接
function getphonenumber(res) {
// 获取用户手机号回调 open-type="getPhoneNumber"时有效(微信、支付宝、百度、字节、快手、京东小程序)
emit('getphonenumber', res)
}
function getuserinfo(res) {
// 用户点击该按钮时,会返回获取到的用户信息,从返回参数的detail中获取到的值同uni.getUserInfo(微信、QQ、百度、快手、京东小程序)
emit('getuserinfo', res)
}
function error(res) {
// 当使用开放能力时,发生错误的回调(微信、QQ、快手、京东小程序)
emit('error', res)
}
function opensetting(res) {
// 在打开授权设置页并关闭后回调(微信、QQ、百度、快手、京东小程序)
emit('opensetting', res)
}
function launchapp(res) {
// 打开 APP 成功的回调(微信、QQ、快手、京东小程序)
emit('launchapp', res)
}
function chooseAvatar(res) {
// 获取用户头像回调(仅微信小程序支持)
emit('chooseAvatar', res)
}
</script>
<style scoped lang="scss">
@import '../../libs/css/index.scss';
// #ifdef MP-WEIXIN
:deep(fan-loading) {
display: inline-flex;
}
// #endif
.hd-button {
position: relative;
display: inline-flex;
align-items: center;
justify-content: center;
box-sizing: border-box;
padding: 0;
text-align: center;
vertical-align: middle;
appearance: none;
-webkit-text-size-adjust: 100%;
height: $button-default-height;
font-size: $button-default-font-size;
transition: all 0.2s;
border-radius: $button-border-radius;
&::before {
position: absolute;
top: 50%;
left: 50%;
width: 100%;
height: 100%;
border: inherit;
border-radius: inherit; /* inherit parent's border radius */
transform: translate(-50%, -50%);
opacity: 0;
content: ' ';
background-color: $color-black;
border-color: $color-black;
}
&::after {
border-width: 0;
}
&--active::before {
opacity: 0.15;
}
&--unavailable::after {
display: none;
}
&--default {
color: $button-default-color;
background: $button-default-background-color;
border: $button-border-width solid $button-default-border-color;
}
&--primary {
color: $button-primary-color;
background: $button-primary-background-color;
border: $button-border-width solid $button-primary-border-color;
}
&--error {
color: $button-error-color;
background: $button-error-background-color;
border: $button-border-width solid $button-error-border-color;
}
&--warning {
color: $button-warning-color;
background: $button-warning-background-color;
border: $button-border-width solid $button-warning-border-color;
}
&--success {
color: $button-success-color;
background: $button-success-background-color;
border: $button-border-width solid $button-success-border-color;
}
&--plain {
background: $button-plain-background-color;
&.hd-button--primary {
color: $button-primary-background-color;
}
&.hd-button--error {
color: $button-error-background-color;
}
&.hd-button--warning {
color: $button-warning-background-color;
}
&.hd-button--success {
color: $button-success-background-color;
}
}
&--large {
width: 100%;
padding: 0 $padding-xl;
height: $button-large-height;
}
&--normal {
padding: 0 $padding-md;
font-size: $button-normal-font-size;
}
&--small {
min-width: $button-small-min-width;
height: $button-small-height;
padding: 0 $padding-xs;
font-size: $button-small-font-size;
}
&--mini {
min-width: $button-mini-min-width;
height: $button-mini-height;
padding: 0 $padding-xs;
font-size: $button-mini-font-size;
}
&--block {
display: flex;
width: 100%;
}
&--square {
border-radius: 0;
}
&--roundsquare {
border-radius: $button-round-square-border-radius;
}
&--round {
border-radius: $button-round-border-radius;
}
&--disabled {
opacity: $button-disabled-opacity;
}
&-text {
display: inline;
}
&-loading-text,
&-icon + &-text:not(:empty) {
margin-left: $padding-base;
}
&-icon {
min-width: 1em;
line-height: inherit !important;
vertical-align: top;
}
&--hairline {
overflow: visible;
border-width: 0;
// padding-top: 1px; // add 1px padding for text vertical align middle
// border: none;
&::after {
border-color: inherit !important;
border-width: 2rpx;
border-radius: $button-border-radius * 2;
top: 0;
left: 0;
transform-origin: 0 0;
}
&.hd-button--roundsquare::after {
border-radius: $button-round-square-border-radius * 2;
}
&.hd-button--round::after {
border-radius: $button-round-border-radius;
}
&.hd-button--square::after {
border-radius: 0;
}
}
}
</style>