first commit

This commit is contained in:
lingxiao865
2026-02-10 08:05:03 +08:00
commit c5af079d8c
1094 changed files with 97530 additions and 0 deletions

View File

@@ -0,0 +1,52 @@
:: BASE_DOC ::
## API
### Progress Props
name | type | default | description | required
-- | -- | -- | -- | --
custom-style | Object | - | CSS(Cascading Style Sheets) | N
color | String / Object / Array | '' | Typescript`string \| Array<string> \| Record<string, string>` | N
label | String / Boolean | true | \- | N
percentage | Number | 0 | \- | N
size | String / Number | 'default' | \- | N
status | String | - | options: success/error/warning/active。Typescript`ProgressStatus` `type ProgressStatus = 'success' \| 'error' \| 'warning' \| 'active'`。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/tree/develop/packages/uniapp-components/progress/type.ts) | N
stroke-width | String / Number | - | \- | N
theme | String | line | options: line/plump/circle。Typescript`ProgressTheme` `type ProgressTheme = 'line' \| 'plump' \| 'circle'`。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/tree/develop/packages/uniapp-components/progress/type.ts) | N
track-color | String | '' | \- | N
### Progress Slots
name | Description
-- | --
label | \-
### Progress External Classes
className | Description
-- | --
t-class | \-
t-class-bar | \-
t-class-label | \-
### CSS Variables
The component provides the following CSS variables, which can be used to customize styles.
Name | Default Value | Description
-- | -- | --
--td-progress-info-dark-color | @text-color-primary | -
--td-progress-info-light-color | @text-color-anti | -
--td-progress-inner-bg-color-active | @bg-color-container | -
--td-progress-inner-bg-color-error | @error-color | -
--td-progress-inner-bg-color-success | @success-color | -
--td-progress-inner-bg-color-warning | @warning-color | -
--td-progress-circle-icon-size | 96rpx | -
--td-progress-circle-inner-bg-color | @bg-color-container | -
--td-progress-circle-label-font | @font-title-extraLarge | -
--td-progress-circle-width | 224rpx | -
--td-progress-inner-bg-color | @brand-color | -
--td-progress-line-stroke-width | 12rpx | -
--td-progress-stroke-circle-width | 12rpx | -
--td-progress-stroke-plump-width | 40rpx | -
--td-progress-track-bg-color | @bg-color-component | -

View File

@@ -0,0 +1,87 @@
---
title: Progress 进度条
description: 用于展示任务当前的进度。
spline: message
isComponent: true
---
## 引入
### 引入组件
可在 `main.ts` 或在需要使用的页面或组件中引入。
```js
import TProgress from '@tdesign/uniapp/progress/progress.vue';
```
### 01 组件类型
{{ base }}
### 02 组件状态
线性进度条
{{ line }}
百分比内显进度条
{{ plump }}
环形进度条
{{ circle }}
## API
### Progress Props
名称 | 类型 | 默认值 | 描述 | 必传
-- | -- | -- | -- | --
custom-style | Object | - | 自定义样式 | N
color | String / Object / Array | '' | 进度条颜色。示例:'#ED7B2F' 或 'orange' 或 `['#f00', '#0ff', '#f0f']``{ '0%': '#f00', '100%': '#0ff' }``{ from: '#000', to: '#000' }` 等。TS 类型:`string \| Array<string> \| Record<string, string>` | N
label | String / Boolean | true | 进度百分比,可自定义 | N
percentage | Number | 0 | 进度条百分比 | N
size | String / Number | 'default' | 进度条尺寸仅对环形进度条有效。可选值default/micro。default 值为 112 micro 值为 24 | N
status | String | - | 进度条状态。可选项success/error/warning/active。TS 类型:`ProgressStatus` `type ProgressStatus = 'success' \| 'error' \| 'warning' \| 'active'`。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/tree/develop/packages/uniapp-components/progress/type.ts) | N
stroke-width | String / Number | - | 进度条线宽,默认单位 `px` | N
theme | String | line | 进度条风格。值为 line标签label显示在进度条右侧值为 plump标签label显示在进度条里面值为 circle标签label显示在进度条正中间。可选项line/plump/circle。TS 类型:`ProgressTheme` `type ProgressTheme = 'line' \| 'plump' \| 'circle'`。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/tree/develop/packages/uniapp-components/progress/type.ts) | N
track-color | String | '' | 进度条未完成部分颜色 | N
### Progress Slots
名称 | 描述
-- | --
label | 进度百分比
### Progress External Classes
类名 | 描述
-- | --
t-class | 根节点样式类
t-class-bar | 进度文字样式类
t-class-label | 标签样式类
### CSS Variables
组件提供了下列 CSS 变量,可用于自定义样式。
名称 | 默认值 | 描述
-- | -- | --
--td-progress-info-dark-color | @text-color-primary | -
--td-progress-info-light-color | @text-color-anti | -
--td-progress-inner-bg-color-active | @bg-color-container | -
--td-progress-inner-bg-color-error | @error-color | -
--td-progress-inner-bg-color-success | @success-color | -
--td-progress-inner-bg-color-warning | @warning-color | -
--td-progress-circle-icon-size | 96rpx | -
--td-progress-circle-inner-bg-color | @bg-color-container | -
--td-progress-circle-label-font | @font-title-extraLarge | -
--td-progress-circle-width | 224rpx | -
--td-progress-inner-bg-color | @brand-color | -
--td-progress-line-stroke-width | 12rpx | -
--td-progress-stroke-circle-width | 12rpx | -
--td-progress-stroke-plump-width | 40rpx | -
--td-progress-track-bg-color | @bg-color-component | -

View File

@@ -0,0 +1,81 @@
import utils from '../common/utils.wxs';
const STATUS = ['success', 'error', 'warning'];
const STATUS_TEXT = ['success', 'error', 'warning', 'active'];
const PRO_THEME = {
LINE: 'line',
PLUMP: 'plump',
CIRCLE: 'circle',
};
const STATUS_COLOR = {
success: '#00a870',
error: '#e34d59',
warning: '#ed7b2f',
};
const LINE_STATUS_ICON = {
success: 'check-circle-filled',
error: 'error-circle-filled',
warning: 'error-circle-filled',
};
const CIRCLE_STATUS_ICON = {
success: 'check',
error: 'close',
warning: 'error',
};
/**
*
* 1. getIOSAriaLabel getAndroidAriaLabel 两个函数的初衷是处理progress异常情况的文案识别。
* 2. iOS可以识别%,而安卓不会识别%,如 80 iOS可以识别成 80% 而安卓只会80因此android部分做了一个% 拼接,后续看是否有更好的方案去解决。
* 3. 安卓 talkback 版本为 8.1.0.278818032 ,只会读一次 80 最新版本talkback 会读 80.0, 80。目前也是一个痛点啰嗦了
*
*/
function getIOSAriaLabel(status) {
if (status === 'error') {
return '进度失败';
}
if (status === 'warning') {
return '进度异常';
}
return '';
}
function getAndroidAriaLabel(status) {
if (status === 'error') {
return '%' + ',进度失败';
}
if (status === 'warning') {
return '%' + ',进度异常';
}
return '%';
}
function getCircleStyle(size, strokeWidth) {
const styles = {
'--td-progress-stroke-circle-width': utils.addUnit(strokeWidth),
};
if (!utils.includes(['default', 'micro'], size)) {
styles['--td-progress-circle-width'] = utils.addUnit(size);
}
return utils._style(styles);
}
export {
STATUS,
STATUS_TEXT,
PRO_THEME,
STATUS_COLOR,
LINE_STATUS_ICON,
CIRCLE_STATUS_ICON,
getAndroidAriaLabel,
getIOSAriaLabel,
getCircleStyle,
};

View File

@@ -0,0 +1,136 @@
.t-progress {
--td-progress-inner-bg-color: var(--td-brand-color, var(--td-primary-color-7, #0052d9));
--td-progress-track-bg-color: var(--td-bg-color-component, var(--td-gray-color-3, #e7e7e7));
--td-progress-circle-from: 0deg;
}
.t-progress__inner {
position: relative;
height: 100%;
background: var(--td-progress-inner-bg-color, var(--td-brand-color, var(--td-primary-color-7, #0052d9)));
border-radius: var(--td-radius-round, 999px);
transition: all var(--td-anim-duration-base, 0.2s) var(--td-anim-time-fn-easing, cubic-bezier(0.38, 0, 0.24, 1));
}
.t-progress__bar {
width: 100%;
height: var(--td-progress-line-stroke-width, 12rpx);
overflow: hidden;
background: var(--td-progress-track-bg-color, var(--td-bg-color-component, var(--td-gray-color-3, #e7e7e7)));
border-radius: var(--td-radius-round, 999px);
}
.t-progress__info {
padding-left: var(--td-spacer, 16rpx);
box-sizing: border-box;
color: var(--td-progress-info-dark-color, var(--td-text-color-primary, var(--td-font-gray-1, rgba(0, 0, 0, 0.9))));
white-space: nowrap;
display: inline-flex;
}
.t-progress--thin {
display: flex;
justify-content: space-between;
align-items: center;
}
.t-progress--thin :deep(.t-progress__icon) {
font-size: calc(var(--td-font-size-base, 28rpx) + 2px);
}
.t-progress--plump {
height: var(--td-progress-stroke-plump-width, 40rpx);
border-radius: calc(var(--td-progress-stroke-plump-width, 40rpx) / 2);
display: flex;
align-items: center;
}
.t-progress--plump .t-progress__info {
font: var(--td-font-body-small, 24rpx / 40rpx var(--td-font-family, PingFang SC, Microsoft YaHei, Arial Regular));
}
.t-progress--over-ten .t-progress__info {
position: absolute;
top: 50%;
right: var(--td-spacer, 16rpx);
color: var(--td-progress-info-light-color, var(--td-text-color-anti, var(--td-font-white-1, #ffffff)));
transform: translateY(-50%);
}
.t-progress--under-ten .t-progress__info,
.t-progress--under-ten .t-progress__inner {
display: inline-block;
}
.t-progress--under-ten .t-progress__info {
vertical-align: top;
}
.t-progress__canvas--circle {
position: relative;
width: var(--td-progress-circle-width, 224rpx);
height: var(--td-progress-circle-width, 224rpx);
border-radius: var(--td-radius-circle, 50%);
}
.t-progress__canvas--circle .t-progress__canvas--inner {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: calc(100% - var(--td-progress-stroke-circle-width, 12rpx)*2);
height: calc(100% - var(--td-progress-stroke-circle-width, 12rpx)*2);
border-radius: var(--td-radius-circle, 50%);
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
background-color: var(--td-progress-circle-inner-bg-color, var(--td-bg-color-container, var(--td-font-white-1, #ffffff)));
}
.t-progress__canvas--circle .t-progress__info {
margin: 0;
padding: 0;
font: var(--td-progress-circle-label-font, var(--td-font-title-extraLarge, 600 40rpx / 56rpx var(--td-font-family, PingFang SC, Microsoft YaHei, Arial Regular)));
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
}
.t-progress__canvas--circle--micro {
--td-progress-circle-width: 48rpx;
--td-progress-stroke-circle-width: 4rpx;
--td-progress-circle-icon-size: 40rpx;
}
.t-progress--status--active .t-progress__inner::before {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 1;
content: '';
animation: progress-active-animation 2s cubic-bezier(0.23, 0.99, 0.86, 0.2) infinite;
background: var(--td-progress-inner-bg-color-active, var(--td-bg-color-container, var(--td-font-white-1, #ffffff)));
opacity: 0.2;
}
.t-progress--status--success .t-progress__inner {
background: var(--td-progress-inner-bg-color-success, var(--td-success-color, var(--td-success-color-5, #2ba471)));
}
.t-progress--status--success :deep(.t-progress__icon) {
color: var(--td-success-color, var(--td-success-color-5, #2ba471));
}
.t-progress--status--warning .t-progress__inner {
background: var(--td-progress-inner-bg-color-warning, var(--td-warning-color, var(--td-warning-color-5, #e37318)));
}
.t-progress--status--warning :deep(.t-progress__icon) {
color: var(--td-warning-color, var(--td-warning-color-5, #e37318));
}
.t-progress--status--error .t-progress__inner {
background: var(--td-progress-inner-bg-color-error, var(--td-error-color, var(--td-error-color-6, #d54941)));
}
.t-progress--status--error :deep(.t-progress__icon) {
color: var(--td-error-color, var(--td-error-color-6, #d54941));
}
@keyframes progress-active-animation {
0% {
width: 0;
opacity: 0.1;
}
35% {
width: 50%;
opacity: 0.4;
}
100% {
width: 100%;
opacity: 0;
}
}

View File

@@ -0,0 +1,259 @@
<template>
<view
:style="tools._style([customStyle])"
:class="classPrefix"
>
<view
v-if="theme === PRO_THEME.LINE"
:class="[
classPrefix + '--thin ' + classPrefix + '--status--' + (status || computedStatus),
tClass
]"
>
<view
aria-role="progressbar"
aria-valuemin="0"
aria-valuemax="100"
:aria-valuenow="computedProgress"
:aria-label="ariaLabel || (isIOS ? getIOSAriaLabel(status) : getAndroidAriaLabel(status))"
aria-live="polite"
:class="classPrefix + '__bar'"
:style="'height: ' + heightBar + 'px;border-radius: ' + heightBar + 'px;background-color: ' + bgColorBar"
>
<view
:class="[
classPrefix + '__inner ',
tClassBar
]"
:style="'background: ' + colorBar + '; width: ' + (computedProgress + '%')"
/>
</view>
<view
v-if="label"
:class="classPrefix + '__info ' + tClassLabel"
:aria-hidden="true"
>
<block
v-if="tools.includes(STATUS, status)"
name="icon"
>
<t-icon
:t-class="classPrefix + '__icon ' + classPrefix + '__icon--'"
:name="LINE_STATUS_ICON[status]"
:size="22 || ''"
/>
</block>
<text v-else>
{{ tools.isString(label) ? label : computedProgress + '%' }}
</text>
</view>
<slot name="label" />
</view>
<view
v-if="theme === PRO_THEME.PLUMP"
aria-role="progressbar"
aria-valuemin="0"
aria-valuemax="100"
:aria-valuenow="computedProgress"
:aria-label="ariaLabel || (isIOS ? getIOSAriaLabel(status) : getAndroidAriaLabel(status))"
aria-live="polite"
:class="
classPrefix +
'__bar ' +
classPrefix +
'--plump ' +
(computedProgress > 10 ? classPrefix + '--over-ten' : classPrefix + '--under-ten') +
' ' +
classPrefix +
'--status--' +
(status || computedStatus) +
' ' +
tClass
"
:style="'height: ' + heightBar + 'px;border-radius: ' + heightBar + 'px;background-color: ' + bgColorBar"
>
<view
:class="classPrefix + '__inner ' + tClassBar"
:style="'background: ' + colorBar + '; width: ' + computedProgress + '%'"
>
<view
v-if="label && computedProgress > 10"
:class="classPrefix + '__info ' + tClassLabel"
>
<text>{{ tools.isString(label) ? label : computedProgress + '%' }}</text>
</view>
<slot
v-if="computedProgress > 10"
name="label"
/>
</view>
<view
v-if="label && computedProgress <= 10"
:class="classPrefix + '__info ' + tClassLabel"
:aria-hidden="true"
>
<text>{{ tools.isString(label) ? label : computedProgress + '%' }}</text>
</view>
<slot
v-if="computedProgress <= 10"
name="label"
/>
</view>
<view
v-if="theme === PRO_THEME.CIRCLE"
:class="classPrefix + '--status--' + (status || computedStatus) + ' ' + tClass"
>
<view
aria-role="progressbar"
aria-valuemin="0"
aria-valuemax="100"
:aria-valuenow="computedProgress"
:aria-label="ariaLabel || (isIOS ? getIOSAriaLabel(status) : getAndroidAriaLabel(status))"
aria-live="polite"
:class="tools.cls(classPrefix + '__canvas--circle', [[size, true]])"
:style="
getCircleStyle(size, heightBar) +
'; background-image: conic-gradient(from var(--td-progress-circle-from), ' +
(colorCircle || STATUS_COLOR[status] || 'var(--td-progress-inner-bg-color)') +
' ' +
computedProgress +
'%, ' +
(bgColorBar || 'var(--td-progress-track-bg-color)') +
' 0%);'
"
>
<view :class="classPrefix + '__canvas--inner ' + tClassBar">
<view
v-if="label"
:class="classPrefix + '__info ' + tClassLabel"
:aria-hidden="true"
>
<block
v-if="tools.includes(STATUS, status)"
name="icon"
>
<t-icon
:t-class="classPrefix + '__icon ' + classPrefix + '__icon--'"
:name="CIRCLE_STATUS_ICON[status]"
size="96rpx"
/>
</block>
<text v-else>
{{ tools.isString(label) ? label : computedProgress + '%' }}
</text>
</view>
<slot name="label" />
</view>
</view>
</view>
</view>
</template>
<script>
import TIcon from '../icon/icon';
import { uniComponent } from '../common/src/index';
import { prefix } from '../common/config';
import props from './props';
import { getBackgroundColor } from './utils';
import { unitConvert, isIOS as isIOSValidator } from '../common/utils';
import tools from '../common/utils.wxs';
import {
STATUS,
STATUS_TEXT,
PRO_THEME,
STATUS_COLOR,
LINE_STATUS_ICON,
CIRCLE_STATUS_ICON,
getCircleStyle,
getIOSAriaLabel,
getAndroidAriaLabel,
} from './computed.js';
const name = `${prefix}-progress`;
export default uniComponent({
name,
options: {
styleIsolation: 'shared',
},
externalClasses: [
`${prefix}-class`,
`${prefix}-class-bar`,
`${prefix}-class-label`,
],
components: {
TIcon,
},
props: {
...props,
},
data() {
return {
prefix,
classPrefix: name,
colorBar: '',
heightBar: '',
computedStatus: '',
computedProgress: 0,
isIOS: isIOSValidator(),
STATUS,
STATUS_TEXT,
PRO_THEME,
STATUS_COLOR,
LINE_STATUS_ICON,
CIRCLE_STATUS_ICON,
getCircleStyle,
getIOSAriaLabel,
getAndroidAriaLabel,
tools,
};
},
watch: {
percentage: {
handler(percentage) {
percentage = Math.max(0, Math.min(percentage, 100));
this.computedStatus = percentage === 100 ? 'success' : '';
this.computedProgress = percentage;
},
immediate: true,
},
color: {
handler(color) {
this.colorBar = getBackgroundColor(color);
this.colorCircle = typeof color === 'object' ? '' : color; // 环形不支持渐变,单独处理
},
immediate: true,
},
strokeWidth: {
handler(strokeWidth) {
if (!strokeWidth) {
return '';
}
this.heightBar = unitConvert(strokeWidth);
},
immediate: true,
},
trackColor: {
handler(trackColor) {
this.bgColorBar = trackColor;
},
immediate: true,
},
},
methods: {
},
});
</script>
<style scoped>
@import './progress.css';
</style>

View File

@@ -0,0 +1,55 @@
/* eslint-disable */
/**
* 该文件为脚本自动生成文件,请勿随意修改。如需修改请联系 PMC
* */
import type { TdProgressProps } from './type';
export default {
/** 进度条颜色。示例:'#ED7B2F' 或 'orange' 或 `['#f00', '#0ff', '#f0f']` 或 `{ '0%': '#f00', '100%': '#0ff' }` 或 `{ from: '#000', to: '#000' }` 等 */
color: {
type: [String, Object, Array],
default: '' as TdProgressProps['color'],
},
/** 进度百分比,可自定义 */
label: {
type: [String, Boolean],
default: true as TdProgressProps['label'],
},
/** 进度条百分比 */
percentage: {
type: Number,
default: 0,
},
/** 进度条尺寸仅对环形进度条有效。可选值default/micro。default 值为 112 micro 值为 24 */
size: {
type: [String, Number],
default: 'default' as TdProgressProps['size'],
},
/** 进度条状态 */
status: {
type: String,
validator(val: TdProgressProps['status']): boolean {
if (!val) return true;
return ['success', 'error', 'warning', 'active'].includes(val);
},
},
/** 进度条线宽,默认单位 `px` */
strokeWidth: {
type: [String, Number],
},
/** 进度条风格。值为 line标签label显示在进度条右侧值为 plump标签label显示在进度条里面值为 circle标签label显示在进度条正中间 */
theme: {
type: String,
default: 'line' as TdProgressProps['theme'],
validator(val: TdProgressProps['theme']): boolean {
if (!val) return true;
return ['line', 'plump', 'circle'].includes(val);
},
},
/** 进度条未完成部分颜色 */
trackColor: {
type: String,
default: '',
},
};

View File

@@ -0,0 +1,50 @@
/* eslint-disable */
/**
* 该文件为脚本自动生成文件,请勿随意修改。如需修改请联系 PMC
* */
export interface TdProgressProps {
/**
* 进度条颜色。示例:'#ED7B2F' 或 'orange' 或 `['#f00', '#0ff', '#f0f']` 或 `{ '0%': '#f00', '100%': '#0ff' }` 或 `{ from: '#000', to: '#000' }` 等
* @default ''
*/
color?: string | Array<string> | Record<string, string>;
/**
* 进度百分比,可自定义
* @default true
*/
label?: string | boolean;
/**
* 进度条百分比
* @default 0
*/
percentage?: number;
/**
* 进度条尺寸仅对环形进度条有效。可选值default/micro。default 值为 112 micro 值为 24
* @default 'default'
*/
size?: string | number;
/**
* 进度条状态
*/
status?: ProgressStatus;
/**
* 进度条线宽,默认单位 `px`
*/
strokeWidth?: string | number;
/**
* 进度条风格。值为 line标签label显示在进度条右侧值为 plump标签label显示在进度条里面值为 circle标签label显示在进度条正中间
* @default line
*/
theme?: ProgressTheme;
/**
* 进度条未完成部分颜色
* @default ''
*/
trackColor?: string;
}
export type ProgressStatus = 'success' | 'error' | 'warning' | 'active';
export type ProgressTheme = 'line' | 'plump' | 'circle';

View File

@@ -0,0 +1,19 @@
export function getBackgroundColor(color) {
if (typeof color === 'string') {
return color;
}
if (Array.isArray(color)) {
if (color[0] && color[0][0] === '#') {
color.unshift('90deg');
}
return `linear-gradient( ${color.join(',')} )`;
}
const { from, to, direction = 'to right', ...rest } = color;
let keys = Object.keys(rest);
if (keys.length) {
keys = keys.sort((a, b) => parseFloat(a.substr(0, a.length - 1)) - parseFloat(b.substr(0, b.length - 1)));
const tempArr = keys.map(key => `${rest[key]} ${key}`);
return `linear-gradient(${direction}, ${tempArr.join(',')})`;
}
return `linear-gradient(${direction}, ${from}, ${to})`;
}