diff --git a/packages/uni-components/src/components/index.ts b/packages/uni-components/src/components/index.ts index fbaaaa1ffba1e5db96669dd3a80e49d07c17b5d4..258bcc50a9b89a2bfe443746d5e40875f6161b75 100644 --- a/packages/uni-components/src/components/index.ts +++ b/packages/uni-components/src/components/index.ts @@ -14,7 +14,7 @@ import MovableView from './movable-view/index.vue' import Navigator from './navigator/index.vue' // import PickerView from './picker-view/index.vue' // import PickerViewColumn from './picker-view-column/index.vue' -import Progress from './progress/index.vue' +import Progress from './progress/index' import Radio from './radio/index.vue' import RadioGroup from './radio-group/index.vue' import ResizeSensor from './resize-sensor/index' diff --git a/packages/uni-components/src/components/progress/index.tsx b/packages/uni-components/src/components/progress/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..c6e310dc26632b78ccaacf7d44ebc280e0b2e997 --- /dev/null +++ b/packages/uni-components/src/components/progress/index.tsx @@ -0,0 +1,151 @@ +import { + defineComponent, + ref, + reactive, + watch, + computed, + ExtractPropTypes, +} from 'vue' + +const VALUES = { + activeColor: '#007AFF', + backgroundColor: '#EBEBEB', + activeMode: 'backwards', +} + +const props = { + percent: { + type: [Number, String], + default: 0, + validator(value: number | string) { + return !isNaN(parseFloat(value as string)) + }, + }, + showInfo: { + type: [Boolean, String], + default: false, + }, + strokeWidth: { + type: [Number, String], + default: 6, + validator(value: number | string) { + return !isNaN(parseFloat(value as string)) + }, + }, + color: { + type: String, + default: VALUES.activeColor, + }, + activeColor: { + type: String, + default: VALUES.activeColor, + }, + backgroundColor: { + type: String, + default: VALUES.backgroundColor, + }, + active: { + type: [Boolean, String], + default: false, + }, + activeMode: { + type: String, + default: VALUES.activeMode, + }, + duration: { + type: [Number, String], + default: 30, + validator(value: number | string) { + return !isNaN(parseFloat(value as string)) + }, + }, +} + +type ProgressProps = ExtractPropTypes +type ProgerssState = ReturnType + +export default defineComponent({ + name: 'Progress', + props, + setup(props, { attrs }) { + const state = useProgressState(props) + + _activeAnimation(state, props) + + watch( + () => state.realPercent, + (newValue, oldValue) => { + state.strokeTimer && clearInterval(state.strokeTimer) + state.lastPercent = oldValue || 0 + _activeAnimation(state, props) + } + ) + + return () => { + const { showInfo } = props + const { outerBarStyle, innerBarStyle, currentPercent } = state + + return ( + +
+
+
+ {showInfo ?

{currentPercent}%

: ''} + + ) + } + }, +}) + +function useProgressState(props: ProgressProps) { + const currentPercent = ref(0) + + const outerBarStyle = computed( + () => + `background-color: ${props.backgroundColor}; height: ${props.strokeWidth}px;` + ) + const innerBarStyle = computed(() => { + // 兼容下不推荐的属性,activeColor 优先级高于 color。 + const backgroundColor = + props.color !== VALUES.activeColor && + props.activeColor === VALUES.activeColor + ? props.color + : props.activeColor + return `width: ${currentPercent.value}%;background-color: ${backgroundColor}` + }) + const realPercent = computed(() => { + // 确保最终计算时使用的是 Number 类型的值,并且在有效范围内。 + let realValue = parseFloat(props.percent as string) + realValue < 0 && (realValue = 0) + realValue > 100 && (realValue = 100) + return realValue + }) + + const state = reactive({ + outerBarStyle, + innerBarStyle, + realPercent, + + currentPercent, + strokeTimer: 0, + lastPercent: 0, + }) + return state +} + +function _activeAnimation(state: ProgerssState, props: ProgressProps) { + if (props.active) { + state.currentPercent = + props.activeMode === VALUES.activeMode ? 0 : state.lastPercent + state.strokeTimer = setInterval(() => { + if (state.currentPercent + 1 > state.realPercent) { + state.currentPercent = state.realPercent + state.strokeTimer && clearInterval(state.strokeTimer) + } else { + state.currentPercent += 1 + } + }, parseFloat(props.duration as string)) + } else { + state.currentPercent = state.realPercent + } +} diff --git a/packages/uni-components/src/components/progress/index.vue b/packages/uni-components/src/components/progress/index.vue deleted file mode 100644 index 8b16d70f0c1f791c2d6db3a1b3dc0459e5e8bc40..0000000000000000000000000000000000000000 --- a/packages/uni-components/src/components/progress/index.vue +++ /dev/null @@ -1,127 +0,0 @@ - -