refactor: vc-checkbox

refactor-checkbox
tangjinzhou 2021-12-27 21:53:31 +08:00
parent a9a2b782b5
commit 4f3823eeda
8 changed files with 160 additions and 306 deletions

View File

@ -2,7 +2,7 @@ import type { ExtractPropTypes } from 'vue';
import { defineComponent, inject, nextTick } from 'vue';
import PropTypes from '../_util/vue-types';
import classNames from '../_util/classNames';
import VcCheckbox from '../vc-checkbox';
import VcCheckbox from '../vc-checkbox/Checkbox';
import hasProp, { getOptionProps, getSlot } from '../_util/props-util';
import { defaultConfigProvider } from '../config-provider';
import warning from '../_util/warning';

View File

@ -27,7 +27,7 @@ export default defineComponent({
setup() {
return {
checked1: ref(false),
checked2: ref(false),
checked2: ref(true),
};
},
});

View File

@ -1,7 +1,7 @@
import type { ExtractPropTypes } from 'vue';
import { defineComponent, inject, ref } from 'vue';
import PropTypes from '../_util/vue-types';
import VcCheckbox from '../vc-checkbox';
import VcCheckbox from '../vc-checkbox/Checkbox';
import classNames from '../_util/classNames';
import useConfigInject from '../_util/hooks/useConfigInject';
import type { RadioChangeEvent, RadioGroupContext } from './interface';

View File

@ -0,0 +1,157 @@
// based on rc-checkbox 2.3.2
import type { HTMLAttributes } from 'vue';
import { nextTick, defineComponent, ref, watch, onMounted } from 'vue';
import classNames from '../_util/classNames';
import PropTypes from '../_util/vue-types';
import { initDefaultProps } from '../_util/props-util';
const checkboxProps = {
prefixCls: String,
name: String,
id: String,
type: String,
defaultChecked: { type: [Boolean, Number], default: undefined },
checked: { type: [Boolean, Number], default: undefined },
disabled: Boolean,
tabindex: { type: [Number, String] },
readonly: Boolean,
autofocus: Boolean,
value: PropTypes.any,
required: Boolean,
};
export default defineComponent({
name: 'Checkbox',
inheritAttrs: false,
props: initDefaultProps(checkboxProps, {
prefixCls: 'rc-checkbox',
type: 'checkbox',
defaultChecked: false,
}),
emits: ['click', 'focus', 'blur', 'change', 'keydown', 'keypress', 'keyup'],
setup(props, { attrs, emit, expose }) {
const checked = ref(props.checked === undefined ? props.defaultChecked : props.checked);
const inputRef = ref<HTMLInputElement>();
watch(
() => props.checked,
() => {
checked.value = props.checked;
},
);
onMounted(() => {
nextTick(() => {
if (process.env.NODE_ENV === 'test') {
if (props.autofocus) {
inputRef.value?.focus();
}
}
});
});
expose({
focus() {
inputRef.value?.focus();
},
blur() {
inputRef.value?.blur();
},
});
const eventShiftKey = ref();
const handleChange = e => {
if (props.disabled) {
return;
}
if (props.checked === undefined) {
checked.value = e.target.checked;
}
e.shiftKey = eventShiftKey.value;
const eventObj = {
target: {
...props,
checked: e.target.checked,
},
stopPropagation() {
e.stopPropagation();
},
preventDefault() {
e.preventDefault();
},
nativeEvent: e,
};
// fix https://github.com/vueComponent/ant-design-vue/issues/3047
//
if (props.checked !== undefined) {
inputRef.value.checked = !!props.checked;
}
emit('change', eventObj);
eventShiftKey.value = false;
};
const onClick = (e: MouseEvent) => {
emit('click', e);
// onChangeshiftKey使onClick hack
eventShiftKey.value = e.shiftKey;
};
return () => {
const {
prefixCls,
name,
id,
type,
disabled,
readonly,
tabindex,
autofocus,
value,
required,
...others
} = props;
const {
class: className,
onFocus,
onBlur,
onKeydown,
onKeypress,
onKeyup,
} = attrs as HTMLAttributes;
const globalProps = Object.keys({ ...others, ...attrs }).reduce((prev, key) => {
if (key.substr(0, 5) === 'aria-' || key.substr(0, 5) === 'data-' || key === 'role') {
prev[key] = others[key];
}
return prev;
}, {});
const classString = classNames(prefixCls, className, {
[`${prefixCls}-checked`]: checked.value,
[`${prefixCls}-disabled`]: disabled,
});
const inputProps = {
name,
id,
type,
readonly,
disabled,
tabindex,
class: `${prefixCls}-input`,
checked: !!checked.value,
autofocus,
value,
...globalProps,
onChange: handleChange,
onClick,
onFocus,
onBlur,
onKeydown,
onKeypress,
onKeyup,
required,
};
return (
<span class={classString}>
<input ref={inputRef} {...inputProps} />
<span class={`${prefixCls}-inner`} />
</span>
);
};
},
});

View File

@ -1,155 +0,0 @@
@checkboxWarpPrefixCls: rc-checkbox;
@checkboxInnerPrefixCls: ~'@{checkboxWarpPrefixCls}-inner';
/* 一般状态 */
.@{checkboxWarpPrefixCls} {
white-space: nowrap;
cursor: pointer;
outline: none;
display: inline-block;
position: relative;
line-height: 1;
vertical-align: middle;
&:hover .@{checkboxInnerPrefixCls},
&-input:focus + .@{checkboxInnerPrefixCls} {
border-color: #3dbcf6;
}
&-inner {
&:after {
-webkit-transform: rotate(45deg);
transform: rotate(45deg);
position: absolute;
left: 4px;
top: 1px;
display: table;
width: 5px;
height: 8px;
border: 2px solid #ffffff;
border-top: 0;
border-left: 0;
content: ' ';
animation-timing-function: cubic-bezier(0.68, -0.55, 0.27, 1.55);
animation-duration: 0.3s;
animation-name: amCheckboxOut;
}
position: relative;
top: 0;
left: 0;
display: inline-block;
width: 14px;
height: 14px;
border-width: 1px;
border-style: solid;
border-radius: 3px;
border-color: #d9d9d9;
background-color: #ffffff;
transition: border-color 0.3s cubic-bezier(0.68, -0.55, 0.27, 1.55),
background-color 0.3s cubic-bezier(0.68, -0.55, 0.27, 1.55);
}
&-input {
position: absolute;
left: 0;
z-index: 9999;
cursor: pointer;
opacity: 0;
top: 0;
bottom: 0;
right: 0;
}
}
/* 选中状态 */
.@{checkboxWarpPrefixCls}-checked {
&:hover {
.@{checkboxInnerPrefixCls} {
border-color: #3dbcf6;
}
}
.@{checkboxInnerPrefixCls} {
border-color: #3dbcf6;
background-color: #3dbcf6;
&:after {
transform: rotate(45deg);
position: absolute;
left: 4px;
top: 1px;
display: table;
width: 5px;
height: 8px;
border: 2px solid #ffffff;
border-top: 0;
border-left: 0;
content: ' ';
animation-timing-function: cubic-bezier(0.68, -0.55, 0.27, 1.55);
animation-duration: 0.3s;
animation-name: amCheckboxOut;
}
}
}
.@{checkboxWarpPrefixCls}-disabled {
&.@{checkboxWarpPrefixCls}-checked {
&:hover {
.@{checkboxInnerPrefixCls} {
border-color: #d9d9d9;
}
}
.@{checkboxInnerPrefixCls} {
background-color: #f3f3f3;
border-color: #d9d9d9;
&:after {
animation-name: none;
border-color: #cccccc;
}
}
}
&:hover {
.@{checkboxInnerPrefixCls} {
border-color: #d9d9d9;
}
}
.@{checkboxInnerPrefixCls} {
border-color: #d9d9d9;
background-color: #f3f3f3;
&:after {
animation-name: none;
border-color: #f3f3f3;
}
}
.@{checkboxInnerPrefixCls}-input {
cursor: default;
}
}
@keyframes amCheckboxIn {
0% {
opacity: 0;
transform-origin: 50% 50%;
transform: scale(0, 0) rotate(45deg);
}
100% {
opacity: 1;
transform-origin: 50% 50%;
transform: scale(1, 1) rotate(45deg);
}
}
@keyframes amCheckboxOut {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}

View File

@ -1,2 +0,0 @@
// based on rc-checkbox 2.1.7
export { default } from './src/';

View File

@ -1,143 +0,0 @@
import { nextTick, defineComponent } from 'vue';
import classNames from '../../_util/classNames';
import PropTypes, { withUndefined } from '../../_util/vue-types';
import BaseMixin from '../../_util/BaseMixin';
import { getOptionProps, hasProp, initDefaultProps } from '../../_util/props-util';
export default defineComponent({
name: 'Checkbox',
mixins: [BaseMixin],
inheritAttrs: false,
props: initDefaultProps(
{
prefixCls: PropTypes.string,
name: PropTypes.string,
id: PropTypes.string,
type: PropTypes.string,
defaultChecked: withUndefined(PropTypes.oneOfType([PropTypes.number, PropTypes.looseBool])),
checked: withUndefined(PropTypes.oneOfType([PropTypes.number, PropTypes.looseBool])),
disabled: PropTypes.looseBool,
// onFocus: PropTypes.func,
// onBlur: PropTypes.func,
// onChange: PropTypes.func,
// onClick: PropTypes.func,
tabindex: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
readonly: PropTypes.looseBool,
autofocus: PropTypes.looseBool,
value: PropTypes.any,
},
{
prefixCls: 'rc-checkbox',
type: 'checkbox',
defaultChecked: false,
},
),
data() {
const checked = hasProp(this, 'checked') ? this.checked : this.defaultChecked;
return {
sChecked: checked,
};
},
watch: {
checked(val) {
this.sChecked = val;
},
},
mounted() {
nextTick(() => {
if (process.env.NODE_ENV === 'test') {
if (this.autofocus) {
this.$refs.input && this.$refs.input.focus();
}
}
});
},
methods: {
focus() {
this.$refs.input.focus();
},
blur() {
this.$refs.input.blur();
},
handleChange(e) {
const props = getOptionProps(this);
if (props.disabled) {
return;
}
if (!('checked' in props)) {
this.sChecked = e.target.checked;
}
e.shiftKey = this.eventShiftKey;
const eventObj = {
target: {
...props,
checked: e.target.checked,
},
stopPropagation() {
e.stopPropagation();
},
preventDefault() {
e.preventDefault();
},
nativeEvent: e,
};
// fix https://github.com/vueComponent/ant-design-vue/issues/3047
//
if ('checked' in props) {
this.$refs.input.checked = props.checked;
}
this.__emit('change', eventObj);
this.eventShiftKey = false;
},
onClick(e) {
this.__emit('click', e);
// onChangeshiftKey使onClick hack
this.eventShiftKey = e.shiftKey;
},
},
render() {
const { prefixCls, name, id, type, disabled, readonly, tabindex, autofocus, value, ...others } =
getOptionProps(this);
const { class: className, onFocus, onBlur } = this.$attrs;
const globalProps = Object.keys({ ...others, ...this.$attrs }).reduce((prev, key) => {
if (key.substr(0, 5) === 'aria-' || key.substr(0, 5) === 'data-' || key === 'role') {
prev[key] = others[key];
}
return prev;
}, {});
const { sChecked } = this;
const classString = classNames(prefixCls, className, {
[`${prefixCls}-checked`]: sChecked,
[`${prefixCls}-disabled`]: disabled,
});
const inputProps = {
name,
id,
type,
readonly,
disabled,
tabindex,
class: `${prefixCls}-input`,
checked: !!sChecked,
autofocus,
value,
...globalProps,
onChange: this.handleChange,
onClick: this.onClick,
onFocus,
onBlur,
};
return (
<span class={classString}>
<input ref="input" {...inputProps} />
<span class={`${prefixCls}-inner`} />
</span>
);
},
});

View File

@ -1,3 +0,0 @@
import Checkbox from './Checkbox';
export default Checkbox;