refactor: switch #3885

pull/3923/head
tangjinzhou 4 years ago
parent 67b9da71eb
commit 4a7fcf95f5

@ -1,7 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Switch should has click wave effect 1`] = ` exports[`Switch should has click wave effect 1`] = `
<button class="ant-switch ant-switch-checked" type="button" role="switch" aria-checked="true"> <button type="button" role="switch" aria-checked="true" class="ant-switch ant-switch-checked">
<!----><span class="ant-switch-inner"><!----></span> <!----><span class="ant-switch-inner"><!----></span>
</button> </button>
`; `;

@ -1,7 +1,16 @@
import { defineComponent, inject, onBeforeMount, ref, ExtractPropTypes, computed } from 'vue'; import {
defineComponent,
inject,
onBeforeMount,
ref,
ExtractPropTypes,
computed,
onMounted,
nextTick,
} from 'vue';
import LoadingOutlined from '@ant-design/icons-vue/LoadingOutlined'; import LoadingOutlined from '@ant-design/icons-vue/LoadingOutlined';
import PropTypes from '../_util/vue-types'; import PropTypes from '../_util/vue-types';
import VcSwitch from '../vc-switch'; import KeyCode from '../_util/KeyCode';
import Wave from '../_util/wave'; import Wave from '../_util/wave';
import { defaultConfigProvider } from '../config-provider'; import { defaultConfigProvider } from '../config-provider';
import warning from '../_util/warning'; import warning from '../_util/warning';
@ -18,7 +27,7 @@ const switchProps = {
checkedChildren: PropTypes.any, checkedChildren: PropTypes.any,
unCheckedChildren: PropTypes.any, unCheckedChildren: PropTypes.any,
tabindex: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), tabindex: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
// defaultChecked: PropTypes.looseBool, defaultChecked: PropTypes.looseBool,
autofocus: PropTypes.looseBool, autofocus: PropTypes.looseBool,
loading: PropTypes.looseBool, loading: PropTypes.looseBool,
checked: PropTypes.looseBool, checked: PropTypes.looseBool,
@ -31,10 +40,24 @@ const Switch = defineComponent({
__ANT_SWITCH: true, __ANT_SWITCH: true,
inheritAttrs: false, inheritAttrs: false,
props: switchProps, props: switchProps,
setup(props: SwitchProps, { attrs, slots, expose }) { emits: ['update:checked', 'mouseup', 'change', 'click', 'keydown'],
setup(props: SwitchProps, { attrs, slots, expose, emit }) {
onBeforeMount(() => {
warning(
!('defaultChecked' in attrs),
'Switch',
`'defaultChecked' is deprecated, please use 'v-model:checked'`,
);
warning(
!('value' in attrs),
'Switch',
'`value` is not validate prop, do you mean `checked`?',
);
});
const configProvider = inject('configProvider', defaultConfigProvider); const configProvider = inject('configProvider', defaultConfigProvider);
const { getPrefixCls } = configProvider;
const refSwitchNode = ref(); const refSwitchNode = ref();
const focus = () => { const focus = () => {
refSwitchNode.value?.focus(); refSwitchNode.value?.focus();
}; };
@ -44,42 +67,85 @@ const Switch = defineComponent({
expose({ focus, blur }); expose({ focus, blur });
onBeforeMount(() => {
if ('defaultChecked' in attrs) {
console.warn(
`[antdv: Switch]: 'defaultChecked' will be obsolete, please use 'v-model:checked'`,
);
}
warning(
!('value' in attrs),
'Switch',
'`value` is not validate prop, do you mean `checked`?',
);
});
const { getPrefixCls } = configProvider;
const prefixCls = computed(() => { const prefixCls = computed(() => {
return getPrefixCls('switch', props.prefixCls); return getPrefixCls('switch', props.prefixCls);
}); });
const checked = computed(() => {
return 'checked' in props ? !!props.checked : !!props.defaultChecked;
});
onMounted(() => {
nextTick(() => {
if (props.autofocus && !props.disabled) {
refSwitchNode.value.focus();
}
});
});
const setChecked = (check: boolean, e: MouseEvent | KeyboardEvent) => {
if (props.disabled) {
return;
}
emit('update:checked', check);
emit('change', check, e);
};
const handleClick = (e: MouseEvent) => {
focus();
const newChecked = !checked.value;
setChecked(newChecked, e);
emit('click', newChecked, e);
};
const handleKeyDown = (e: KeyboardEvent) => {
if (e.keyCode === KeyCode.LEFT) {
setChecked(false, e);
} else if (e.keyCode === KeyCode.RIGHT) {
setChecked(true, e);
}
emit('keydown', e);
};
const handleMouseUp = (e: MouseEvent) => {
refSwitchNode.value?.blur();
emit('mouseup', e);
};
return () => ( return () => (
<Wave insertExtraNode> <Wave insertExtraNode>
<VcSwitch <button
{...Omit(props, ['prefixCls', 'size', 'loading', 'disabled'])} {...Omit(props, [
'prefixCls',
'checkedChildren',
'unCheckedChildren',
'checked',
'autofocus',
'defaultChecked',
])}
{...attrs} {...attrs}
checked={props.checked} onKeydown={handleKeyDown}
prefixCls={prefixCls.value} onClick={handleClick}
loadingIcon={ onMouseup={handleMouseUp}
props.loading ? <LoadingOutlined class={`${prefixCls.value}-loading-icon`} /> : null type="button"
} role="switch"
checkedChildren={getPropsSlot(slots, props, 'checkedChildren')} aria-checked={checked.value}
unCheckedChildren={getPropsSlot(slots, props, 'unCheckedChildren')}
disabled={props.disabled || props.loading} disabled={props.disabled || props.loading}
class={{ class={{
[attrs.class as string]: attrs.class, [attrs.class as string]: attrs.class,
[prefixCls.value]: true,
[`${prefixCls.value}-small`]: props.size === 'small', [`${prefixCls.value}-small`]: props.size === 'small',
[`${prefixCls.value}-loading`]: props.loading, [`${prefixCls.value}-loading`]: props.loading,
[`${prefixCls.value}-checked`]: checked.value,
[`${prefixCls.value}-disabled`]: props.disabled,
}} }}
ref={refSwitchNode} ref={refSwitchNode}
/> >
{props.loading ? <LoadingOutlined class={`${prefixCls.value}-loading-icon`} /> : null}
<span class={`${prefixCls.value}-inner`}>
{checked.value
? getPropsSlot(slots, props, 'checkedChildren')
: getPropsSlot(slots, props, 'unCheckedChildren')}
</span>
</button>
</Wave> </Wave>
); );
}, },

@ -1,117 +0,0 @@
@switchPrefixCls: rc-switch;
@duration: 0.3s;
.@{switchPrefixCls} {
position: relative;
display: inline-block;
box-sizing: border-box;
width: 44px;
height: 22px;
line-height: 20px;
padding: 0;
vertical-align: middle;
border-radius: 20px 20px;
border: 1px solid #ccc;
background-color: #ccc;
cursor: pointer;
transition: all @duration cubic-bezier(0.35, 0, 0.25, 1);
&-inner {
color: #fff;
font-size: 12px;
position: absolute;
left: 24px;
top: 0;
}
&:after {
position: absolute;
width: 18px;
height: 18px;
left: 2px;
top: 1px;
border-radius: 50% 50%;
background-color: #fff;
content: ' ';
cursor: pointer;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.26);
transform: scale(1);
transition: left @duration cubic-bezier(0.35, 0, 0.25, 1);
animation-timing-function: cubic-bezier(0.35, 0, 0.25, 1);
animation-duration: @duration;
animation-name: rcSwitchOff;
}
&:hover:after {
transform: scale(1.1);
animation-name: rcSwitchOn;
}
&:focus {
box-shadow: 0 0 0 2px tint(#2db7f5, 80%);
outline: none;
}
&-checked {
border: 1px solid #87d068;
background-color: #87d068;
.@{switchPrefixCls}-inner {
left: 6px;
}
&:after {
left: 22px;
}
}
&-disabled {
cursor: no-drop;
background: #ccc;
border-color: #ccc;
&:after {
background: #9e9e9e;
animation-name: none;
cursor: no-drop;
}
&:hover:after {
transform: scale(1);
animation-name: none;
}
}
&-label {
display: inline-block;
line-height: 20px;
font-size: 14px;
padding-left: 10px;
vertical-align: middle;
white-space: normal;
pointer-events: none;
user-select: text;
}
}
@keyframes rcSwitchOn {
0% {
transform: scale(1);
}
50% {
transform: scale(1.25);
}
100% {
transform: scale(1.1);
}
}
@keyframes rcSwitchOff {
0% {
transform: scale(1.1);
}
100% {
transform: scale(1);
}
}

@ -1,4 +0,0 @@
// base rc-switch 1.9.0
import Switch from './src/Switch';
export default Switch;

@ -1,16 +0,0 @@
import PropTypes from '../../_util/vue-types';
export const switchPropTypes = {
prefixCls: PropTypes.string,
disabled: PropTypes.looseBool.def(false),
checkedChildren: PropTypes.any,
unCheckedChildren: PropTypes.any,
// onChange: PropTypes.func,
// onMouseUp: PropTypes.func,
// onClick: PropTypes.func,
tabindex: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
checked: PropTypes.looseBool,
defaultChecked: PropTypes.looseBool.def(false),
autofocus: PropTypes.looseBool.def(false),
loadingIcon: PropTypes.any,
};

@ -1,99 +0,0 @@
import { switchPropTypes } from './PropTypes';
import Omit from 'omit.js';
import { defineComponent, nextTick, onMounted, ref } from 'vue';
import KeyCode from '../../_util/KeyCode';
import { getPropsSlot } from '../../_util/props-util';
export default defineComponent({
name: 'VcSwitch',
inheritAttrs: false,
props: {
...switchPropTypes,
prefixCls: switchPropTypes.prefixCls.def('rc-switch'),
},
emits: ['update:checked', 'mouseup', 'change', 'click'],
setup(props, { attrs, slots, emit, expose }) {
const checked = ref('checked' in props ? !!props.checked : !!props.defaultChecked);
const refSwitchNode = ref();
onMounted(() => {
nextTick(() => {
if (props.autofocus && !props.disabled) {
refSwitchNode.value.focus();
}
});
});
const setChecked = (check: boolean, e: MouseEvent | KeyboardEvent) => {
if (props.disabled) {
return;
}
checked.value = !checked.value;
emit('update:checked', checked);
emit('change', check, e);
};
const handleClick = (e: MouseEvent) => {
setChecked(checked.value, e);
emit('click', checked.value, e);
};
const handleKeyDown = (e: KeyboardEvent) => {
if (e.keyCode === KeyCode.LEFT) {
setChecked(false, e);
} else if (e.keyCode === KeyCode.RIGHT) {
setChecked(true, e);
}
};
const handleMouseUp = (e: MouseEvent) => {
refSwitchNode.value?.blur();
emit('mouseup', e);
};
const focus = () => {
refSwitchNode.value?.focus();
};
const blur = () => {
refSwitchNode.value?.blur();
};
expose({ focus, blur });
return () => (
<button
{...Omit(props, [
'prefixCls',
'checkedChildren',
'unCheckedChildren',
'checked',
'autofocus',
'defaultChecked',
])}
{...attrs}
onKeydown={handleKeyDown}
onClick={handleClick}
onMouseup={handleMouseUp}
type="button"
role="switch"
aria-checked={checked.value}
disabled={props.disabled}
class={{
[attrs.class as string]: attrs.class,
[props.prefixCls]: true,
[`${props.prefixCls}-checked`]: checked.value,
[`${props.prefixCls}-disabled`]: props.disabled,
}}
ref={refSwitchNode}
>
{props.loadingIcon}
<span class={`${props.prefixCls}-inner`}>
{checked.value
? getPropsSlot(slots, props, 'checkedChildren')
: getPropsSlot(slots, props, 'unCheckedChildren')}
</span>
</button>
);
},
});

@ -1 +1 @@
Subproject commit 496ff9154658d1ff28917f0bea6adfcb0cd05d43 Subproject commit 31d85319dcc0438b3c80957c99f57b931b047c11
Loading…
Cancel
Save