提交 b16368ec 编写于 作者: D DCloud_LXH

feat(h5): progress

上级 d700685c
......@@ -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'
......
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<typeof props>
type ProgerssState = ReturnType<typeof useProgressState>
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 (
<uni-progress class="uni-progress" {...attrs}>
<div style={outerBarStyle} class="uni-progress-bar">
<div style={innerBarStyle} class="uni-progress-inner-bar" />
</div>
{showInfo ? <p class="uni-progress-info">{currentPercent}%</p> : ''}
</uni-progress>
)
}
},
})
function useProgressState(props: ProgressProps) {
const currentPercent = ref<number>(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
}
}
<template>
<uni-progress
class="uni-progress"
v-bind="$attrs"
>
<div
:style="outerBarStyle"
class="uni-progress-bar"
>
<div
:style="innerBarStyle"
class="uni-progress-inner-bar"
/>
</div>
<template v-if="showInfo">
<p class="uni-progress-info">
{{ currentPercent }}%
</p>
</template>
</uni-progress>
</template>
<script>
const VALUES = {
activeColor: '#007AFF',
backgroundColor: '#EBEBEB',
activeMode: 'backwards'
}
export default {
name: 'Progress',
props: {
percent: {
type: [Number, String],
default: 0,
validator (value) {
return !isNaN(parseFloat(value, 10))
}
},
showInfo: {
type: [Boolean, String],
default: false
},
strokeWidth: {
type: [Number, String],
default: 6,
validator (value) {
return !isNaN(parseFloat(value, 10))
}
},
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
}
},
data () {
return {
currentPercent: 0,
strokeTimer: 0,
lastPercent: 0
}
},
computed: {
outerBarStyle () {
return `background-color: ${this.backgroundColor}; height: ${this.strokeWidth}px;`
},
innerBarStyle () {
// 兼容下不推荐的属性,activeColor 优先级高于 color。
let backgroundColor = ''
if (this.color !== VALUES.activeColor && this.activeColor === VALUES.activeColor) {
backgroundColor = this.color
} else {
backgroundColor = this.activeColor
}
return `width: ${this.currentPercent}%;background-color: ${backgroundColor}`
},
realPercent () {
// 确保最终计算时使用的是 Number 类型的值,并且在有效范围内。
let realValue = parseFloat(this.percent, 10)
realValue < 0 && (realValue = 0)
realValue > 100 && (realValue = 100)
return realValue
}
},
watch: {
realPercent (newValue, oldValue) {
this.strokeTimer && clearInterval(this.strokeTimer)
this.lastPercent = oldValue || 0
this._activeAnimation()
}
},
created () {
this._activeAnimation()
},
methods: {
_activeAnimation () {
if (this.active) {
this.currentPercent = this.activeMode === VALUES.activeMode ? 0 : this.lastPercent
this.strokeTimer = setInterval(() => {
if (this.currentPercent + 1 > this.realPercent) {
this.currentPercent = this.realPercent
this.strokeTimer && clearInterval(this.strokeTimer)
} else {
this.currentPercent += 1
}
}, 30)
} else {
this.currentPercent = this.realPercent
}
}
}
}
</script>
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册