* refactor(switch): support customize checked value #4329 * test: add test case * refactor: update props name * refactor: update ts * refactor: optimizepull/4346/head
parent
9e0244dfc3
commit
427cf36eaa
|
@ -4,6 +4,7 @@ import focusTest from '../../../tests/shared/focusTest';
|
||||||
import { resetWarned } from '../../_util/warning';
|
import { resetWarned } from '../../_util/warning';
|
||||||
import mountTest from '../../../tests/shared/mountTest';
|
import mountTest from '../../../tests/shared/mountTest';
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
|
import { asyncExpect } from '@/tests/utils';
|
||||||
|
|
||||||
describe('Switch', () => {
|
describe('Switch', () => {
|
||||||
focusTest(Switch);
|
focusTest(Switch);
|
||||||
|
@ -42,4 +43,31 @@ describe('Switch', () => {
|
||||||
);
|
);
|
||||||
errorSpy.mockRestore();
|
errorSpy.mockRestore();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('customize checked value should work', async () => {
|
||||||
|
resetWarned();
|
||||||
|
const checked = ref(1);
|
||||||
|
const onUpdate = val => (checked.value = val);
|
||||||
|
const wrapper = mount({
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<Switch
|
||||||
|
{...{ 'onUpdate:checked': onUpdate }}
|
||||||
|
checked={checked.value}
|
||||||
|
uncheckedValue={1}
|
||||||
|
checkedValue={2}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
await asyncExpect(() => {
|
||||||
|
wrapper.find('button').trigger('click');
|
||||||
|
});
|
||||||
|
expect(checked.value).toBe(2);
|
||||||
|
|
||||||
|
await asyncExpect(() => {
|
||||||
|
wrapper.find('button').trigger('click');
|
||||||
|
});
|
||||||
|
expect(checked.value).toBe(1);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import type { ExtractPropTypes } from 'vue';
|
import type { ExtractPropTypes, PropType } from 'vue';
|
||||||
import {
|
import {
|
||||||
defineComponent,
|
defineComponent,
|
||||||
inject,
|
inject,
|
||||||
|
@ -19,23 +19,35 @@ import { tuple, withInstall } from '../_util/type';
|
||||||
import { getPropsSlot } from '../_util/props-util';
|
import { getPropsSlot } from '../_util/props-util';
|
||||||
import Omit from 'omit.js';
|
import Omit from 'omit.js';
|
||||||
|
|
||||||
export const SwitchSizes = tuple('small', 'default', 'large');
|
export const SwitchSizes = tuple('small', 'default');
|
||||||
|
|
||||||
const switchProps = {
|
const switchProps = {
|
||||||
prefixCls: PropTypes.string,
|
prefixCls: PropTypes.string,
|
||||||
size: PropTypes.oneOf(SwitchSizes),
|
size: PropTypes.oneOf(SwitchSizes),
|
||||||
disabled: PropTypes.looseBool,
|
disabled: PropTypes.looseBool,
|
||||||
checkedChildren: PropTypes.any,
|
checkedChildren: PropTypes.VNodeChild,
|
||||||
unCheckedChildren: PropTypes.any,
|
unCheckedChildren: PropTypes.VNodeChild,
|
||||||
tabindex: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
tabindex: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||||
autofocus: PropTypes.looseBool,
|
autofocus: PropTypes.looseBool,
|
||||||
loading: PropTypes.looseBool,
|
loading: PropTypes.looseBool,
|
||||||
checked: PropTypes.looseBool,
|
checked: PropTypes.any,
|
||||||
onChange: PropTypes.func,
|
checkedValue: PropTypes.any.def(true),
|
||||||
onClick: PropTypes.func,
|
uncheckedValue: PropTypes.any.def(false),
|
||||||
onKeydown: PropTypes.func,
|
onChange: {
|
||||||
onMouseup: PropTypes.func,
|
type: Function as PropType<(checked: any, e: Event) => void>,
|
||||||
'onUpdate:checked': PropTypes.func,
|
},
|
||||||
|
onClick: {
|
||||||
|
type: Function as PropType<(checked: any, e: Event) => void>,
|
||||||
|
},
|
||||||
|
onKeydown: {
|
||||||
|
type: Function as PropType<(e: Event) => void>,
|
||||||
|
},
|
||||||
|
onMouseup: {
|
||||||
|
type: Function as PropType<(e: Event) => void>,
|
||||||
|
},
|
||||||
|
'onUpdate:checked': {
|
||||||
|
type: Function as PropType<(checked: any) => void>,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export type SwitchProps = Partial<ExtractPropTypes<typeof switchProps>>;
|
export type SwitchProps = Partial<ExtractPropTypes<typeof switchProps>>;
|
||||||
|
@ -46,7 +58,7 @@ const Switch = defineComponent({
|
||||||
inheritAttrs: false,
|
inheritAttrs: false,
|
||||||
props: switchProps,
|
props: switchProps,
|
||||||
emits: ['update:checked', 'mouseup', 'change', 'click', 'keydown'],
|
emits: ['update:checked', 'mouseup', 'change', 'click', 'keydown'],
|
||||||
setup(props: SwitchProps, { attrs, slots, expose, emit }) {
|
setup(props, { attrs, slots, expose, emit }) {
|
||||||
onBeforeMount(() => {
|
onBeforeMount(() => {
|
||||||
warning(
|
warning(
|
||||||
!('defaultChecked' in attrs),
|
!('defaultChecked' in attrs),
|
||||||
|
@ -59,12 +71,13 @@ const Switch = defineComponent({
|
||||||
'`value` is not validate prop, do you mean `checked`?',
|
'`value` is not validate prop, do you mean `checked`?',
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
const checked = ref(props.checked !== undefined ? !!props.checked : !!attrs.defaultChecked);
|
const checked = ref(props.checked !== undefined ? props.checked : attrs.defaultChecked);
|
||||||
|
const checkedStatus = computed(() => checked.value === props.checkedValue);
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props.checked,
|
() => props.checked,
|
||||||
() => {
|
() => {
|
||||||
checked.value = !!props.checked;
|
checked.value = props.checked;
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -92,29 +105,26 @@ const Switch = defineComponent({
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const setChecked = (check: boolean, e: MouseEvent | KeyboardEvent) => {
|
const setChecked = (check: any, e: MouseEvent | KeyboardEvent) => {
|
||||||
if (props.disabled) {
|
if (props.disabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (props.checked === undefined) {
|
|
||||||
checked.value = check;
|
|
||||||
}
|
|
||||||
emit('update:checked', check);
|
emit('update:checked', check);
|
||||||
emit('change', check, e);
|
emit('change', check, e);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleClick = (e: MouseEvent) => {
|
const handleClick = (e: MouseEvent) => {
|
||||||
focus();
|
focus();
|
||||||
const newChecked = !checked.value;
|
const newChecked = checkedStatus.value ? props.uncheckedValue : props.checkedValue;
|
||||||
setChecked(newChecked, e);
|
setChecked(newChecked, e);
|
||||||
emit('click', newChecked, e);
|
emit('click', newChecked, e);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleKeyDown = (e: KeyboardEvent) => {
|
const handleKeyDown = (e: KeyboardEvent) => {
|
||||||
if (e.keyCode === KeyCode.LEFT) {
|
if (e.keyCode === KeyCode.LEFT) {
|
||||||
setChecked(false, e);
|
setChecked(props.uncheckedValue, e);
|
||||||
} else if (e.keyCode === KeyCode.RIGHT) {
|
} else if (e.keyCode === KeyCode.RIGHT) {
|
||||||
setChecked(true, e);
|
setChecked(props.checkedValue, e);
|
||||||
}
|
}
|
||||||
emit('keydown', e);
|
emit('keydown', e);
|
||||||
};
|
};
|
||||||
|
@ -123,6 +133,13 @@ const Switch = defineComponent({
|
||||||
refSwitchNode.value?.blur();
|
refSwitchNode.value?.blur();
|
||||||
emit('mouseup', e);
|
emit('mouseup', e);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const classNames = computed(() => ({
|
||||||
|
[`${prefixCls.value}-small`]: props.size === 'small',
|
||||||
|
[`${prefixCls.value}-loading`]: props.loading,
|
||||||
|
[`${prefixCls.value}-checked`]: checkedStatus.value,
|
||||||
|
[`${prefixCls.value}-disabled`]: props.disabled,
|
||||||
|
}));
|
||||||
return () => (
|
return () => (
|
||||||
<Wave insertExtraNode>
|
<Wave insertExtraNode>
|
||||||
<button
|
<button
|
||||||
|
@ -133,6 +150,8 @@ const Switch = defineComponent({
|
||||||
'checked',
|
'checked',
|
||||||
'autofocus',
|
'autofocus',
|
||||||
'defaultChecked',
|
'defaultChecked',
|
||||||
|
'checkedValue',
|
||||||
|
'uncheckedValue',
|
||||||
])}
|
])}
|
||||||
{...attrs}
|
{...attrs}
|
||||||
onKeydown={handleKeyDown}
|
onKeydown={handleKeyDown}
|
||||||
|
@ -142,14 +161,13 @@ const Switch = defineComponent({
|
||||||
role="switch"
|
role="switch"
|
||||||
aria-checked={checked.value}
|
aria-checked={checked.value}
|
||||||
disabled={props.disabled || props.loading}
|
disabled={props.disabled || props.loading}
|
||||||
class={{
|
class={[
|
||||||
[attrs.class as string]: attrs.class,
|
{
|
||||||
[prefixCls.value]: true,
|
[attrs.class as string]: !!attrs.class,
|
||||||
[`${prefixCls.value}-small`]: props.size === 'small',
|
[prefixCls.value]: true,
|
||||||
[`${prefixCls.value}-loading`]: props.loading,
|
},
|
||||||
[`${prefixCls.value}-checked`]: checked.value,
|
classNames.value,
|
||||||
[`${prefixCls.value}-disabled`]: props.disabled,
|
]}
|
||||||
}}
|
|
||||||
ref={refSwitchNode}
|
ref={refSwitchNode}
|
||||||
>
|
>
|
||||||
{props.loading ? <LoadingOutlined class={`${prefixCls.value}-loading-icon`} /> : null}
|
{props.loading ? <LoadingOutlined class={`${prefixCls.value}-loading-icon`} /> : null}
|
||||||
|
|
Loading…
Reference in New Issue