refactor: vc-checkbox
parent
a9a2b782b5
commit
4f3823eeda
|
@ -2,7 +2,7 @@ import type { ExtractPropTypes } from 'vue';
|
||||||
import { defineComponent, inject, nextTick } from 'vue';
|
import { defineComponent, inject, nextTick } from 'vue';
|
||||||
import PropTypes from '../_util/vue-types';
|
import PropTypes from '../_util/vue-types';
|
||||||
import classNames from '../_util/classNames';
|
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 hasProp, { getOptionProps, getSlot } from '../_util/props-util';
|
||||||
import { defaultConfigProvider } from '../config-provider';
|
import { defaultConfigProvider } from '../config-provider';
|
||||||
import warning from '../_util/warning';
|
import warning from '../_util/warning';
|
||||||
|
|
|
@ -27,7 +27,7 @@ export default defineComponent({
|
||||||
setup() {
|
setup() {
|
||||||
return {
|
return {
|
||||||
checked1: ref(false),
|
checked1: ref(false),
|
||||||
checked2: ref(false),
|
checked2: ref(true),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import type { ExtractPropTypes } from 'vue';
|
import type { ExtractPropTypes } from 'vue';
|
||||||
import { defineComponent, inject, ref } from 'vue';
|
import { defineComponent, inject, ref } from 'vue';
|
||||||
import PropTypes from '../_util/vue-types';
|
import PropTypes from '../_util/vue-types';
|
||||||
import VcCheckbox from '../vc-checkbox';
|
import VcCheckbox from '../vc-checkbox/Checkbox';
|
||||||
import classNames from '../_util/classNames';
|
import classNames from '../_util/classNames';
|
||||||
import useConfigInject from '../_util/hooks/useConfigInject';
|
import useConfigInject from '../_util/hooks/useConfigInject';
|
||||||
import type { RadioChangeEvent, RadioGroupContext } from './interface';
|
import type { RadioChangeEvent, RadioGroupContext } from './interface';
|
||||||
|
|
|
@ -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);
|
||||||
|
// onChange没能获取到shiftKey,使用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>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,2 +0,0 @@
|
||||||
// based on rc-checkbox 2.1.7
|
|
||||||
export { default } from './src/';
|
|
|
@ -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);
|
|
||||||
// onChange没能获取到shiftKey,使用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>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
|
|
@ -1,3 +0,0 @@
|
||||||
import Checkbox from './Checkbox';
|
|
||||||
|
|
||||||
export default Checkbox;
|
|
Loading…
Reference in New Issue