mirror of
https://github.com/element-plus/element-plus.git
synced 2025-01-30 11:16:12 +08:00
refactor(components): [progress] switch to script-setup syntax (#7795)
This commit is contained in:
parent
ffd83fda93
commit
0c1ed4c133
@ -99,7 +99,7 @@ describe('Progress.vue', () => {
|
||||
const wrapper = mount(Progress, {
|
||||
props: {
|
||||
percentage: 0,
|
||||
color: (percentage) => {
|
||||
color: (percentage: number) => {
|
||||
if (percentage > 50) {
|
||||
return 'rgb(4, 5, 6)'
|
||||
} else {
|
||||
@ -141,7 +141,7 @@ describe('Progress.vue', () => {
|
||||
const wrapper = mount(Progress, {
|
||||
props: {
|
||||
percentage: 100,
|
||||
format: (percent) => `占比${percent}%`,
|
||||
format: (percent: number) => `占比${percent}%`,
|
||||
},
|
||||
})
|
||||
expect(wrapper.find('.el-progress__text').text()).toBe('占比100%')
|
@ -1,8 +1,9 @@
|
||||
import { buildProps, definePropType } from '@element-plus/utils'
|
||||
import type { ExtractPropTypes, SVGAttributes } from 'vue'
|
||||
import type Progress from './progress.vue'
|
||||
|
||||
type Color = { color: string; percentage: number }
|
||||
type ProgressFn = (percentage: number) => string
|
||||
export type ProgressColor = { color: string; percentage: number }
|
||||
export type ProgressFn = (percentage: number) => string
|
||||
|
||||
export const progressProps = buildProps({
|
||||
type: {
|
||||
@ -49,7 +50,7 @@ export const progressProps = buildProps({
|
||||
default: true,
|
||||
},
|
||||
color: {
|
||||
type: definePropType<string | Color[] | ProgressFn>([
|
||||
type: definePropType<string | ProgressColor[] | ProgressFn>([
|
||||
String,
|
||||
Array,
|
||||
Function,
|
||||
@ -63,3 +64,4 @@ export const progressProps = buildProps({
|
||||
} as const)
|
||||
|
||||
export type ProgressProps = ExtractPropTypes<typeof progressProps>
|
||||
export type ProgressInstance = InstanceType<typeof Progress>
|
||||
|
@ -30,7 +30,7 @@
|
||||
v-if="(showText || $slots.default) && textInside"
|
||||
:class="ns.be('bar', 'innerText')"
|
||||
>
|
||||
<slot v-bind="slotData">
|
||||
<slot :percentage="percentage">
|
||||
<span>{{ content }}</span>
|
||||
</slot>
|
||||
</div>
|
||||
@ -68,7 +68,7 @@
|
||||
:class="ns.e('text')"
|
||||
:style="{ fontSize: `${progressTextSize}px` }"
|
||||
>
|
||||
<slot v-bind="slotData">
|
||||
<slot :percentage="percentage">
|
||||
<span v-if="!status">{{ content }}</span>
|
||||
<el-icon v-else><component :is="statusIcon" /></el-icon>
|
||||
</slot>
|
||||
@ -76,8 +76,8 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent } from 'vue'
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue'
|
||||
import { ElIcon } from '@element-plus/components/icon'
|
||||
import {
|
||||
Check,
|
||||
@ -87,177 +87,135 @@ import {
|
||||
WarningFilled,
|
||||
} from '@element-plus/icons-vue'
|
||||
import { useNamespace } from '@element-plus/hooks'
|
||||
import { isFunction, isString } from '@element-plus/utils'
|
||||
import { progressProps } from './progress'
|
||||
import type { CSSProperties } from 'vue'
|
||||
import type { ProgressColor } from './progress'
|
||||
|
||||
export default defineComponent({
|
||||
defineOptions({
|
||||
name: 'ElProgress',
|
||||
components: {
|
||||
ElIcon,
|
||||
CircleCheck,
|
||||
CircleClose,
|
||||
Check,
|
||||
Close,
|
||||
WarningFilled,
|
||||
},
|
||||
props: progressProps,
|
||||
})
|
||||
|
||||
setup(props) {
|
||||
const ns = useNamespace('progress')
|
||||
const STATUS_COLOR_MAP = {
|
||||
success: '#13ce66',
|
||||
exception: '#ff4949',
|
||||
warning: '#e6a23c',
|
||||
default: '#20a0ff',
|
||||
}
|
||||
|
||||
const barStyle = computed(
|
||||
(): CSSProperties => ({
|
||||
width: `${props.percentage}%`,
|
||||
animationDuration: `${props.duration}s`,
|
||||
backgroundColor: getCurrentColor(props.percentage),
|
||||
})
|
||||
const props = defineProps(progressProps)
|
||||
|
||||
const ns = useNamespace('progress')
|
||||
|
||||
const barStyle = computed<CSSProperties>(() => ({
|
||||
width: `${props.percentage}%`,
|
||||
animationDuration: `${props.duration}s`,
|
||||
backgroundColor: getCurrentColor(props.percentage),
|
||||
}))
|
||||
|
||||
const relativeStrokeWidth = computed(() =>
|
||||
((props.strokeWidth / props.width) * 100).toFixed(1)
|
||||
)
|
||||
|
||||
const radius = computed(() => {
|
||||
if (['circle', 'dashboard'].includes(props.type)) {
|
||||
return Number.parseInt(
|
||||
`${50 - Number.parseFloat(relativeStrokeWidth.value) / 2}`,
|
||||
10
|
||||
)
|
||||
}
|
||||
return 0
|
||||
})
|
||||
|
||||
const relativeStrokeWidth = computed(() =>
|
||||
((props.strokeWidth / props.width) * 100).toFixed(1)
|
||||
)
|
||||
|
||||
const radius = computed(() => {
|
||||
if (props.type === 'circle' || props.type === 'dashboard') {
|
||||
return Number.parseInt(
|
||||
`${50 - Number.parseFloat(relativeStrokeWidth.value) / 2}`,
|
||||
10
|
||||
)
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
})
|
||||
|
||||
const trackPath = computed(() => {
|
||||
const r = radius.value
|
||||
const isDashboard = props.type === 'dashboard'
|
||||
return `
|
||||
const trackPath = computed(() => {
|
||||
const r = radius.value
|
||||
const isDashboard = props.type === 'dashboard'
|
||||
return `
|
||||
M 50 50
|
||||
m 0 ${isDashboard ? '' : '-'}${r}
|
||||
a ${r} ${r} 0 1 1 0 ${isDashboard ? '-' : ''}${r * 2}
|
||||
a ${r} ${r} 0 1 1 0 ${isDashboard ? '' : '-'}${r * 2}
|
||||
`
|
||||
})
|
||||
|
||||
const perimeter = computed(() => 2 * Math.PI * radius.value)
|
||||
|
||||
const rate = computed(() => (props.type === 'dashboard' ? 0.75 : 1))
|
||||
|
||||
const strokeDashoffset = computed(() => {
|
||||
const offset = (-1 * perimeter.value * (1 - rate.value)) / 2
|
||||
return `${offset}px`
|
||||
})
|
||||
|
||||
const trailPathStyle = computed(
|
||||
(): CSSProperties => ({
|
||||
strokeDasharray: `${perimeter.value * rate.value}px, ${
|
||||
perimeter.value
|
||||
}px`,
|
||||
strokeDashoffset: strokeDashoffset.value,
|
||||
})
|
||||
)
|
||||
|
||||
const circlePathStyle = computed(
|
||||
(): CSSProperties => ({
|
||||
strokeDasharray: `${
|
||||
perimeter.value * rate.value * (props.percentage / 100)
|
||||
}px, ${perimeter.value}px`,
|
||||
strokeDashoffset: strokeDashoffset.value,
|
||||
transition:
|
||||
'stroke-dasharray 0.6s ease 0s, stroke 0.6s ease, opacity ease 0.6s',
|
||||
})
|
||||
)
|
||||
|
||||
const stroke = computed(() => {
|
||||
let ret: string
|
||||
if (props.color) {
|
||||
ret = getCurrentColor(props.percentage)
|
||||
} else {
|
||||
switch (props.status) {
|
||||
case 'success':
|
||||
ret = '#13ce66'
|
||||
break
|
||||
case 'exception':
|
||||
ret = '#ff4949'
|
||||
break
|
||||
case 'warning':
|
||||
ret = '#e6a23c'
|
||||
break
|
||||
default:
|
||||
ret = '#20a0ff'
|
||||
}
|
||||
}
|
||||
return ret
|
||||
})
|
||||
|
||||
const statusIcon = computed(() => {
|
||||
if (props.status === 'warning') {
|
||||
return WarningFilled
|
||||
}
|
||||
if (props.type === 'line') {
|
||||
return props.status === 'success' ? CircleCheck : CircleClose
|
||||
} else {
|
||||
return props.status === 'success' ? Check : Close
|
||||
}
|
||||
})
|
||||
|
||||
const progressTextSize = computed(() => {
|
||||
return props.type === 'line'
|
||||
? 12 + props.strokeWidth * 0.4
|
||||
: props.width * 0.111111 + 2
|
||||
})
|
||||
|
||||
const content = computed(() => props.format(props.percentage))
|
||||
|
||||
const getCurrentColor = (percentage: number) => {
|
||||
const { color } = props
|
||||
if (typeof color === 'function') {
|
||||
return color(percentage)
|
||||
} else if (typeof color === 'string') {
|
||||
return color
|
||||
} else {
|
||||
const span = 100 / color.length
|
||||
const seriesColors = color.map((seriesColor, index) => {
|
||||
if (typeof seriesColor === 'string') {
|
||||
return {
|
||||
color: seriesColor,
|
||||
percentage: (index + 1) * span,
|
||||
}
|
||||
}
|
||||
return seriesColor
|
||||
})
|
||||
const colors = seriesColors.sort((a, b) => a.percentage - b.percentage)
|
||||
|
||||
for (const color of colors) {
|
||||
if (color.percentage > percentage) return color.color
|
||||
}
|
||||
return colors[colors.length - 1]?.color
|
||||
}
|
||||
}
|
||||
|
||||
const slotData = computed(() => {
|
||||
return {
|
||||
percentage: props.percentage,
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
ns,
|
||||
barStyle,
|
||||
relativeStrokeWidth,
|
||||
radius,
|
||||
trackPath,
|
||||
perimeter,
|
||||
rate,
|
||||
strokeDashoffset,
|
||||
trailPathStyle,
|
||||
circlePathStyle,
|
||||
stroke,
|
||||
statusIcon,
|
||||
progressTextSize,
|
||||
content,
|
||||
slotData,
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
const perimeter = computed(() => 2 * Math.PI * radius.value)
|
||||
|
||||
const rate = computed(() => (props.type === 'dashboard' ? 0.75 : 1))
|
||||
|
||||
const strokeDashoffset = computed(() => {
|
||||
const offset = (-1 * perimeter.value * (1 - rate.value)) / 2
|
||||
return `${offset}px`
|
||||
})
|
||||
|
||||
const trailPathStyle = computed<CSSProperties>(() => ({
|
||||
strokeDasharray: `${perimeter.value * rate.value}px, ${perimeter.value}px`,
|
||||
strokeDashoffset: strokeDashoffset.value,
|
||||
}))
|
||||
|
||||
const circlePathStyle = computed<CSSProperties>(() => ({
|
||||
strokeDasharray: `${
|
||||
perimeter.value * rate.value * (props.percentage / 100)
|
||||
}px, ${perimeter.value}px`,
|
||||
strokeDashoffset: strokeDashoffset.value,
|
||||
transition:
|
||||
'stroke-dasharray 0.6s ease 0s, stroke 0.6s ease, opacity ease 0.6s',
|
||||
}))
|
||||
|
||||
const stroke = computed(() => {
|
||||
let ret: string
|
||||
if (props.color) {
|
||||
ret = getCurrentColor(props.percentage)
|
||||
} else {
|
||||
ret = STATUS_COLOR_MAP[props.status] || STATUS_COLOR_MAP.default
|
||||
}
|
||||
return ret
|
||||
})
|
||||
|
||||
const statusIcon = computed(() => {
|
||||
if (props.status === 'warning') {
|
||||
return WarningFilled
|
||||
}
|
||||
if (props.type === 'line') {
|
||||
return props.status === 'success' ? CircleCheck : CircleClose
|
||||
} else {
|
||||
return props.status === 'success' ? Check : Close
|
||||
}
|
||||
})
|
||||
|
||||
const progressTextSize = computed(() => {
|
||||
return props.type === 'line'
|
||||
? 12 + props.strokeWidth * 0.4
|
||||
: props.width * 0.111111 + 2
|
||||
})
|
||||
|
||||
const content = computed(() => props.format(props.percentage))
|
||||
|
||||
function getColors(color: ProgressColor[]) {
|
||||
const span = 100 / color.length
|
||||
const seriesColors = color.map((seriesColor, index) => {
|
||||
if (isString(seriesColor)) {
|
||||
return {
|
||||
color: seriesColor,
|
||||
percentage: (index + 1) * span,
|
||||
}
|
||||
}
|
||||
return seriesColor
|
||||
})
|
||||
return seriesColors.sort((a, b) => a.percentage - b.percentage)
|
||||
}
|
||||
|
||||
const getCurrentColor = (percentage: number) => {
|
||||
const { color } = props
|
||||
if (isFunction(color)) {
|
||||
return color(percentage)
|
||||
} else if (isString(color)) {
|
||||
return color
|
||||
} else {
|
||||
const colors = getColors(color)
|
||||
for (const color of colors) {
|
||||
if (color.percentage > percentage) return color.color
|
||||
}
|
||||
return colors[colors.length - 1]?.color
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
Loading…
Reference in New Issue
Block a user