194 行
5.3 KiB
Vue
194 行
5.3 KiB
Vue
<script setup>
|
||
import { computed, ref, watch } from 'vue'
|
||
|
||
|
||
const props = defineProps({
|
||
type: { type: String, default: 'from' },
|
||
price: { type: [String, Number, Array], default: 0 },
|
||
color: { type: String, default: '#333' },
|
||
fontSize: { type: [Number, String], default: 36 },
|
||
currencySymbol: { type: String, default: '¥' },
|
||
fontClass: { type: String, default: 'font-ALMM' },
|
||
fillDecimalZero: { type: Boolean, default: false },
|
||
decimalScale: { type: Number, default: 0.8 },
|
||
fromScale: { type: Number, default: 0.7 },
|
||
|
||
})
|
||
|
||
const priceType = ref(props.type)
|
||
const minPrice = ref(0)
|
||
const maxPrice = ref(0)
|
||
const minPriceSplit = computed(() => splitPrice(minPrice.value))
|
||
const maxPriceSplit = computed(() => splitPrice(maxPrice.value))
|
||
const decimalFontSize = computed(() => {
|
||
return (Number(props.fontSize) * props.decimalScale).toFixed(0)
|
||
})
|
||
const fromFontSize = computed(() => {
|
||
return (Number(props.fontSize) * props.fromScale).toFixed(0)
|
||
})
|
||
|
||
function toSafeNumber(v) {
|
||
const n = Number(v)
|
||
return Number.isFinite(n) ? n : 0
|
||
}
|
||
|
||
function formatPrice() {
|
||
const p = props.price
|
||
|
||
if (Array.isArray(p)) {
|
||
if (p.length === 0) {
|
||
minPrice.value = 0
|
||
maxPrice.value = 0
|
||
}
|
||
else if (p.length === 1) {
|
||
minPrice.value = toSafeNumber(p[0])
|
||
maxPrice.value = minPrice.value
|
||
}
|
||
else {
|
||
const nums = p.map(toSafeNumber)
|
||
minPrice.value = Math.min(...nums)
|
||
maxPrice.value = Math.max(...nums)
|
||
}
|
||
}
|
||
else {
|
||
minPrice.value = maxPrice.value = toSafeNumber(p)
|
||
}
|
||
|
||
if (minPrice.value === maxPrice.value) {
|
||
priceType.value = 'single'
|
||
}
|
||
else {
|
||
priceType.value = props.type
|
||
}
|
||
}
|
||
|
||
function splitPrice(price) {
|
||
const str = toSafeNumber(price).toFixed(2)
|
||
const [intPart, decPart = '00'] = str.split('.')
|
||
return {
|
||
int: intPart,
|
||
dec: decPart,
|
||
hasDec: decPart !== '00',
|
||
}
|
||
}
|
||
|
||
// 关键:props 变化时重算(含 price 从 undefined -> 有值)
|
||
watch(() => [props.price, props.type], formatPrice, { immediate: true, deep: true })
|
||
</script>
|
||
|
||
<template>
|
||
<view class="ss-flex">
|
||
<view class="ss-flex ss-col-baseline" :style="{ color: props.color }">
|
||
<!-- 货币单位 -->
|
||
<!-- <sar-icon name="demo-icons:bbd" color="#FFB013" :size="`${decimalFontSize}rpx`" /> -->
|
||
<view
|
||
v-if="props.currencySymbol"
|
||
class="ss-col-bottom"
|
||
:class="{ [props.fontClass]: true }"
|
||
:style="{
|
||
fontSize: `${decimalFontSize}rpx`,
|
||
}"
|
||
>
|
||
{{ props.currencySymbol }}
|
||
</view>
|
||
<!-- 单独价格 -->
|
||
<view v-if="priceType === 'single'" class="ss-flex ss-col-baseline">
|
||
<view
|
||
class="ss-col-bottom"
|
||
:class="{ [props.fontClass]: true }"
|
||
:style="{
|
||
fontSize: `${props.fontSize}rpx`,
|
||
}"
|
||
>
|
||
{{ minPriceSplit.int }}
|
||
</view>
|
||
<view
|
||
v-if="minPriceSplit.hasDec || props.fillDecimalZero"
|
||
class="ss-col-bottom"
|
||
:class="{ [props.fontClass]: true }"
|
||
:style="{
|
||
fontSize: `${decimalFontSize}rpx`,
|
||
}"
|
||
>
|
||
.{{ minPriceSplit.dec }}
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 起价 -->
|
||
<view v-else-if="priceType === 'from'" class="ss-flex ss-col-baseline">
|
||
<view
|
||
class="ss-col-bottom"
|
||
:class="{ [props.fontClass]: true }"
|
||
:style="{
|
||
fontSize: `${props.fontSize}rpx`,
|
||
}"
|
||
>
|
||
{{ minPriceSplit.int }}
|
||
</view>
|
||
<view
|
||
v-if="minPriceSplit.hasDec || props.fillDecimalZero"
|
||
class="ss-col-bottom"
|
||
:class="{ [props.fontClass]: true }"
|
||
:style="{
|
||
fontSize: `${decimalFontSize}rpx`,
|
||
}"
|
||
>
|
||
.{{ minPriceSplit.dec }}
|
||
</view>
|
||
<view
|
||
class="ss-m-l-2 ss-col-bottom"
|
||
:style="{
|
||
fontSize: `${fromFontSize}rpx`,
|
||
}"
|
||
>
|
||
起
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 价格范围 -->
|
||
<view v-else-if="priceType === 'range'" class="ss-flex ss-col-baseline" :class="{ [props.fontClass]: true }">
|
||
<view
|
||
class="ss-col-bottom"
|
||
:style="{
|
||
fontSize: `${props.fontSize}rpx`,
|
||
}"
|
||
>
|
||
{{ minPriceSplit.int }}
|
||
</view>
|
||
|
||
<!-- 小数部分:单独样式 -->
|
||
<view
|
||
v-if="minPriceSplit.hasDec || props.fillDecimalZero"
|
||
class="ss-col-bottom"
|
||
:style="{
|
||
fontSize: `${decimalFontSize}rpx`,
|
||
}"
|
||
>
|
||
.{{ minPriceSplit.dec }}
|
||
</view>
|
||
<view>~</view>
|
||
<view
|
||
class="ss-col-bottom"
|
||
:style="{
|
||
fontSize: `${props.fontSize}rpx`,
|
||
}"
|
||
>
|
||
{{ maxPriceSplit.int }}
|
||
</view>
|
||
|
||
<!-- 小数部分:单独样式 -->
|
||
<view
|
||
v-if="maxPriceSplit.hasDec || props.fillDecimalZero"
|
||
class="ss-col-bottom"
|
||
:class="{ [props.fontClass]: true }"
|
||
:style="{
|
||
fontSize: `${decimalFontSize}rpx`,
|
||
}"
|
||
>
|
||
.{{ maxPriceSplit.dec }}
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</template>
|