fix(slider): [slider] value of input does not change when using max and min (#1056)

This commit is contained in:
yoyo 2023-12-08 16:29:04 +08:00 committed by GitHub
parent 2a2383b0bb
commit 3bb0f0ff12
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 71 additions and 23 deletions

View File

@ -59,7 +59,8 @@ export default {
'demoId': 'shortcut-operation', 'demoId': 'shortcut-operation',
'name': { 'zh-CN': '快捷键操作', 'en-US': 'Shortcut Key Operations' }, 'name': { 'zh-CN': '快捷键操作', 'en-US': 'Shortcut Key Operations' },
'desc': { 'desc': {
'zh-CN': '<p>通过设置<code>num-pages</code>总步数,即按快捷键 PageDown/PageUp 时,每次移动的距离是 "⌈(max-min)/num-pages⌉"。</p>', 'zh-CN':
'<p>通过设置<code>num-pages</code>总步数,即按快捷键 PageDown/PageUp 时,每次移动的距离是 "⌈(max-min)/num-pages⌉"。</p>',
'en-US': 'en-US':
'<p>Set <code>num-pages</code>the total number of steps. That is, when you press the shortcut key PageDown or PageUp, the moving distance is "⌈(max-min)/num-pages⌉"。</p>' '<p>Set <code>num-pages</code>the total number of steps. That is, when you press the shortcut key PageDown or PageUp, the moving distance is "⌈(max-min)/num-pages⌉"。</p>'
}, },
@ -104,7 +105,7 @@ export default {
'name': { 'zh-CN': '事件', 'en-US': 'Event' }, 'name': { 'zh-CN': '事件', 'en-US': 'Event' },
'desc': { 'zh-CN': '<p>change、start、stop 事件。</p>', 'en-US': '<p>change, start, stop events.</p>' }, 'desc': { 'zh-CN': '<p>change、start、stop 事件。</p>', 'en-US': '<p>change, start, stop events.</p>' },
'codeFiles': ['slider-event.vue'] 'codeFiles': ['slider-event.vue']
}, }
], ],
apis: [ apis: [
{ {
@ -114,7 +115,10 @@ export default {
{ {
'name': 'v-model', 'name': 'v-model',
'type': 'number | [number, number]', 'type': 'number | [number, number]',
'desc': { 'zh-CN': '设置单滑块的当前值,必需是整数或数组', 'en-US': 'Sets the current value of a single slider. The value must be an integer or an array.' }, 'desc': {
'zh-CN': '设置单滑块的当前值,必需是整数或数组',
'en-US': 'Sets the current value of a single slider. The value must be an integer or an array.'
},
'demoId': 'basic-usage' 'demoId': 'basic-usage'
}, },
{ {
@ -180,7 +184,10 @@ export default {
'name': 'height', 'name': 'height',
'type': 'string', 'type': 'string',
'defaultValue': `'300px'`, 'defaultValue': `'300px'`,
'desc': { 'zh-CN': 'Slider组件的高度当vertical为true时有效', 'en-US': 'Height of Slider component, effective when vertical is true' }, 'desc': {
'zh-CN': 'Slider 组件的高度,当 vertical 为 true 时有效',
'en-US': 'Height of Slider component, effective when vertical is true'
},
'demoId': 'vertical-mode' 'demoId': 'vertical-mode'
}, },
{ {
@ -188,8 +195,7 @@ export default {
'type': 'number', 'type': 'number',
'defaultValue': '1', 'defaultValue': '1',
'desc': { 'desc': {
'zh-CN': 'zh-CN': '设置总步数,即按快捷键 PageDown/PageUp 时,每次移动的距离是 "⌈(max-min)/num-pages⌉"',
'设置总步数,即按快捷键 PageDown/PageUp 时,每次移动的距离是 "⌈(max-min)/num-pages⌉"',
'en-US': 'en-US':
'Set the total number of steps. That is, when you press PageDown or PageUp, the moving distance is "⌈(max-min)/num-pages⌉".' 'Set the total number of steps. That is, when you press PageDown or PageUp, the moving distance is "⌈(max-min)/num-pages⌉".'
}, },
@ -209,8 +215,7 @@ export default {
'type': '(value: number | [number, number]) => void', 'type': '(value: number | [number, number]) => void',
'defaultValue': '', 'defaultValue': '',
'desc': { 'desc': {
'zh-CN': 'zh-CN': '值改变时触发(使用鼠标拖曳时,只在松开鼠标后触发)',
'值改变时触发(使用鼠标拖曳时,只在松开鼠标后触发)',
'en-US': 'en-US':
'Triggered when the value changes (When you drag the mouse, it is triggered only after you release the mouse).' 'Triggered when the value changes (When you drag the mouse, it is triggered only after you release the mouse).'
}, },
@ -221,22 +226,18 @@ export default {
'type': '(event: Event, value: number | [number, number]) => void', 'type': '(event: Event, value: number | [number, number]) => void',
'defaultValue': '', 'defaultValue': '',
'desc': { 'desc': {
'zh-CN': 'zh-CN': '设置滑块滑动开始时,触发该事件',
'设置滑块滑动开始时,触发该事件', 'en-US': 'This event is triggered when the slider starts to slide.'
'en-US':
'This event is triggered when the slider starts to slide.'
}, },
'demoId': 'slider-event' 'demoId': 'slider-event'
}, },
{ {
'name': 'Stop', 'name': 'stop',
'type': '(value: number | [number, number]) => void', 'type': '(value: number | [number, number]) => void',
'defaultValue': '', 'defaultValue': '',
'desc': { 'desc': {
'zh-CN': 'zh-CN': '设置滑块滑动结束时,触发该事件',
'设置滑块滑动结束时,触发该事件', 'en-US': 'This event is triggered when the slider sliding ends. '
'en-US':
'This event is triggered when the slider sliding ends. '
}, },
'demoId': 'slider-event' 'demoId': 'slider-event'
} }
@ -246,7 +247,11 @@ export default {
'name': 'default', 'name': 'default',
'type': '', 'type': '',
'defaultValue': '', 'defaultValue': '',
'desc': { 'zh-CN': '显示滑块值的插槽仅仅v-model是单数值时才有效插槽参数为slotArg: { slotScope: number }', 'en-US': 'Slot for displaying slider values, valid only if v-model is a single value. Slot parameters are: slotArg: {slotScope: number}' }, 'desc': {
'zh-CN': '显示滑块值的插槽,仅仅 v-model 是单数值时才有效插槽参数为slotArg: { slotScope: number }',
'en-US':
'Slot for displaying slider values, valid only if v-model is a single value. Slot parameters are: slotArg: {slotScope: number}'
},
'demoId': 'slider-slot' 'demoId': 'slider-slot'
} }
] ]

View File

@ -483,6 +483,11 @@ export const watchActiveValue =
} else { } else {
state.activeValue = nNewValue || 0 state.activeValue = nNewValue || 0
} }
// 正在输入时,不应该改变输入的内容
if (!state.isSlotTyping) {
state.slotValue = state.activeValue
}
} }
export const watchModelValue = export const watchModelValue =
@ -554,3 +559,16 @@ export const inputValueChange =
} }
api.initSlider([Math.min(...state.inputValue), Math.max(...state.inputValue)]) api.initSlider([Math.min(...state.inputValue), Math.max(...state.inputValue)])
} }
export const handleSlotInputFocus = (state: ISliderRenderlessParams['state']) => () => {
state.isSlotTyping = true
}
export const handleSlotInputBlur = (state: ISliderRenderlessParams['state']) => () => {
state.isSlotTyping = false
state.slotValue = state.activeValue
}
export const handleSlotInput = (state: ISliderRenderlessParams['state']) => (event: Event) => {
state.activeValue = Number((event.target as HTMLInputElement).value)
}

View File

@ -38,7 +38,10 @@ import {
watchModelValue, watchModelValue,
getPoints, getPoints,
getLabels, getLabels,
inputValueChange inputValueChange,
handleSlotInputFocus,
handleSlotInputBlur,
handleSlotInput
} from './index' } from './index'
import type { import type {
@ -74,7 +77,10 @@ export const api = [
'customBeforeAppearHook', 'customBeforeAppearHook',
'customAppearHook', 'customAppearHook',
'customAfterAppearHook', 'customAfterAppearHook',
'inputValueChange' 'inputValueChange',
'handleSlotInputFocus',
'handleSlotInputBlur',
'handleSlotInput'
] ]
const initState = ({ reactive, computed, props, api, parent, inject }) => { const initState = ({ reactive, computed, props, api, parent, inject }) => {
@ -106,7 +112,9 @@ const initState = ({ reactive, computed, props, api, parent, inject }) => {
rangeDiff: computed(() => props.max - props.min), rangeDiff: computed(() => props.max - props.min),
tipValue: computed(() => api.formatTipValue(state.activeValue)), tipValue: computed(() => api.formatTipValue(state.activeValue)),
formDisabled: computed(() => (parent.tinyForm || {}).disabled), formDisabled: computed(() => (parent.tinyForm || {}).disabled),
disabled: computed(() => props.disabled || state.formDisabled) disabled: computed(() => props.disabled || state.formDisabled),
slotValue: '',
isSlotTyping: false
}) })
return state return state
@ -150,7 +158,10 @@ export const renderless = (
watchActiveValue: watchActiveValue({ api, emit, props, state }), watchActiveValue: watchActiveValue({ api, emit, props, state }),
getPoints: getPoints({ props, state }), getPoints: getPoints({ props, state }),
getLabels: getLabels({ props, state }), getLabels: getLabels({ props, state }),
inputValueChange: inputValueChange({ props, api, state }) inputValueChange: inputValueChange({ props, api, state }),
handleSlotInputFocus: handleSlotInputFocus(state),
handleSlotInputBlur: handleSlotInputBlur(state),
handleSlotInput: handleSlotInput(state)
}) })
watch(() => props.modelValue, api.watchModelValue, { immediate: true }) watch(() => props.modelValue, api.watchModelValue, { immediate: true })

View File

@ -34,6 +34,10 @@ export interface ISliderState {
tipValue: ComputedRef<string> tipValue: ComputedRef<string>
formDisabled: ComputedRef<boolean> formDisabled: ComputedRef<boolean>
disabled: ComputedRef<boolean> disabled: ComputedRef<boolean>
/** 使用这个值作为插槽中输入的值而不是直接用activeValue来实现在输入时不会被max min属性计算而改变 */
slotValue: number
/** 是否正在输入 */
isSlotTyping: boolean
} }
export interface ISliderApi { export interface ISliderApi {
@ -65,6 +69,9 @@ export interface ISliderApi {
getPoints: () => void getPoints: () => void
getLabels: () => void getLabels: () => void
inputValueChange: () => void inputValueChange: () => void
handleSlotInputFocus: () => void
handleSlotInputBlur: () => void
handleSlotInput: (event: Event) => void
} }
export type ISliderRenderlessParams = ISharedRenderlessFunctionParams<ISliderConstants> & { export type ISliderRenderlessParams = ISharedRenderlessFunctionParams<ISliderConstants> & {

View File

@ -74,7 +74,14 @@
<template v-if="showInput && !state.isDouble"> <template v-if="showInput && !state.isDouble">
<div class="tiny-slider__input"> <div class="tiny-slider__input">
<slot :slot-scope="state.activeValue"> <slot :slot-scope="state.activeValue">
<input type="text" v-model="state.activeValue" :disabled="state.disabled" /><span>%</span> <input
type="text"
v-model="state.slotValue"
@focus="handleSlotInputFocus"
@blur="handleSlotInputBlur"
@input="handleSlotInput"
:disabled="state.disabled"
/><span>%</span>
</slot> </slot>
</div> </div>
</template> </template>