提交 026134ae 编写于 作者: d-u-a's avatar d-u-a

feat(nvue): progress

上级 382742d8
import { PRIMARY_COLOR } from '@dcloudio/uni-shared'
const FONT_SIZE = 16
export const PROGRESS_VALUES = {
activeColor: PRIMARY_COLOR,
backgroundColor: '#EBEBEB',
activeMode: 'backwards',
}
export const progressProps = {
percent: {
type: [Number, String],
default: 0,
validator(value: number | string) {
return !isNaN(parseFloat(value as string))
},
},
fontSize: {
type: [String, Number],
default: FONT_SIZE,
},
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: PROGRESS_VALUES.activeColor,
},
activeColor: {
type: String,
default: PROGRESS_VALUES.activeColor,
},
backgroundColor: {
type: String,
default: PROGRESS_VALUES.backgroundColor,
},
active: {
type: [Boolean, String],
default: false,
},
activeMode: {
type: String,
default: PROGRESS_VALUES.activeMode,
},
duration: {
type: [Number, String],
default: 30,
validator(value: number | string) {
return !isNaN(parseFloat(value as string))
},
},
}
......@@ -3,10 +3,12 @@ import Label from './label'
import Button from './button'
import MovableArea from './movable-area'
import MovableView from './movable-view'
import Progress from './progress'
export default {
Navigator,
Label,
Button,
MovableArea,
MovableView,
Progress,
}
import {
defineComponent,
Ref,
ref,
reactive,
watch,
computed,
onMounted,
ExtractPropTypes,
} from 'vue'
import {
useCustomEvent,
EmitEvent,
CustomEventTrigger,
} from '../../helpers/useNvueEvent'
import { getComponentSize } from '../helpers'
import { createNVueTextVNode } from '../utils'
import { PROGRESS_VALUES, progressProps } from '../../components/progress'
const progressStyles: Record<string, Record<string, string | number>>[] = [
{
'uni-progress': {
flex: 1,
flexDirection: 'row',
alignItems: 'center',
},
'uni-progress-bar': {
flex: 1,
},
'uni-progress-inner-bar': {
position: 'absolute',
},
'uni-progress-info': {
marginLeft: '15px',
},
},
]
type ProgressProps = ExtractPropTypes<typeof progressProps>
type ProgerssState = ReturnType<typeof useProgressState>
export default defineComponent({
name: 'Progress',
props: progressProps,
styles: progressStyles,
emits: ['activeend'],
setup(props, { emit }) {
const progressRef: Ref<HTMLElement | null> = ref(null)
const progressBarRef: Ref<HTMLElement | null> = ref(null)
const trigger = useCustomEvent<EmitEvent<typeof emit>>(progressRef, emit)
const state = useProgressState(props)
watch(
() => state.realPercent,
(newValue, oldValue) => {
state.lastPercent = oldValue || 0
_activeAnimation(state, props, trigger)
}
)
onMounted(() => {
setTimeout(() => {
getComponentSize(progressBarRef.value!).then(({ width }) => {
state.progressWidth = width || 0
_activeAnimation(state, props, trigger)
})
}, 50)
})
return () => {
const { showInfo, fontSize } = props
const { outerBarStyle, innerBarStyle, currentPercent } = state
return (
<div ref={progressRef} class="uni-progress">
<div
ref={progressBarRef}
style={outerBarStyle}
class="uni-progress-bar"
>
<div style={innerBarStyle} class="uni-progress-inner-bar"></div>
</div>
{showInfo
? createNVueTextVNode(currentPercent + '%', {
class: 'uni-progress-info',
style: {
fontSize,
},
})
: null}
</div>
)
}
},
})
function useProgressState(props: ProgressProps) {
const currentPercent = ref<number>(0)
const progressWidth = ref<number>(0)
const outerBarStyle = computed(() => ({
backgroundColor: props.backgroundColor,
height: props.strokeWidth,
}))
const innerBarStyle = computed(() => {
// 兼容下不推荐的属性,activeColor 优先级高于 color。
// nvue 不支持百分比,宽度必须为数值。
const backgroundColor =
props.color !== PROGRESS_VALUES.activeColor &&
props.activeColor === PROGRESS_VALUES.activeColor
? props.color
: props.activeColor
return {
width: (currentPercent.value * progressWidth.value) / 100,
height: props.strokeWidth,
backgroundColor: 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,
progressWidth,
})
return state
}
function _activeAnimation(
state: ProgerssState,
props: ProgressProps,
trigger: CustomEventTrigger
) {
state.strokeTimer && clearInterval(state.strokeTimer)
if (props.active) {
state.currentPercent =
props.activeMode === PROGRESS_VALUES.activeMode ? 0 : state.lastPercent
state.strokeTimer = setInterval(() => {
if (state.currentPercent + 1 > state.realPercent) {
state.currentPercent = state.realPercent
state.strokeTimer && clearInterval(state.strokeTimer)
trigger('activeend', {})
} else {
state.currentPercent += 1
}
}, parseFloat(props.duration as string)) as unknown as number
} else {
state.currentPercent = state.realPercent
}
}
import { PRIMARY_COLOR } from '@dcloudio/uni-shared'
import { ref, reactive, watch, computed, ExtractPropTypes } from 'vue'
import { defineBuiltInComponent } from '../../helpers/component'
const VALUES = {
activeColor: PRIMARY_COLOR,
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))
},
},
}
import { PROGRESS_VALUES, progressProps } from '../../components/progress'
type ProgressProps = ExtractPropTypes<typeof props>
type ProgressProps = ExtractPropTypes<typeof progressProps>
type ProgerssState = ReturnType<typeof useProgressState>
export default /*#__PURE__*/ defineBuiltInComponent({
name: 'Progress',
props,
props: progressProps,
setup(props) {
const state = useProgressState(props)
......@@ -107,8 +54,8 @@ function useProgressState(props: ProgressProps) {
const innerBarStyle = computed(() => {
// 兼容下不推荐的属性,activeColor 优先级高于 color。
const backgroundColor =
props.color !== VALUES.activeColor &&
props.activeColor === VALUES.activeColor
props.color !== PROGRESS_VALUES.activeColor &&
props.activeColor === PROGRESS_VALUES.activeColor
? props.color
: props.activeColor
return `width: ${currentPercent.value}%;background-color: ${backgroundColor}`
......@@ -136,7 +83,7 @@ function useProgressState(props: ProgressProps) {
function _activeAnimation(state: ProgerssState, props: ProgressProps) {
if (props.active) {
state.currentPercent =
props.activeMode === VALUES.activeMode ? 0 : state.lastPercent
props.activeMode === PROGRESS_VALUES.activeMode ? 0 : state.lastPercent
state.strokeTimer = setInterval(() => {
if (state.currentPercent + 1 > state.realPercent) {
state.currentPercent = state.realPercent
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册