perf(components): [rate] optimize mousemove and keydown logic (#21847)

refactor(components): [rate] optimaze `mousemove` and `keydown` logic
This commit is contained in:
Zhong
2025-08-26 07:42:32 +08:00
committed by GitHub
parent 0808687d07
commit 3643c9e35f

View File

@@ -24,6 +24,7 @@
@click="selectValue(item)"
>
<el-icon
ref="iconRefs"
:class="[
ns.e('icon'),
{ hover: hoverIndex === item },
@@ -32,9 +33,9 @@
>
<template v-if="!showDecimalIcon(item)">
<component :is="activeComponent" v-show="item <= currentValue" />
<component :is="voidComponent" v-show="!(item <= currentValue)" />
<component :is="voidComponent" v-show="item > currentValue" />
</template>
<template v-if="showDecimalIcon(item)">
<template v-else>
<component :is="voidComponent" :class="[ns.em('decimal', 'box')]" />
<el-icon
:style="decimalStyle"
@@ -57,12 +58,13 @@
<script lang="ts" setup>
import { computed, inject, markRaw, ref, watch } from 'vue'
import { clamp } from 'lodash-unified'
import {
CHANGE_EVENT,
EVENT_CODE,
UPDATE_MODEL_EVENT,
} from '@element-plus/constants'
import { hasClass, isArray, isObject, isString } from '@element-plus/utils'
import { isArray, isObject, isString } from '@element-plus/utils'
import {
formContextKey,
formItemContextKey,
@@ -74,6 +76,7 @@ import { useNamespace } from '@element-plus/hooks'
import { rateEmits, rateProps } from './rate'
import type { CSSProperties, Component } from 'vue'
import type { IconInstance } from '@element-plus/components/icon'
function getValueFromMap<T>(
value: number,
@@ -114,6 +117,10 @@ const currentValue = ref(props.modelValue)
const hoverIndex = ref(-1)
const pointerAtLeftHalf = ref(true)
const iconRefs = ref<IconInstance[]>([])
const iconClientWidths = computed<number[]>(() =>
iconRefs.value.map((icon) => icon.$el.clientWidth)
)
const rateClasses = computed(() => [ns.b(), ns.m(rateSize.value)])
const rateDisabled = computed(() => props.disabled || formContext?.disabled)
const rateStyles = computed(() => {
@@ -238,27 +245,23 @@ function handleKey(e: KeyboardEvent) {
if (rateDisabled.value) {
return
}
let _currentValue = currentValue.value
const code = e.code
const step = props.allowHalf ? 0.5 : 1
let _currentValue = currentValue.value
if (code === EVENT_CODE.up || code === EVENT_CODE.right) {
if (props.allowHalf) {
_currentValue += 0.5
} else {
_currentValue += 1
}
e.stopPropagation()
e.preventDefault()
_currentValue += step
} else if (code === EVENT_CODE.left || code === EVENT_CODE.down) {
if (props.allowHalf) {
_currentValue -= 0.5
} else {
_currentValue -= 1
}
e.stopPropagation()
e.preventDefault()
_currentValue -= step
}
_currentValue = _currentValue < 0 ? 0 : _currentValue
_currentValue = _currentValue > props.max ? props.max : _currentValue
_currentValue = clamp(_currentValue, 0, props.max)
if (_currentValue === currentValue.value) {
return
}
e.stopPropagation()
e.preventDefault()
emit(UPDATE_MODEL_EVENT, _currentValue)
emit(CHANGE_EVENT, _currentValue)
return _currentValue
@@ -269,15 +272,8 @@ function setCurrentValue(value: number, event?: MouseEvent) {
return
}
if (props.allowHalf && event) {
// TODO: use cache via computed https://github.com/element-plus/element-plus/pull/5456#discussion_r786472092
let target = event.target as HTMLElement
if (hasClass(target, ns.e('item'))) {
target = target.querySelector(`.${ns.e('icon')}`)!
}
if (target.clientWidth === 0 || hasClass(target, ns.e('decimal'))) {
target = target.parentNode as HTMLElement
}
pointerAtLeftHalf.value = event.offsetX * 2 <= target.clientWidth
pointerAtLeftHalf.value =
event.offsetX * 2 <= iconClientWidths.value[value - 1]
currentValue.value = pointerAtLeftHalf.value ? value - 0.5 : value
} else {
currentValue.value = value