refactor: vc-checkbox
parent
a9a2b782b5
commit
4f3823eeda
|
@ -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';
|
||||
|
|
|
@ -27,7 +27,7 @@ export default defineComponent({
|
|||
setup() {
|
||||
return {
|
||||
checked1: ref(false),
|
||||
checked2: ref(false),
|
||||
checked2: ref(true),
|
||||
};
|
||||
},
|
||||
});
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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