Files
2026-09-24 16:25:22 +08:00

228 lines
6.7 KiB
Plaintext

<script lang="ts" setup>
import { computed } from "vue"
import { getDefaultColor } from "../../core/util/xCoreColorUtil.uts"
import { checkIsCssUnit } from "../../core/util/xCoreUtil.uts"
import { xConfig } from "../../config/xConfig.uts"
/**
*
* @name 卡片 xCard
* @page /pages/index/card
* @category 展示组件
* @description 圆角,主题可统一全局配置风格。
* @constant 平台兼容
* | Harmony | H5 | andriod | IOS | 小程序 | UTS | UNIAPP-X SDK | version |
| --- | --- | --- | --- | --- | --- | --- | --- |
| ☑ | ☑ | ☑️ | ☑️ | ☑️ | ☑️ | 4.76+ | 1.1.18 |
*/
defineOptions({name:"xCard"})
const emits = defineEmits([
/** 卡片被点击 */
'click',
/** 右边状态小图标被点击 */
'status',
/** 底部按钮被点击 */
'action'
])
type BtnSizeType = "mini" | "small" | "normal" | "large"
type xCardPropsType = {
/** 内容的内边距。 */
padding: string,
/** 标题文字大小 */
titleSize: string,
/** 按钮颜色 */
btnColor: string,
/** 标题颜色 */
color: string,
/** 背景颜色 */
bgColor: string,
/** 暗黑背景颜色,如果为空,取sheetDarkColor */
darkBgColor: string,
/** 底部按钮数组。如果不满意风格布局请使用插槽footer来布局 */
btns: string[],
/** 副标题 */
subtitle: string,
/** 标题 */
title: string,
/** 右边的小图标,如果你是想显示状态,日期请使用对应插槽 */
statusIcon: string,
/** 中间内容。如果有大量内容请直接在默认插槽(标签内)内布局 */
content: string,
/** 头部图片地址。 */
image: string,
/** 头图片高度 */
imageHeight: string,
/** 圆角请不要动态更改此会,默认为空,取全局设置的风格值。 */
round: string,
/** 请不要动态更改些投影值,截止4.75+鸿蒙无法使用投影 */
shadow: string,
/** 按钮尺寸 */
btnSize: BtnSizeType
}
const props = withDefaults(defineProps<xCardPropsType>(), {
padding: "16",
titleSize: "18",
btnColor: "",
color: "#333333",
bgColor: "#ffffff",
darkBgColor: "",
btns: () : string[] => [] as string[],
subtitle: "",
title: "",
statusIcon: "more-fill",
content: "",
image: "",
imageHeight: "150",
round: "",
shadow: "0 3px 10px rgba(0, 0, 0, 0.05)",
btnSize: "small" as BtnSizeType
})
// 计算属性
const _image = computed((): string => props.image)
const _round = computed((): string => {
if (props.round == "") return checkIsCssUnit(xConfig.cardRound, xConfig.unit)
return checkIsCssUnit(props.round, xConfig.unit)
})
const _imageHeight = computed((): string => checkIsCssUnit(props.imageHeight, xConfig.unit))
const _padding = computed((): string => checkIsCssUnit(props.padding, xConfig.unit))
const _titleSize = computed((): string => props.titleSize)
const _color = computed((): string => getDefaultColor(props.color))
const _bgColor = computed((): string => {
if(xConfig.dark=='dark'){
if(props.darkBgColor!='') return getDefaultColor(props.darkBgColor)
return getDefaultColor(xConfig.sheetDarkColor)
}
return getDefaultColor(props.bgColor)
})
const _btnColor = computed((): string => {
if (props.btnColor == "") return getDefaultColor(xConfig.color)
return getDefaultColor(props.btnColor)
})
const _btns = computed((): string[] => props.btns)
const _subtitle = computed((): string => props.subtitle)
const _title = computed((): string => props.title)
const _statusIcon = computed((): string => props.statusIcon)
const _content = computed((): string => props.content)
// 方法
function actionClick(index : number) {
emits('action', index)
}
function statusClick() {
emits('status')
}
function onClick() {
emits('click')
}
</script>
<template>
<!-- boxShadow: shadow, -->
<view @click="onClick" class="xCard"
<!-- #ifndef APP-HARMONY -->
:style="{borderRadius:_round,boxShadow: shadow,backgroundColor:_bgColor}"
<!-- #endif -->
<!-- #ifdef APP-HARMONY -->
:style="{borderRadius:_round,backgroundColor:_bgColor}"
<!-- #endif -->
>
<!--
@slot 图片插槽
-->
<slot name="image">
<image :style="{width:'100%',height:_imageHeight,borderRadius:`${_round} ${_round} 0px 0px`}" :src="_image"
v-if="_image!=''"></image>
</slot>
<view :style="{padding:_padding}">
<view class="xCardHeader">
<!--
@slot 标题插槽
-->
<slot name="title">
<view v-if="_title!=''">
<x-text :color="_color" :font-size="_titleSize" class="xCardTitle">{{_title}}</x-text>
</view>
</slot>
<!--
@slot 状态右边小图标插槽
-->
<slot name="statusIcon">
<view @click.stop="statusClick" v-if="_statusIcon!=''" style="padding: 0rpx 0rpx 0rpx 16px;">
<x-icon :font-size="_titleSize" :name="_statusIcon"></x-icon>
</view>
</slot>
</view>
<view class="xCardSubtitle">
<!--
@slot 副标题插槽
-->
<slot name="subtitle">
<x-text font-size="12" v-if="_subtitle!=''" class="xCardSubtitleText">
{{subtitle}}
</x-text>
</slot>
</view>
<!--
@slot 默认内容插槽
-->
<slot>
<x-text :color="_color" font-size="16" v-if="_content!=''" class="xCardContent">
{{_content}}
</x-text>
</slot>
<!--
@slot 底部插槽
-->
<slot name="footer">
<view class="xCardFooter" v-if="_btns.length>0">
<x-button round="6" @click.stop="actionClick(index)" v-for="(item,index) in _btns" :key="index"
:style="{marginRight:(index!=_btns.length-1)?'12px':'0px'}" :color="_btnColor"
:size="btnSize">{{item}}</x-button>
</view>
</slot>
</view>
</view>
</template>
<style scoped>
.xCardContent {
font-size: 14px;
line-height: 1.4;
opacity: 0.8;
}
.xCardFooter {
display: flex;
justify-content: flex-end;
flex-direction: row;
flex-wrap: wrap;
align-items: flex-start;
margin-top: 16px;
}
.xCardSubtitle {}
.xCardSubtitleText {
font-size: 13px;
opacity: 0.7;
padding: 12rpx 0rpx 24rpx 0rpx;
}
.xCardHeader {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
.xCardTitle {
font-weight: bold;
}
.xCard {
/* box-shadow: 0 3px 10px rgba(0, 0, 0, 0.1); */
}
</style>