2025/2/8第一次更新

This commit is contained in:
爱吃咸鱼小猫咪
2025-02-08 18:50:38 +08:00
commit d7af560866
26519 changed files with 5046029 additions and 0 deletions
+8
View File
@@ -0,0 +1,8 @@
import { withNoopInstall } from '../../utils'
import CountDown from './src/count-down.vue'
export const TnCountDown = withNoopInstall(CountDown)
export default TnCountDown
export * from './src/count-down'
export type { TnCountDownInstance } from './src/instance'
@@ -0,0 +1,114 @@
import { computed, toRef } from 'vue'
import {
useComponentColor,
useComponentSize,
useNamespace,
} from '../../../../hooks'
import { formatDomSizeValue } from '../../../../utils'
import type { CSSProperties } from 'vue'
import type { CountDownProps } from '../count-down'
export const useCountDownCustomStyle = (props: CountDownProps) => {
const ns = useNamespace('count-down')
// 解析颜色
const [textColorClass, textColorStyle] = useComponentColor(
toRef(props, 'textColor'),
'text'
)
const [separatorColorClass, separatorColorStyle] = useComponentColor(
toRef(props, 'separatorColor'),
'text'
)
const [borderColorClass, borderColorStyle] = useComponentColor(
toRef(props, 'borderColor'),
'border'
)
const { sizeType } = useComponentSize(props.size)
// 倒计时的类
const countDownClass = computed<string>(() => {
const cls: string[] = [ns.b()]
if (props.size && sizeType.value === 'inner') cls.push(ns.m(props.size))
return cls.join(' ')
})
// 倒计时的样式
const countDownStyle = computed<CSSProperties>(() => {
const style: CSSProperties = {}
// 设置字体大小
if (props.size && sizeType.value === 'custom')
style.fontSize = formatDomSizeValue(props.size)
return style
})
// 倒计时文字的类
const textClass = computed<string>(() => {
const cls: string[] = [ns.e('text')]
// 设置字体颜色
if (textColorClass.value) cls.push(textColorClass.value)
// 设置边框颜色
if (props.border) {
cls.push(ns.is('border'))
if (borderColorClass.value) cls.push(borderColorClass.value)
}
return cls.join(' ')
})
// 倒计时文字的样式
const textStyle = computed<CSSProperties>(() => {
const style: CSSProperties = {}
// 设置字体颜色
if (!textColorClass.value)
style.color = textColorStyle.value || 'var(--tn-text-color-primary)'
// 设置边框颜色
if (props.border) {
if (!borderColorClass.value)
style.borderColor =
borderColorStyle.value || 'var(--tn-color-gray-disabled)'
}
return style
})
// 分割符的类
const separatorClass = computed<string>(() => {
const cls: string[] = [
ns.e('separator'),
ns.em('separator', props.separatorMode),
]
if (separatorColorClass.value) cls.push(separatorColorClass.value)
return cls.join(' ')
})
// 分割符的样式
const separatorStyle = computed<CSSProperties>(() => {
const style: CSSProperties = {}
if (!separatorColorClass.value)
style.color =
separatorColorStyle.value || 'var(--tn-text-color-secondary)'
return style
})
return {
ns,
countDownClass,
countDownStyle,
textClass,
textStyle,
separatorClass,
separatorStyle,
}
}
@@ -0,0 +1,40 @@
import type { CountDownSeparatorMode } from '../count-down'
interface CountDownSeparatorItem {
day: string
hour: string
minute: string
second: string
}
type CountDownSeparatorData = Record<
CountDownSeparatorMode,
CountDownSeparatorItem
>
export const useCountDownSeparatorData = () => {
const countDownSeparatorData: CountDownSeparatorData = {
cn: {
day: '天',
hour: '时',
minute: '分',
second: '秒',
},
en: {
day: ':',
hour: ':',
minute: ':',
second: '',
},
}
const getSeparatorData = (
mode: CountDownSeparatorMode,
key: keyof CountDownSeparatorItem
) => {
return countDownSeparatorData[mode][key]
}
return {
getSeparatorData,
}
}
@@ -0,0 +1,3 @@
export * from './count-down-custom'
export * from './count-down-separator-data'
export * from './use-count-down'
@@ -0,0 +1,109 @@
import { ref, watch } from 'vue'
import { formatNumber } from '../../../../utils'
import type { SetupContext } from 'vue'
import type { CountDownEmits, CountDownProps } from '../count-down'
const SECOND = 1
const MINUTE = 60 * SECOND
const HOUR = 60 * MINUTE
const DAY = 24 * HOUR
export const useCountDown = (
props: CountDownProps,
emits: SetupContext<CountDownEmits>['emit']
) => {
// 当前倒计时时间
let time = 0
// 时间定义
const day = ref<string>('')
const hour = ref<string>('')
const minute = ref<string>('')
const second = ref<string>('')
// 将时间戳转换为对应的时间
const splitCountDownData = () => {
const { showDay, showHour, showMinute, showSecond, autoHideDay } = props
const _day = Math.floor(time / DAY)
// 如果不显示天数则将天的时间加到小时上,后面的分钟和秒如此累加
const _hour = showDay
? Math.floor((time % DAY) / HOUR)
: Math.floor(time / HOUR)
const _minute = Math.floor((time % HOUR) / MINUTE)
const _second = Math.floor(time % MINUTE)
// 判断是否自动隐藏天数
if (!showDay || (autoHideDay && _day === 0)) day.value = ''
else day.value = formatNumber(_day, 4)
hour.value = showHour ? formatNumber(_hour, 4) : ''
minute.value = showMinute ? formatNumber(_minute) : ''
second.value = showSecond ? formatNumber(_second) : ''
}
// 倒计时定时器
let countDownTimer: ReturnType<typeof setInterval> | null = null
// 开始倒计时
const startCountDown = () => {
// 如果倒计时时间为0,重新设置倒计时时间
if (time <= 0) time = props.time
else {
// 先渲染一次
time--
}
// 先停止之前的倒计时
stopCountDown()
emits('start')
// 开始倒计时
countDownTimer = setInterval(() => {
if (time < 0) {
stopCountDown()
emits('end')
return
}
splitCountDownData()
time--
}, 1000)
}
// 停止倒计时
const stopCountDown = () => {
if (countDownTimer) {
clearInterval(countDownTimer)
countDownTimer = null
}
}
// 重置定时器
const resetCountDown = () => {
stopCountDown()
time = props.time
splitCountDownData()
}
watch(
() => props.time,
(_time) => {
resetCountDown()
// 自动开始倒计时
if (props.autoStart && _time > 0) {
startCountDown()
}
},
{
immediate: true,
}
)
return {
day,
hour,
minute,
second,
startCountDown,
stopCountDown,
resetCountDown,
}
}
@@ -0,0 +1,99 @@
import { buildProps } from '../../../utils'
import type { ExtractPropTypes } from 'vue'
export const countDownSeparatorMode = ['cn', 'en'] as const
export const countDownProps = buildProps({
/**
* @description 倒计时时间,单位 秒
*/
time: {
type: Number,
required: true,
default: 0,
},
/**
* @description 是否自动开始倒计时
*/
autoStart: {
type: Boolean,
default: true,
},
/**
* @description 尺寸,内置 `sm` 、 `lg` 、 `xl`,也可以传递指定数值
*/
size: String,
/**
* @description 字体颜色,以tn开头使用图鸟内置的颜色
*/
textColor: String,
/**
* @description 是否显示天数
*/
showDay: Boolean,
/**
* @description 是否显示小时
*/
showHour: {
type: Boolean,
default: true,
},
/**
* @description 是否显示分钟
*/
showMinute: {
type: Boolean,
default: true,
},
/**
* @description 是否显示秒数
*/
showSecond: {
type: Boolean,
default: true,
},
/**
* @description 自动隐藏天数
*/
autoHideDay: {
type: Boolean,
default: true,
},
/**
* @description 分割符类型,`cn` 显示 对应语言的中文分割符,`en` 显示 : 分割符
*/
separatorMode: {
type: String,
values: countDownSeparatorMode,
default: 'en',
},
/**
* @description 分割符颜色,以tn开头使用图鸟内置的颜色
*/
separatorColor: String,
/**
* @description 是否显示边框
*/
border: Boolean,
/**
* @description 边框颜色,以tn开头使用图鸟内置的颜色
*/
borderColor: String,
})
export const countDownEmits = {
/**
* @description 倒计时开始时触发
*/
start: () => true,
/**
* @description 倒计时结束时触发
*/
end: () => true,
}
export type CountDownProps = ExtractPropTypes<typeof countDownProps>
export type CountDownEmits = typeof countDownEmits
export type CountDownSeparatorMode = (typeof countDownSeparatorMode)[number]
@@ -0,0 +1,93 @@
<script lang="ts" setup>
import { countDownEmits, countDownProps } from './count-down'
import {
useCountDown,
useCountDownCustomStyle,
useCountDownSeparatorData,
} from './composables'
const props = defineProps(countDownProps)
const emits = defineEmits(countDownEmits)
const {
day,
hour,
minute,
second,
startCountDown,
stopCountDown,
resetCountDown,
} = useCountDown(props, emits)
const {
countDownClass,
countDownStyle,
textClass,
textStyle,
separatorClass,
separatorStyle,
} = useCountDownCustomStyle(props)
const { getSeparatorData } = useCountDownSeparatorData()
defineExpose({
/**
* @description 开始倒计时
*/
start: startCountDown,
/**
* @description 停止倒计时
*/
stop: stopCountDown,
/**
* @description 重置倒计时
*/
reset: resetCountDown,
})
</script>
<template>
<view :class="[countDownClass]" :style="countDownStyle">
<!-- -->
<template v-if="day">
<view class="day" :class="[textClass]" :style="textStyle">{{ day }}</view>
<view class="day" :class="[separatorClass]" :style="separatorStyle">
{{ getSeparatorData(separatorMode, 'day') }}
</view>
</template>
<!-- -->
<template v-if="hour">
<view class="hour" :class="[textClass]" :style="textStyle">
{{ hour }}
</view>
<view class="hour" :class="[separatorClass]" :style="separatorStyle">
{{ getSeparatorData(separatorMode, 'hour') }}
</view>
</template>
<!-- -->
<template v-if="minute">
<view class="minute" :class="[textClass]" :style="textStyle">
{{ minute }}
</view>
<view class="minute" :class="[separatorClass]" :style="separatorStyle">
{{ getSeparatorData(separatorMode, 'minute') }}
</view>
</template>
<!-- -->
<template v-if="second">
<view class="second" :class="[textClass]" :style="textStyle">
{{ second }}
</view>
<view
v-if="getSeparatorData(separatorMode, 'second')"
class="minute"
:class="[separatorClass]"
:style="separatorStyle"
>
{{ getSeparatorData(separatorMode, 'second') }}
</view>
</template>
</view>
</template>
<style lang="scss" scoped>
@import '../../../theme-chalk/src/count-down.scss';
</style>
@@ -0,0 +1,3 @@
import type CountDown from './count-down.vue'
export type TnCountDownInstance = InstanceType<typeof CountDown>