refactor(Checkbox): refactor with composition api

This commit is contained in:
chenjiahan 2020-09-25 11:35:18 +08:00
parent 3ead2f4027
commit 278ea6a439
2 changed files with 85 additions and 83 deletions

View File

@ -1,12 +1,13 @@
import { watch } from 'vue';
import { createNamespace } from '../utils'; import { createNamespace } from '../utils';
import { FieldMixin } from '../mixins/field'; import { CHECKBOX_KEY } from '../checkbox';
import { ParentMixin } from '../mixins/relation'; import { useExpose } from '../composition/use-expose';
import { useChildren } from '../composition/use-relation';
import { useParentField } from '../composition/use-parent-field';
const [createComponent, bem] = createNamespace('checkbox-group'); const [createComponent, bem] = createNamespace('checkbox-group');
export default createComponent({ export default createComponent({
mixins: [ParentMixin('vanCheckbox'), FieldMixin],
props: { props: {
max: [Number, String], max: [Number, String],
disabled: Boolean, disabled: Boolean,
@ -21,31 +22,31 @@ export default createComponent({
emits: ['change', 'update:modelValue'], emits: ['change', 'update:modelValue'],
watch: { setup(props, { emit, slots }) {
modelValue(val) { const { children, linkChildren } = useChildren(CHECKBOX_KEY);
this.$emit('change', val);
},
},
methods: { const toggleAll = (checked) => {
// @exposed-api
toggleAll(checked) {
if (checked === false) { if (checked === false) {
this.$emit('update:modelValue', []); emit('update:modelValue', []);
return; } else {
const names = children
.filter((item) => checked || !item.checked.value)
.map((item) => item.name);
emit('update:modelValue', names);
} }
};
let { children } = this; watch(
if (!checked) { () => props.modelValue,
children = children.filter((item) => !item.checked); (value) => {
emit('change', value);
} }
);
const names = children.map((item) => item.name); useExpose({ toggleAll });
this.$emit('update:modelValue', names); useParentField(() => props.modelValue);
}, linkChildren({ emit, props });
},
render() { return () => <div class={bem([props.direction])}>{slots.default?.()}</div>;
return <div class={bem([this.direction])}>{this.$slots.default?.()}</div>;
}, },
}); });

View File

@ -1,15 +1,18 @@
import { computed, watch } from 'vue';
import { createNamespace, pick } from '../utils'; import { createNamespace, pick } from '../utils';
import { FieldMixin } from '../mixins/field'; import { useExpose } from '../composition/use-expose';
import { ChildrenMixin } from '../mixins/relation'; import { useParentField } from '../composition/use-parent-field';
import { useParent } from '../composition/use-relation';
import Checker, { checkerProps } from './Checker'; import Checker, { checkerProps } from './Checker';
const [createComponent, bem] = createNamespace('checkbox'); const [createComponent, bem] = createNamespace('checkbox');
export default createComponent({ export const CHECKBOX_KEY = 'vanCheckbox';
mixins: [FieldMixin, ChildrenMixin('vanCheckbox')],
export default createComponent({
props: { props: {
...checkerProps, ...checkerProps,
// TODO
bindGroup: { bindGroup: {
type: Boolean, type: Boolean,
default: true, default: true,
@ -18,79 +21,77 @@ export default createComponent({
emits: ['change', 'update:modelValue'], emits: ['change', 'update:modelValue'],
computed: { setup(props, { emit, slots }) {
checked: { const { parent } = useParent(CHECKBOX_KEY);
const setParentValue = (checked) => {
const { name } = props;
const { max, modelValue } = parent.props;
const value = modelValue.slice();
if (checked) {
const overlimit = max && value.length >= max;
if (!overlimit && value.indexOf(name) === -1) {
value.push(name);
parent.emit('update:modelValue', value);
}
} else {
const index = value.indexOf(name);
if (index !== -1) {
value.splice(index, 1);
parent.emit('update:modelValue', value);
}
}
};
const checked = computed({
get() { get() {
if (this.parent) { if (parent) {
return this.parent.modelValue.indexOf(this.name) !== -1; return parent.props.modelValue.indexOf(props.name) !== -1;
} }
return this.modelValue; return props.modelValue;
}, },
set(value) {
set(val) { if (parent) {
if (this.parent) { setParentValue(value);
this.setParentValue(val);
} else { } else {
this.$emit('update:modelValue', val); emit('update:modelValue', value);
} }
}, },
}, });
},
watch: { let toggleTimer;
modelValue(val) { const toggle = (newValue = !checked.value) => {
this.$emit('change', val);
},
},
methods: {
// @exposed-api
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,
// only the last call is valid. // only the last call is valid.
// This is a hack for usage inside Cell. // This is a hack for usage inside Cell.
clearTimeout(this.toggleTask); clearTimeout(toggleTimer);
this.toggleTask = setTimeout(() => { toggleTimer = setTimeout(() => {
this.checked = checked; checked.value = newValue;
}); });
}, };
setParentValue(val) { watch(
const { parent } = this; () => props.modelValue,
const value = parent.modelValue.slice(); (value) => {
emit('change', value);
if (val) {
if (parent.max && value.length >= parent.max) {
return;
}
/* istanbul ignore else */
if (value.indexOf(this.name) === -1) {
value.push(this.name);
parent.$emit('update:modelValue', value);
}
} else {
const index = value.indexOf(this.name);
/* istanbul ignore else */
if (index !== -1) {
value.splice(index, 1);
parent.$emit('update:modelValue', value);
}
} }
}, );
},
render() { useExpose({ toggle, checked });
return ( useParentField(() => props.modelValue);
return () => (
<Checker <Checker
v-slots={pick(this.$slots, ['default', 'icon'])} v-slots={pick(slots, ['default', 'icon'])}
bem={bem} bem={bem}
role="checkbox" role="checkbox"
parent={this.parent} parent={parent}
checked={this.checked} checked={checked.value}
onToggle={this.toggle} onToggle={toggle}
{...this.$props} {...props}
/> />
); );
}, },