mirror of
https://gitee.com/vant-contrib/vant.git
synced 2025-04-23 18:00:27 +08:00
refactor(Checkbox): extract Checker component
This commit is contained in:
parent
f7397e399d
commit
eb68632e50
147
src/checkbox/Checker.js
Normal file
147
src/checkbox/Checker.js
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
import { addUnit } from '../utils';
|
||||||
|
import Icon from '../icon';
|
||||||
|
|
||||||
|
export const checkerProps = {
|
||||||
|
name: null,
|
||||||
|
disabled: Boolean,
|
||||||
|
iconSize: [Number, String],
|
||||||
|
modelValue: null,
|
||||||
|
checkedColor: String,
|
||||||
|
labelPosition: String,
|
||||||
|
labelDisabled: Boolean,
|
||||||
|
shape: {
|
||||||
|
type: String,
|
||||||
|
default: 'round',
|
||||||
|
},
|
||||||
|
bindGroup: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
...checkerProps,
|
||||||
|
bem: Function,
|
||||||
|
role: String,
|
||||||
|
parent: Object,
|
||||||
|
checked: Boolean,
|
||||||
|
},
|
||||||
|
|
||||||
|
emits: ['click', 'toggle'],
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
isDisabled() {
|
||||||
|
return (this.parent && this.parent.disabled) || this.disabled;
|
||||||
|
},
|
||||||
|
|
||||||
|
direction() {
|
||||||
|
return (this.parent && this.parent.direction) || null;
|
||||||
|
},
|
||||||
|
|
||||||
|
iconStyle() {
|
||||||
|
const checkedColor =
|
||||||
|
this.checkedColor || (this.parent && this.parent.checkedColor);
|
||||||
|
|
||||||
|
if (checkedColor && this.checked && !this.isDisabled) {
|
||||||
|
return {
|
||||||
|
borderColor: checkedColor,
|
||||||
|
backgroundColor: checkedColor,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
tabindex() {
|
||||||
|
return this.isDisabled ? -1 : 0;
|
||||||
|
},
|
||||||
|
|
||||||
|
disableBindRelation() {
|
||||||
|
return !this.bindGroup;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
onClick(event) {
|
||||||
|
const { target } = event;
|
||||||
|
const { icon } = this.$refs;
|
||||||
|
const iconClicked = icon === target || icon.contains(target);
|
||||||
|
|
||||||
|
if (!this.isDisabled && (iconClicked || !this.labelDisabled)) {
|
||||||
|
this.$emit('toggle');
|
||||||
|
|
||||||
|
// wait for toggle method to complete
|
||||||
|
// so we can get the changed value in the click event listener
|
||||||
|
setTimeout(() => {
|
||||||
|
this.$emit('click', event);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.$emit('click', event);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
genIcon() {
|
||||||
|
const { checked } = this;
|
||||||
|
const iconSize = this.iconSize || (this.parent && this.parent.iconSize);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
ref="icon"
|
||||||
|
class={this.bem('icon', [
|
||||||
|
this.shape,
|
||||||
|
{ disabled: this.isDisabled, checked },
|
||||||
|
])}
|
||||||
|
style={{ fontSize: addUnit(iconSize) }}
|
||||||
|
>
|
||||||
|
{this.$slots.icon ? (
|
||||||
|
this.$slots.icon({ checked })
|
||||||
|
) : (
|
||||||
|
<Icon name="success" style={this.iconStyle} />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
genLabel() {
|
||||||
|
if (this.$slots.default) {
|
||||||
|
return (
|
||||||
|
<span
|
||||||
|
class={this.bem('label', [
|
||||||
|
this.labelPosition,
|
||||||
|
{ disabled: this.isDisabled },
|
||||||
|
])}
|
||||||
|
>
|
||||||
|
{this.$slots.default()}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const Children = [this.genIcon()];
|
||||||
|
|
||||||
|
if (this.labelPosition === 'left') {
|
||||||
|
Children.unshift(this.genLabel());
|
||||||
|
} else {
|
||||||
|
Children.push(this.genLabel());
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
role={this.role}
|
||||||
|
class={this.bem([
|
||||||
|
{
|
||||||
|
disabled: this.isDisabled,
|
||||||
|
'label-disabled': this.labelDisabled,
|
||||||
|
},
|
||||||
|
this.direction,
|
||||||
|
])}
|
||||||
|
tabindex={this.tabindex}
|
||||||
|
aria-checked={String(this.checked)}
|
||||||
|
onClick={this.onClick}
|
||||||
|
>
|
||||||
|
{Children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
};
|
@ -1,66 +1,18 @@
|
|||||||
import { addUnit, createNamespace } from '../utils';
|
import { createNamespace, pick } from '../utils';
|
||||||
import { FieldMixin } from '../mixins/field';
|
import { FieldMixin } from '../mixins/field';
|
||||||
import { ChildrenMixin } from '../mixins/relation';
|
import { ChildrenMixin } from '../mixins/relation';
|
||||||
import Icon from '../icon';
|
import Checker, { checkerProps } from './Checker';
|
||||||
|
|
||||||
const [createComponent, bem] = createNamespace('checkbox');
|
const [createComponent, bem] = createNamespace('checkbox');
|
||||||
|
|
||||||
export default createComponent({
|
export default createComponent({
|
||||||
mixins: [FieldMixin, ChildrenMixin('vanCheckbox')],
|
mixins: [FieldMixin, ChildrenMixin('vanCheckbox')],
|
||||||
|
|
||||||
props: {
|
props: checkerProps,
|
||||||
name: null,
|
|
||||||
disabled: Boolean,
|
|
||||||
iconSize: [Number, String],
|
|
||||||
modelValue: null,
|
|
||||||
checkedColor: String,
|
|
||||||
labelPosition: String,
|
|
||||||
labelDisabled: Boolean,
|
|
||||||
shape: {
|
|
||||||
type: String,
|
|
||||||
default: 'round',
|
|
||||||
},
|
|
||||||
bindGroup: {
|
|
||||||
type: Boolean,
|
|
||||||
default: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
emits: ['click', 'change', 'update:modelValue'],
|
emits: ['change', 'update:modelValue'],
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
disableBindRelation() {
|
|
||||||
return !this.bindGroup;
|
|
||||||
},
|
|
||||||
|
|
||||||
isDisabled() {
|
|
||||||
return (this.parent && this.parent.disabled) || this.disabled;
|
|
||||||
},
|
|
||||||
|
|
||||||
direction() {
|
|
||||||
return (this.parent && this.parent.direction) || null;
|
|
||||||
},
|
|
||||||
|
|
||||||
iconStyle() {
|
|
||||||
const checkedColor =
|
|
||||||
this.checkedColor || (this.parent && this.parent.checkedColor);
|
|
||||||
|
|
||||||
if (checkedColor && this.checked && !this.isDisabled) {
|
|
||||||
return {
|
|
||||||
borderColor: checkedColor,
|
|
||||||
backgroundColor: checkedColor,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
tabindex() {
|
|
||||||
if (this.isDisabled) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
},
|
|
||||||
|
|
||||||
checked: {
|
checked: {
|
||||||
get() {
|
get() {
|
||||||
if (this.parent) {
|
if (this.parent) {
|
||||||
@ -86,61 +38,6 @@ export default createComponent({
|
|||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
onClick(event) {
|
|
||||||
const { target } = event;
|
|
||||||
const { icon } = this.$refs;
|
|
||||||
const iconClicked = icon === target || icon.contains(target);
|
|
||||||
|
|
||||||
if (!this.isDisabled && (iconClicked || !this.labelDisabled)) {
|
|
||||||
this.toggle();
|
|
||||||
|
|
||||||
// wait for toggle method to complete
|
|
||||||
// so we can get the changed value in the click event listener
|
|
||||||
setTimeout(() => {
|
|
||||||
this.$emit('click', event);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.$emit('click', event);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
genIcon() {
|
|
||||||
const { checked } = this;
|
|
||||||
const iconSize = this.iconSize || (this.parent && this.parent.iconSize);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
ref="icon"
|
|
||||||
class={bem('icon', [
|
|
||||||
this.shape,
|
|
||||||
{ disabled: this.isDisabled, checked },
|
|
||||||
])}
|
|
||||||
style={{ fontSize: addUnit(iconSize) }}
|
|
||||||
>
|
|
||||||
{this.$slots.icon ? (
|
|
||||||
this.$slots.icon({ checked })
|
|
||||||
) : (
|
|
||||||
<Icon name="success" style={this.iconStyle} />
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
genLabel() {
|
|
||||||
if (this.$slots.default) {
|
|
||||||
return (
|
|
||||||
<span
|
|
||||||
class={bem('label', [
|
|
||||||
this.labelPosition,
|
|
||||||
{ disabled: this.isDisabled },
|
|
||||||
])}
|
|
||||||
>
|
|
||||||
{this.$slots.default()}
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// @exposed-api
|
// @exposed-api
|
||||||
toggle(checked = !this.checked) {
|
toggle(checked = !this.checked) {
|
||||||
// When toggle method is called multiple times at the same time,
|
// When toggle method is called multiple times at the same time,
|
||||||
@ -179,30 +76,16 @@ export default createComponent({
|
|||||||
},
|
},
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const Children = [this.genIcon()];
|
|
||||||
|
|
||||||
if (this.labelPosition === 'left') {
|
|
||||||
Children.unshift(this.genLabel());
|
|
||||||
} else {
|
|
||||||
Children.push(this.genLabel());
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<Checker
|
||||||
|
v-slots={pick(this.$slots, ['default', 'icon'])}
|
||||||
|
bem={bem}
|
||||||
role="checkbox"
|
role="checkbox"
|
||||||
class={bem([
|
parent={this.parent}
|
||||||
{
|
checked={this.checked}
|
||||||
disabled: this.isDisabled,
|
onToggle={this.toggle}
|
||||||
'label-disabled': this.labelDisabled,
|
{...this.$props}
|
||||||
},
|
/>
|
||||||
this.direction,
|
|
||||||
])}
|
|
||||||
tabindex={this.tabindex}
|
|
||||||
aria-checked={String(this.checked)}
|
|
||||||
onClick={this.onClick}
|
|
||||||
>
|
|
||||||
{Children}
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -1,57 +1,17 @@
|
|||||||
import { addUnit, createNamespace } from '../utils';
|
import { pick, createNamespace } from '../utils';
|
||||||
import { ChildrenMixin } from '../mixins/relation';
|
import { ChildrenMixin } from '../mixins/relation';
|
||||||
import Icon from '../icon';
|
import Checker, { checkerProps } from '../checkbox/Checker';
|
||||||
|
|
||||||
const [createComponent, bem] = createNamespace('radio');
|
const [createComponent, bem] = createNamespace('radio');
|
||||||
|
|
||||||
export default createComponent({
|
export default createComponent({
|
||||||
mixins: [ChildrenMixin('vanRadio')],
|
mixins: [ChildrenMixin('vanRadio')],
|
||||||
|
|
||||||
props: {
|
props: checkerProps,
|
||||||
name: null,
|
|
||||||
disabled: Boolean,
|
|
||||||
iconSize: [Number, String],
|
|
||||||
modelValue: null,
|
|
||||||
checkedColor: String,
|
|
||||||
labelPosition: String,
|
|
||||||
labelDisabled: Boolean,
|
|
||||||
shape: {
|
|
||||||
type: String,
|
|
||||||
default: 'round',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
emits: ['click', 'update:modelValue'],
|
emits: ['update:modelValue'],
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
isDisabled() {
|
|
||||||
return (this.parent && this.parent.disabled) || this.disabled;
|
|
||||||
},
|
|
||||||
|
|
||||||
direction() {
|
|
||||||
return (this.parent && this.parent.direction) || null;
|
|
||||||
},
|
|
||||||
|
|
||||||
iconStyle() {
|
|
||||||
const checkedColor =
|
|
||||||
this.checkedColor || (this.parent && this.parent.checkedColor);
|
|
||||||
|
|
||||||
if (checkedColor && this.checked && !this.isDisabled) {
|
|
||||||
return {
|
|
||||||
borderColor: checkedColor,
|
|
||||||
backgroundColor: checkedColor,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
tabindex() {
|
|
||||||
if (this.isDisabled || !this.checked) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
},
|
|
||||||
|
|
||||||
currentValue: {
|
currentValue: {
|
||||||
get() {
|
get() {
|
||||||
return this.parent ? this.parent.modelValue : this.modelValue;
|
return this.parent ? this.parent.modelValue : this.modelValue;
|
||||||
@ -71,88 +31,19 @@ export default createComponent({
|
|||||||
toggle() {
|
toggle() {
|
||||||
this.currentValue = this.name;
|
this.currentValue = this.name;
|
||||||
},
|
},
|
||||||
|
|
||||||
onClick(event) {
|
|
||||||
const { target } = event;
|
|
||||||
const { icon } = this.$refs;
|
|
||||||
const iconClicked = icon === target || icon.contains(target);
|
|
||||||
|
|
||||||
if (!this.isDisabled && (iconClicked || !this.labelDisabled)) {
|
|
||||||
this.toggle();
|
|
||||||
|
|
||||||
// wait for toggle method to complete
|
|
||||||
// so we can get the changed value in the click event listener
|
|
||||||
setTimeout(() => {
|
|
||||||
this.$emit('click', event);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.$emit('click', event);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
genIcon() {
|
|
||||||
const { checked } = this;
|
|
||||||
const iconSize = this.iconSize || (this.parent && this.parent.iconSize);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
ref="icon"
|
|
||||||
class={bem('icon', [
|
|
||||||
this.shape,
|
|
||||||
{ disabled: this.isDisabled, checked },
|
|
||||||
])}
|
|
||||||
style={{ fontSize: addUnit(iconSize) }}
|
|
||||||
>
|
|
||||||
{this.$slots.icon ? (
|
|
||||||
this.$slots.icon({ checked })
|
|
||||||
) : (
|
|
||||||
<Icon name="success" style={this.iconStyle} />
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
genLabel() {
|
|
||||||
if (this.$slots.default) {
|
|
||||||
return (
|
|
||||||
<span
|
|
||||||
class={bem('label', [
|
|
||||||
this.labelPosition,
|
|
||||||
{ disabled: this.isDisabled },
|
|
||||||
])}
|
|
||||||
>
|
|
||||||
{this.$slots.default()}
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const Children = [this.genIcon()];
|
|
||||||
|
|
||||||
if (this.labelPosition === 'left') {
|
|
||||||
Children.unshift(this.genLabel());
|
|
||||||
} else {
|
|
||||||
Children.push(this.genLabel());
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<Checker
|
||||||
|
v-slots={pick(this.$slots, ['default', 'icon'])}
|
||||||
|
bem={bem}
|
||||||
role="radio"
|
role="radio"
|
||||||
class={bem([
|
parent={this.parent}
|
||||||
{
|
checked={this.checked}
|
||||||
disabled: this.isDisabled,
|
onToggle={this.toggle}
|
||||||
'label-disabled': this.labelDisabled,
|
{...this.$props}
|
||||||
},
|
/>
|
||||||
this.direction,
|
|
||||||
])}
|
|
||||||
tabindex={this.tabindex}
|
|
||||||
aria-checked={String(this.checked)}
|
|
||||||
onClick={this.onClick}
|
|
||||||
>
|
|
||||||
{Children}
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user