New Huajishe Check ChaoXing

This commit is contained in:
e2hang
2025-10-01 10:01:52 +08:00
parent 240b884eac
commit 80be8ae3cf
1094 changed files with 61709 additions and 0 deletions

View File

@@ -0,0 +1,43 @@
:: BASE_DOC ::
## API
### CountDown Props
name | type | default | description | required
-- | -- | -- | -- | --
style | Object | - | CSS(Cascading Style Sheets) | N
custom-style | Object | - | CSS(Cascading Style Sheets)used to set style on virtual component | N
auto-start | Boolean | true | \- | N
content | String / Slot | 'default' | [see more ts definition](https://github.com/Tencent/tdesign-miniprogram/blob/develop/src/common/common.ts) | N
format | String | HH:mm:ss | \- | N
millisecond | Boolean | false | \- | N
size | String | 'medium' | `0.5.1`。options: small/medium/large | N
split-with-unit | Boolean | false | `0.5.1` | N
theme | String | 'default' | `0.5.1`。options: default/round/square | N
time | Number | 0 | required | Y
### CountDown Events
name | params | description
-- | -- | --
change | `(time: TimeData)` | [see more ts definition](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/count-down/type.ts)。<br/>`interface TimeData { days: number; hours: number; minutes: number; seconds: number; milliseconds: number }`<br/>
finish | \- | \-
### CountDown External Classes
className | Description
-- | --
t-class | \-
t-class-count | \-
t-class-split | \-
### CSS Variables
The component provides the following CSS variables, which can be used to customize styles.
Name | Default Value | Description
-- | -- | --
--td-countdown-bg-color | @error-color | -
--td-countdown-default-color | @text-color-primary | -
--td-countdown-round-border-radius | @radius-circle | -
--td-countdown-round-color | @text-color-anti | -
--td-countdown-square-border-radius | @radius-small | -

View File

@@ -0,0 +1,79 @@
---
title: CountDown 倒计时
description: 用于实时展示倒计时数值。
spline: data
isComponent: true
---
<span class="coverages-badge" style="margin-right: 10px"><img src="https://img.shields.io/badge/coverages%3A%20lines-99%25-blue" /></span><span class="coverages-badge" style="margin-right: 10px"><img src="https://img.shields.io/badge/coverages%3A%20functions-100%25-blue" /></span><span class="coverages-badge" style="margin-right: 10px"><img src="https://img.shields.io/badge/coverages%3A%20statements-99%25-blue" /></span><span class="coverages-badge" style="margin-right: 10px"><img src="https://img.shields.io/badge/coverages%3A%20branches-85%25-blue" /></span>
> CountDown 组件用于实时展示倒计时数值。
如果需要与站点演示一致的数字字体效果,推荐您到 <a href="https://tdesign.tencent.com/design/fonts">数字字体章节</a>,将 TCloudNumber 字体下载并将包含的 TCloudNumberVF.ttf 做为 TCloudNumber 字体资源引入到具体项目中使用。
## 引入
全局引入,在 miniprogram 根目录下的`app.json`中配置,局部引入,在需要引入的页面或组件的`index.json`中配置。
```json
"usingComponents": {
"t-count-down": "tdesign-miniprogram/count-down/count-down"
}
```
## 代码演示
<a href="https://developers.weixin.qq.com/s/C37tsims79Sk" title="在开发者工具中预览效果" target="_blank" rel="noopener noreferrer"> 在开发者工具中预览效果 </a>
<blockquote style="background-color: #d9e1ff; font-size: 15px; line-height: 26px;margin: 16px 0 0;padding: 16px; border-radius: 6px; color: #0052d9" >
<p>Tips: 请确保开发者工具为打开状态。导入开发者工具后依次执行npm i > 构建npm包 > 勾选 "将JS编译成ES5"</p>
</blockquote>
### 基础倒计时
{{ base }}
### 调整尺寸
{{ size }}
## API
### CountDown Props
名称 | 类型 | 默认值 | 描述 | 必传
-- | -- | -- | -- | --
style | Object | - | 样式 | N
custom-style | Object | - | 样式,一般用于开启虚拟化组件节点场景 | N
auto-start | Boolean | true | 是否自动开始倒计时 | N
content | String / Slot | 'default' | 最终倒计时的展示内容,值为'default'时使用默认的格式,否则使用自定义样式插槽。[通用类型定义](https://github.com/Tencent/tdesign-miniprogram/blob/develop/src/common/common.ts) | N
format | String | HH:mm:ss | 时间格式DD-日HH-时mm-分ss-秒SSS-毫秒 | N
millisecond | Boolean | false | 是否开启毫秒级渲染 | N
size | String | 'medium' | `0.5.1`。倒计时尺寸。可选项small/medium/large | N
split-with-unit | Boolean | false | `0.5.1`。使用时间单位分割 | N
theme | String | 'default' | `0.5.1`。倒计时风格。可选项default/round/square | N
time | Number | 0 | 必需。倒计时时长,单位毫秒 | Y
### CountDown Events
名称 | 参数 | 描述
-- | -- | --
change | `(time: TimeData)` | 时间变化时触发。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/count-down/type.ts)。<br/>`interface TimeData { days: number; hours: number; minutes: number; seconds: number; milliseconds: number }`<br/>
finish | \- | 倒计时结束时触发
### CountDown External Classes
类名 | 描述
-- | --
t-class | 根节点样式类
t-class-count | 计数样式类
t-class-split | 分隔线样式类
### CSS Variables
组件提供了下列 CSS 变量,可用于自定义样式。
名称 | 默认值 | 描述
-- | -- | --
--td-countdown-bg-color | @error-color | -
--td-countdown-default-color | @text-color-primary | -
--td-countdown-round-border-radius | @radius-circle | -
--td-countdown-round-color | @text-color-anti | -
--td-countdown-square-border-radius | @radius-small | -

View File

@@ -0,0 +1,33 @@
import { SuperComponent } from '../common/src/index';
export default class CountDown extends SuperComponent {
externalClasses: string[];
properties: import("./type").TdCountDownProps;
observers: {
time(): void;
};
data: {
prefix: string;
classPrefix: string;
timeDataUnit: {
DD: string;
HH: string;
mm: string;
ss: string;
SSS: string;
};
timeData: import("./utils").TimeData;
formattedTime: string;
};
timeoutId: null | number;
lifetimes: {
detached(): void;
};
methods: {
start(): void;
pause(): void;
reset(): void;
getTime(): number;
updateTime(remain: number): void;
doCount(): void;
};
}

View File

@@ -0,0 +1,100 @@
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import { SuperComponent, wxComponent } from '../common/src/index';
import config from '../common/config';
import props from './props';
import { isSameSecond, parseFormat, parseTimeData, TimeDataUnit } from './utils';
const { prefix } = config;
const name = `${prefix}-count-down`;
let CountDown = class CountDown extends SuperComponent {
constructor() {
super(...arguments);
this.externalClasses = [`${prefix}-class`, `${prefix}-class-count`, `${prefix}-class-split`];
this.properties = props;
this.observers = {
time() {
this.reset();
},
};
this.data = {
prefix,
classPrefix: name,
timeDataUnit: TimeDataUnit,
timeData: parseTimeData(0),
formattedTime: '0',
};
this.timeoutId = null;
this.lifetimes = {
detached() {
if (this.timeoutId) {
clearTimeout(this.timeoutId);
this.timeoutId = null;
}
},
};
this.methods = {
start() {
if (this.counting) {
return;
}
this.counting = true;
this.endTime = Date.now() + this.remain;
this.doCount();
},
pause() {
this.counting = false;
this.timeoutId && clearTimeout(this.timeoutId);
},
reset() {
this.pause();
this.remain = this.properties.time;
this.updateTime(this.remain);
if (this.properties.autoStart) {
this.start();
}
},
getTime() {
return Math.max(this.endTime - Date.now(), 0);
},
updateTime(remain) {
const { format } = this.properties;
this.remain = remain;
const timeData = parseTimeData(remain);
this.triggerEvent('change', timeData);
const { timeText } = parseFormat(remain, format);
const timeRange = format.split(':');
this.setData({
timeRange,
timeData,
formattedTime: timeText.replace(/:/g, ' : '),
});
if (remain === 0) {
this.pause();
this.triggerEvent('finish');
}
},
doCount() {
this.timeoutId = setTimeout(() => {
const time = this.getTime();
if (this.properties.millisecond) {
this.updateTime(time);
}
else if (!isSameSecond(time, this.remain) || time === 0) {
this.updateTime(time);
}
if (time !== 0) {
this.doCount();
}
}, 33);
},
};
}
};
CountDown = __decorate([
wxComponent()
], CountDown);
export default CountDown;

View File

@@ -0,0 +1,7 @@
{
"component": true,
"styleIsolation": "apply-shared",
"usingComponents": {
"t-icon": "../icon/icon"
}
}

View File

@@ -0,0 +1,22 @@
<wxs src="../common/utils.wxs" module="_" />
<wxs module="_this"> module.exports.format = function(num) { return num < 10 ? '0' + num : num; } </wxs>
<view
style="{{_._style([style, customStyle])}}"
class="{{classPrefix}} {{classPrefix}}--{{theme}} {{classPrefix}}--{{size}} class {{prefix}}-class "
aria-role="option"
>
<slot wx:if="{{content !== 'default'}}" name="content" />
<slot wx:if="{{content !== 'default'}}" />
<block wx:elif="{{theme == 'default' && !splitWithUnit}}">{{formattedTime}}</block>
<block wx:else>
<block wx:for="{{timeRange}}" wx:key="index">
<text class="{{classPrefix}}__item {{prefix}}-class-count">{{_this.format(timeData[timeRange[index]])}}</text>
<text
wx:if="{{ splitWithUnit || timeRange.length - 1 !== index}}"
class="{{classPrefix}}__split {{classPrefix}}__split--{{splitWithUnit ? 'text' : 'dot'}} {{prefix}}-class-split"
>{{splitWithUnit ? timeDataUnit[timeRange[index]] : ':'}}</text
>
</block>
</block>
</view>

View File

@@ -0,0 +1,137 @@
.t-float-left {
float: left;
}
.t-float-right {
float: right;
}
@keyframes tdesign-fade-out {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
.hotspot-expanded.relative {
position: relative;
}
.hotspot-expanded::after {
content: '';
display: block;
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
transform: scale(1.5);
}
.t-count-down--small.t-count-down--default {
font-size: var(--td-font-size-base, 28rpx);
}
.t-count-down--small.t-count-down--round > .t-count-down__item {
font-size: var(--td-font-size-s, 24rpx);
}
.t-count-down--small.t-count-down--square > .t-count-down__item {
font-size: var(--td-font-size-s, 24rpx);
}
.t-count-down--small.t-count-down--round > .t-count-down__item,
.t-count-down--small.t-count-down--square > .t-count-down__item {
width: 40rpx;
height: 40rpx;
}
.t-count-down--small.t-count-down--round > .t-count-down__split--dot,
.t-count-down--small.t-count-down--square > .t-count-down__split--dot {
margin: 0 4rpx;
font-size: var(--td-font-size-base, 28rpx);
font-weight: 700;
}
.t-count-down--small.t-count-down--round > .t-count-down__split--text,
.t-count-down--small.t-count-down--square > .t-count-down__split--text {
margin: 0 8rpx;
font-size: var(--td-font-size, 20rpx);
}
.t-count-down--medium.t-count-down--default {
font-size: var(--td-font-size-m, 32rpx);
}
.t-count-down--medium.t-count-down--round > .t-count-down__item {
font-size: var(--td-font-size-base, 28rpx);
}
.t-count-down--medium.t-count-down--square > .t-count-down__item {
font-size: var(--td-font-size-base, 28rpx);
}
.t-count-down--medium.t-count-down--round > .t-count-down__item,
.t-count-down--medium.t-count-down--square > .t-count-down__item {
width: 48rpx;
height: 48rpx;
}
.t-count-down--medium.t-count-down--round > .t-count-down__split--dot,
.t-count-down--medium.t-count-down--square > .t-count-down__split--dot {
margin: 0 6rpx;
font-size: var(--td-font-size-m, 32rpx);
font-weight: 700;
}
.t-count-down--medium.t-count-down--round > .t-count-down__split--text,
.t-count-down--medium.t-count-down--square > .t-count-down__split--text {
margin: 0 10rpx;
font-size: var(--td-font-size-s, 24rpx);
}
.t-count-down--large.t-count-down--default {
font-size: 36rpx;
}
.t-count-down--large.t-count-down--round > .t-count-down__item {
font-size: var(--td-font-size-m, 32rpx);
}
.t-count-down--large.t-count-down--square > .t-count-down__item {
font-size: var(--td-font-size-m, 32rpx);
}
.t-count-down--large.t-count-down--round > .t-count-down__item,
.t-count-down--large.t-count-down--square > .t-count-down__item {
width: 56rpx;
height: 56rpx;
}
.t-count-down--large.t-count-down--round > .t-count-down__split--dot,
.t-count-down--large.t-count-down--square > .t-count-down__split--dot {
margin: 0 12rpx;
font-size: 36rpx;
font-weight: 700;
}
.t-count-down--large.t-count-down--round > .t-count-down__split--text,
.t-count-down--large.t-count-down--square > .t-count-down__split--text {
margin: 0 12rpx;
font-size: var(--td-font-size-base, 28rpx);
}
.t-count-down {
font-family: TCloudNumber, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Hiragino Sans GB, Microsoft YaHei UI, Microsoft YaHei, Source Han Sans CN, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol;
display: flex;
}
.t-count-down .t-count-down__item,
.t-count-down .t-count-down__split {
display: flex;
align-items: center;
justify-content: center;
}
.t-count-down--square > .t-count-down__split--dot,
.t-count-down--round > .t-count-down__split--dot {
color: var(--td-error-color, var(--td-error-color-6, #d54941));
}
.t-count-down--square > .t-count-down__split--text,
.t-count-down--round > .t-count-down__split--text {
color: var(--td-text-color-primary, var(--td-font-gray-1, rgba(0, 0, 0, 0.9)));
}
.t-count-down--default {
color: var(--td-countdown-default-color, var(--td-text-color-primary, var(--td-font-gray-1, rgba(0, 0, 0, 0.9))));
}
.t-count-down--square {
color: var(--td-countdown-round-color, var(--td-text-color-anti, var(--td-font-white-1, #ffffff)));
}
.t-count-down--square > .t-count-down__item {
border-radius: var(--td-countdown-square-border-radius, var(--td-radius-small, 6rpx));
background: var(--td-countdown-bg-color, var(--td-error-color, var(--td-error-color-6, #d54941)));
}
.t-count-down--round {
color: var(--td-countdown-round-color, var(--td-text-color-anti, var(--td-font-white-1, #ffffff)));
}
.t-count-down--round > .t-count-down__item {
border-radius: var(--td-countdown-round-border-radius, var(--td-radius-circle, 50%));
background: var(--td-countdown-bg-color, var(--td-error-color, var(--td-error-color-6, #d54941)));
}

View File

@@ -0,0 +1,3 @@
import { TdCountDownProps } from './type';
declare const props: TdCountDownProps;
export default props;

View File

@@ -0,0 +1,36 @@
const props = {
autoStart: {
type: Boolean,
value: true,
},
content: {
type: String,
value: 'default',
},
format: {
type: String,
value: 'HH:mm:ss',
},
millisecond: {
type: Boolean,
value: false,
},
size: {
type: String,
value: 'medium',
},
splitWithUnit: {
type: Boolean,
value: false,
},
theme: {
type: String,
value: 'default',
},
time: {
type: Number,
value: 0,
required: true,
},
};
export default props;

View File

@@ -0,0 +1,35 @@
export interface TdCountDownProps {
autoStart?: {
type: BooleanConstructor;
value?: boolean;
};
content?: {
type: StringConstructor;
value?: string;
};
format?: {
type: StringConstructor;
value?: string;
};
millisecond?: {
type: BooleanConstructor;
value?: boolean;
};
size?: {
type: StringConstructor;
value?: 'small' | 'medium' | 'large';
};
splitWithUnit?: {
type: BooleanConstructor;
value?: boolean;
};
theme?: {
type: StringConstructor;
value?: 'default' | 'round' | 'square';
};
time: {
type: NumberConstructor;
value?: number;
required?: boolean;
};
}

View File

@@ -0,0 +1 @@
export {};

View File

@@ -0,0 +1,25 @@
export interface TimeData {
DD: number;
HH: number;
mm: number;
ss: number;
SSS: number;
}
export declare const TimeDataUnit: {
DD: string;
HH: string;
mm: string;
ss: string;
SSS: string;
};
export declare const parseTimeData: (time: number) => TimeData;
export declare const isSameSecond: (time1: number, time2: number) => boolean;
export declare type TTimeList = {
digit: string;
unit: string;
match: string;
}[];
export declare const parseFormat: (time: number, format: string) => {
timeText: string;
timeList: TTimeList;
};

View File

@@ -0,0 +1,61 @@
export const TimeDataUnit = {
DD: '天',
HH: '时',
mm: '分',
ss: '秒',
SSS: '毫秒',
};
const SECOND = 1000;
const MINUTE = 60 * SECOND;
const HOUR = 60 * MINUTE;
const DAY = 24 * HOUR;
export const parseTimeData = function (time) {
const days = Math.floor(time / DAY);
const hours = Math.floor((time % DAY) / HOUR);
const minutes = Math.floor((time % HOUR) / MINUTE);
const seconds = Math.floor((time % MINUTE) / SECOND);
const milliseconds = Math.floor(time % SECOND);
return {
DD: days,
HH: hours,
mm: minutes,
ss: seconds,
SSS: milliseconds,
};
};
export const isSameSecond = function (time1, time2) {
return Math.floor(time1 / 1000) === Math.floor(time2 / 1000);
};
export const parseFormat = function (time, format) {
const obj = {
'D+': Math.floor(time / 86400000),
'H+': Math.floor((time % 86400000) / 3600000),
'm+': Math.floor((time % 3600000) / 60000),
's+': Math.floor((time % 60000) / 1000),
'S+': Math.floor(time % 1000),
};
const timeList = [];
let timeText = format;
Object.keys(obj).forEach((prop) => {
if (new RegExp(`(${prop})`).test(timeText)) {
timeText = timeText.replace(RegExp.$1, (match, offset, source) => {
const v = `${obj[prop]}`;
let digit = v;
if (match.length > 1) {
digit = (match.replace(new RegExp(match[0], 'g'), '0') + v).substr(v.length);
}
const unit = source.substr(offset + match.length);
const last = timeList[timeList.length - 1];
if (last) {
const index = last.unit.indexOf(match);
if (index !== -1) {
last.unit = last.unit.substr(0, index);
}
}
timeList.push({ digit, unit, match });
return digit;
});
}
});
return { timeText, timeList };
};