feat: update checkbox

pull/1790/head
tangjinzhou 2020-02-11 15:21:29 +08:00
parent 81e6391707
commit c0b92c6c50
11 changed files with 132 additions and 60 deletions

View File

@ -1,5 +1,5 @@
module.exports = { module.exports = {
dev: { dev: {
componentName: 'carousel', // dev components componentName: 'checkbox', // dev components
}, },
}; };

View File

@ -1,13 +1,15 @@
import PropTypes from '../_util/vue-types'; import PropTypes from '../_util/vue-types';
import classNames from 'classnames'; import classNames from 'classnames';
import VcCheckbox from '../vc-checkbox'; import VcCheckbox from '../vc-checkbox';
import { getOptionProps, getAttrs, getListeners } from '../_util/props-util'; import hasProp, { getOptionProps, getAttrs, getListeners } from '../_util/props-util';
import { ConfigConsumerProps } from '../config-provider'; import { ConfigConsumerProps } from '../config-provider';
import warning from '../_util/warning';
function noop() {} function noop() {}
export default { export default {
name: 'ACheckbox', name: 'ACheckbox',
inheritAttrs: false, inheritAttrs: false,
__ANT_CHECKBOX: true,
model: { model: {
prop: 'checked', prop: 'checked',
}, },
@ -26,7 +28,36 @@ export default {
}, },
inject: { inject: {
configProvider: { default: () => ConfigConsumerProps }, configProvider: { default: () => ConfigConsumerProps },
checkboxGroupContext: { default: () => null }, checkboxGroupContext: { default: () => undefined },
},
watch: {
value(value, prevValue) {
this.$nextTick(() => {
const { checkboxGroupContext: checkboxGroup = {} } = this;
if (checkboxGroup.registerValue && checkboxGroup.cancelValue) {
checkboxGroup.cancelValue(prevValue);
checkboxGroup.registerValue(value);
}
});
},
},
mounted() {
const { value, checkboxGroupContext: checkboxGroup = {} } = this;
if (checkboxGroup.registerValue) {
checkboxGroup.registerValue(value);
}
warning(
hasProp(this, 'checked') || this.checkboxGroupContext || !hasProp(this, 'value'),
'Checkbox',
'`value` is not validate prop, do you mean `checked`?',
);
},
beforeDestroy() {
const { value, checkboxGroupContext: checkboxGroup = {} } = this;
if (checkboxGroup.cancelValue) {
checkboxGroup.cancelValue(value);
}
}, },
methods: { methods: {
handleChange(event) { handleChange(event) {
@ -61,6 +92,7 @@ export default {
this.$emit('change', ...args); this.$emit('change', ...args);
checkboxGroup.toggleOption({ label: children, value: props.value }); checkboxGroup.toggleOption({ label: children, value: props.value });
}; };
checkboxProps.props.name = checkboxGroup.name;
checkboxProps.props.checked = checkboxGroup.sValue.indexOf(props.value) !== -1; checkboxProps.props.checked = checkboxGroup.sValue.indexOf(props.value) !== -1;
checkboxProps.props.disabled = props.disabled || checkboxGroup.disabled; checkboxProps.props.disabled = props.disabled || checkboxGroup.disabled;
} else { } else {

View File

@ -10,6 +10,7 @@ export default {
prop: 'value', prop: 'value',
}, },
props: { props: {
name: PropTypes.string,
prefixCls: PropTypes.string, prefixCls: PropTypes.string,
defaultValue: PropTypes.array, defaultValue: PropTypes.array,
value: PropTypes.array, value: PropTypes.array,
@ -28,6 +29,7 @@ export default {
const { value, defaultValue } = this; const { value, defaultValue } = this;
return { return {
sValue: value || defaultValue || [], sValue: value || defaultValue || [],
registeredValues: [],
}; };
}, },
watch: { watch: {
@ -52,7 +54,15 @@ export default {
return { ...option, label }; return { ...option, label };
}); });
}, },
cancelValue(value) {
this.registeredValues = this.registeredValues.filter(val => val !== value);
},
registerValue(value) {
this.registeredValues = [...this.registeredValues, value];
},
toggleOption(option) { toggleOption(option) {
const { registeredValues } = this;
const optionIndex = this.sValue.indexOf(option.value); const optionIndex = this.sValue.indexOf(option.value);
const value = [...this.sValue]; const value = [...this.sValue];
if (optionIndex === -1) { if (optionIndex === -1) {
@ -63,8 +73,16 @@ export default {
if (!hasProp(this, 'value')) { if (!hasProp(this, 'value')) {
this.sValue = value; this.sValue = value;
} }
this.$emit('input', value); const options = this.getOptions();
this.$emit('change', value); const val = value
.filter(val => registeredValues.indexOf(val) !== -1)
.sort((a, b) => {
const indexA = options.findIndex(opt => opt.value === a);
const indexB = options.findIndex(opt => opt.value === b);
return indexA - indexB;
});
this.$emit('input', val);
this.$emit('change', val);
}, },
}, },
render() { render() {

View File

@ -24,7 +24,7 @@ exports[`renders ./components/checkbox/demo/disabled.md correctly 1`] = `<div><l
exports[`renders ./components/checkbox/demo/group.md correctly 1`] = ` exports[`renders ./components/checkbox/demo/group.md correctly 1`] = `
<div> <div>
<div class="ant-checkbox-group"><label class="ant-checkbox-wrapper ant-checkbox-group-item"><span class="ant-checkbox"><input type="checkbox" class="ant-checkbox-input" value="Apple"><span class="ant-checkbox-inner"></span></span><span>Apple</span></label><label class="ant-checkbox-wrapper ant-checkbox-group-item"><span class="ant-checkbox"><input type="checkbox" class="ant-checkbox-input" value="Pear"><span class="ant-checkbox-inner"></span></span><span>Pear</span></label><label class="ant-checkbox-wrapper ant-checkbox-group-item"><span class="ant-checkbox"><input type="checkbox" class="ant-checkbox-input" value="Orange"><span class="ant-checkbox-inner"></span></span><span>Orange</span></label></div> <br> <div class="ant-checkbox-group"><label class="ant-checkbox-wrapper ant-checkbox-group-item"><span class="ant-checkbox"><input name="checkboxgroup" type="checkbox" class="ant-checkbox-input" value="Apple"><span class="ant-checkbox-inner"></span></span><span>Apple</span></label><label class="ant-checkbox-wrapper ant-checkbox-group-item"><span class="ant-checkbox"><input name="checkboxgroup" type="checkbox" class="ant-checkbox-input" value="Pear"><span class="ant-checkbox-inner"></span></span><span>Pear</span></label><label class="ant-checkbox-wrapper ant-checkbox-group-item"><span class="ant-checkbox"><input name="checkboxgroup" type="checkbox" class="ant-checkbox-input" value="Orange"><span class="ant-checkbox-inner"></span></span><span>Orange</span></label></div> <br>
<div class="ant-checkbox-group"><label class="ant-checkbox-wrapper ant-checkbox-wrapper-checked ant-checkbox-group-item"><span class="ant-checkbox ant-checkbox-checked"><input type="checkbox" class="ant-checkbox-input" value="Apple"><span class="ant-checkbox-inner"></span></span><span>Apple</span></label><label class="ant-checkbox-wrapper ant-checkbox-group-item"><span class="ant-checkbox"><input type="checkbox" class="ant-checkbox-input" value="Pear"><span class="ant-checkbox-inner"></span></span><span>Pear</span></label><label class="ant-checkbox-wrapper ant-checkbox-group-item"><span class="ant-checkbox"><input type="checkbox" class="ant-checkbox-input" value="Orange"><span class="ant-checkbox-inner"></span></span><span>Orange</span></label></div> <br> <div class="ant-checkbox-group"><label class="ant-checkbox-wrapper ant-checkbox-wrapper-checked ant-checkbox-group-item"><span class="ant-checkbox ant-checkbox-checked"><input type="checkbox" class="ant-checkbox-input" value="Apple"><span class="ant-checkbox-inner"></span></span><span>Apple</span></label><label class="ant-checkbox-wrapper ant-checkbox-group-item"><span class="ant-checkbox"><input type="checkbox" class="ant-checkbox-input" value="Pear"><span class="ant-checkbox-inner"></span></span><span>Pear</span></label><label class="ant-checkbox-wrapper ant-checkbox-group-item"><span class="ant-checkbox"><input type="checkbox" class="ant-checkbox-input" value="Orange"><span class="ant-checkbox-inner"></span></span><span>Orange</span></label></div> <br>
<div class="ant-checkbox-group"><label class="ant-checkbox-wrapper ant-checkbox-group-item"><span class="ant-checkbox"><input type="checkbox" class="ant-checkbox-input" value="Apple"><span class="ant-checkbox-inner"></span></span><span>Apple</span></label><label class="ant-checkbox-wrapper ant-checkbox-wrapper-checked ant-checkbox-group-item"><span class="ant-checkbox ant-checkbox-checked"><input type="checkbox" class="ant-checkbox-input" value="Pear"><span class="ant-checkbox-inner"></span></span><span>Pear</span></label><label class="ant-checkbox-wrapper ant-checkbox-group-item"><span class="ant-checkbox"><input type="checkbox" class="ant-checkbox-input" value="Orange"><span class="ant-checkbox-inner"></span></span><span>Orange</span></label></div> <br> <div class="ant-checkbox-group"><label class="ant-checkbox-wrapper ant-checkbox-group-item"><span class="ant-checkbox"><input type="checkbox" class="ant-checkbox-input" value="Apple"><span class="ant-checkbox-inner"></span></span><span>Apple</span></label><label class="ant-checkbox-wrapper ant-checkbox-wrapper-checked ant-checkbox-group-item"><span class="ant-checkbox ant-checkbox-checked"><input type="checkbox" class="ant-checkbox-input" value="Pear"><span class="ant-checkbox-inner"></span></span><span>Pear</span></label><label class="ant-checkbox-wrapper ant-checkbox-group-item"><span class="ant-checkbox"><input type="checkbox" class="ant-checkbox-input" value="Orange"><span class="ant-checkbox-inner"></span></span><span>Orange</span></label></div> <br>
<div class="ant-checkbox-group"><label class="ant-checkbox-wrapper ant-checkbox-wrapper-checked ant-checkbox-wrapper-disabled ant-checkbox-group-item"><span class="ant-checkbox ant-checkbox-checked ant-checkbox-disabled"><input type="checkbox" disabled="disabled" class="ant-checkbox-input" value="Apple"><span class="ant-checkbox-inner"></span></span><span><span style="color: red;">Apple</span></span></label><label class="ant-checkbox-wrapper ant-checkbox-wrapper-disabled ant-checkbox-group-item"><span class="ant-checkbox ant-checkbox-disabled"><input type="checkbox" disabled="disabled" class="ant-checkbox-input" value="Pear"><span class="ant-checkbox-inner"></span></span><span>Pear</span></label><label class="ant-checkbox-wrapper ant-checkbox-wrapper-disabled ant-checkbox-group-item"><span class="ant-checkbox ant-checkbox-disabled"><input type="checkbox" disabled="disabled" class="ant-checkbox-input" value="Orange"><span class="ant-checkbox-inner"></span></span><span>Orange</span></label></div> <div class="ant-checkbox-group"><label class="ant-checkbox-wrapper ant-checkbox-wrapper-checked ant-checkbox-wrapper-disabled ant-checkbox-group-item"><span class="ant-checkbox ant-checkbox-checked ant-checkbox-disabled"><input type="checkbox" disabled="disabled" class="ant-checkbox-input" value="Apple"><span class="ant-checkbox-inner"></span></span><span><span style="color: red;">Apple</span></span></label><label class="ant-checkbox-wrapper ant-checkbox-wrapper-disabled ant-checkbox-group-item"><span class="ant-checkbox ant-checkbox-disabled"><input type="checkbox" disabled="disabled" class="ant-checkbox-input" value="Pear"><span class="ant-checkbox-inner"></span></span><span>Pear</span></label><label class="ant-checkbox-wrapper ant-checkbox-wrapper-disabled ant-checkbox-group-item"><span class="ant-checkbox ant-checkbox-disabled"><input type="checkbox" disabled="disabled" class="ant-checkbox-input" value="Orange"><span class="ant-checkbox-inner"></span></span><span>Orange</span></label></div>

View File

@ -1,9 +1,12 @@
import { mount } from '@vue/test-utils'; import { mount } from '@vue/test-utils';
import Checkbox from '..'; import Checkbox from '..';
import focusTest from '../../../tests/shared/focusTest'; import focusTest from '../../../tests/shared/focusTest';
import { resetWarned } from '../../_util/warning';
import mountTest from '../../../tests/shared/mountTest';
describe('Checkbox', () => { describe('Checkbox', () => {
focusTest(Checkbox); focusTest(Checkbox);
mountTest(Checkbox);
it('responses hover events', () => { it('responses hover events', () => {
const onMouseEnter = jest.fn(); const onMouseEnter = jest.fn();
const onMouseLeave = jest.fn(); const onMouseLeave = jest.fn();
@ -21,4 +24,18 @@ describe('Checkbox', () => {
wrapper.trigger('mouseleave'); wrapper.trigger('mouseleave');
expect(onMouseLeave).toHaveBeenCalled(); expect(onMouseLeave).toHaveBeenCalled();
}); });
it('warning if set `value`', () => {
resetWarned();
const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
mount(Checkbox, {
propsData: {
value: 'xxx',
},
});
expect(errorSpy).toHaveBeenCalledWith(
'Warning: [antdv: Checkbox] `value` is not validate prop, do you mean `checked`?',
);
errorSpy.mockRestore();
});
}); });

View File

@ -1,8 +1,10 @@
import { mount } from '@vue/test-utils'; import { mount } from '@vue/test-utils';
import { asyncExpect } from '@/tests/utils'; import { asyncExpect } from '@/tests/utils';
import Checkbox from '../index'; import Checkbox from '../index';
import mountTest from '../../../tests/shared/mountTest';
describe('CheckboxGroup', () => { describe('CheckboxGroup', () => {
mountTest(Checkbox.Group);
it('should work basically', () => { it('should work basically', () => {
const onChange = jest.fn(); const onChange = jest.fn();
const wrapper = mount( const wrapper = mount(
@ -19,22 +21,22 @@ describe('CheckboxGroup', () => {
.findAll('.ant-checkbox-input') .findAll('.ant-checkbox-input')
.at(0) .at(0)
.trigger('change'); .trigger('change');
expect(onChange).toBeCalledWith(['Apple']); expect(onChange).toHaveBeenCalledWith(['Apple']);
wrapper wrapper
.findAll('.ant-checkbox-input') .findAll('.ant-checkbox-input')
.at(1) .at(1)
.trigger('change'); .trigger('change');
expect(onChange).toBeCalledWith(['Apple', 'Pear']); expect(onChange).toHaveBeenCalledWith(['Apple', 'Pear']);
wrapper wrapper
.findAll('.ant-checkbox-input') .findAll('.ant-checkbox-input')
.at(2) .at(2)
.trigger('change'); .trigger('change');
expect(onChange).toBeCalledWith(['Apple', 'Pear', 'Orange']); expect(onChange).toHaveBeenCalledWith(['Apple', 'Pear', 'Orange']);
wrapper wrapper
.findAll('.ant-checkbox-input') .findAll('.ant-checkbox-input')
.at(1) .at(1)
.trigger('change'); .trigger('change');
expect(onChange).toBeCalledWith(['Apple', 'Orange']); expect(onChange).toHaveBeenCalledWith(['Apple', 'Orange']);
}); });
it('does not trigger onChange callback of both Checkbox and CheckboxGroup when CheckboxGroup is disabled', () => { it('does not trigger onChange callback of both Checkbox and CheckboxGroup when CheckboxGroup is disabled', () => {
@ -89,12 +91,12 @@ describe('CheckboxGroup', () => {
.findAll('.ant-checkbox-input') .findAll('.ant-checkbox-input')
.at(0) .at(0)
.trigger('change'); .trigger('change');
expect(onChangeGroup).toBeCalledWith(['Apple']); expect(onChangeGroup).toHaveBeenCalledWith(['Apple']);
groupWrapper groupWrapper
.findAll('.ant-checkbox-input') .findAll('.ant-checkbox-input')
.at(1) .at(1)
.trigger('change'); .trigger('change');
expect(onChangeGroup).toBeCalledWith(['Apple']); expect(onChangeGroup).toHaveBeenCalledWith(['Apple']);
}); });
it('passes prefixCls down to checkbox', () => { it('passes prefixCls down to checkbox', () => {

View File

@ -11,7 +11,7 @@ Generate a group of checkboxes from an array
```tpl ```tpl
<template> <template>
<div> <div>
<a-checkbox-group :options="plainOptions" v-model="value" @change="onChange" /> <a-checkbox-group name="checkboxgroup" :options="plainOptions" v-model="value" @change="onChange" />
<br /> <br />
<a-checkbox-group :options="plainOptions" :defaultValue="['Apple']" @change="onChange" /> <a-checkbox-group :options="plainOptions" :defaultValue="['Apple']" @change="onChange" />
<br /> <br />

View File

@ -4,40 +4,41 @@
#### Checkbox #### Checkbox
| Property | Description | Type | Default | | Property | Description | Type | Default | Version |
| --- | --- | --- | --- | | --- | --- | --- | --- | --- |
| autoFocus | get focus when component mounted | boolean | false | | autoFocus | get focus when component mounted | boolean | false | |
| checked | Specifies whether the checkbox is selected. | boolean | false | | checked | Specifies whether the checkbox is selected. | boolean | false | |
| defaultChecked | Specifies the initial state: whether or not the checkbox is selected. | boolean | false | | defaultChecked | Specifies the initial state: whether or not the checkbox is selected. | boolean | false | |
| disabled | Disable checkbox | boolean | false | | disabled | Disable checkbox | boolean | false | |
| indeterminate | indeterminate checked state of checkbox | boolean | false | | indeterminate | indeterminate checked state of checkbox | boolean | false | |
#### events #### events
| Events Name | Description | Arguments | | Events Name | Description | Arguments | Version |
| --- | --- | --- | | --- | --- | --- | --- |
| change | The callback function that is triggered when the state changes. | Function(e:Event) | | change | The callback function that is triggered when the state changes. | Function(e:Event) | |
#### Checkbox Group #### Checkbox Group
| Property | Description | Type | Default | | Property | Description | Type | Default | Version |
| --- | --- | --- | --- | | --- | --- | --- | --- | --- |
| defaultValue | Default selected value | string\[] | \[] | | defaultValue | Default selected value | string\[] | \[] | |
| disabled | Disable all checkboxes | boolean | false | | disabled | Disable all checkboxes | boolean | false | |
| options | Specifies options, you can customize `label` with slot = "label" slot-scope="option" | string\[] \| Array&lt;{ label: string value: string disabled?: boolean, onChange?: function }> | \[] | | name | The `name` property of all `input[type="checkbox"]` children | string | - | 1.5.0 |
| value | Used for setting the currently selected value. | string\[] | \[] | | options | Specifies options, you can customize `label` with slot = "label" slot-scope="option" | string\[] \| Array&lt;{ label: string value: string disabled?: boolean, onChange?: function }> | \[] | |
| value | Used for setting the currently selected value. | string\[] | \[] | |
#### events #### events
| Events Name | Description | Arguments | | Events Name | Description | Arguments | Version |
| --- | --- | --- | | --- | --- | --- | --- |
| change | The callback function that is triggered when the state changes. | Function(checkedValue) | | change | The callback function that is triggered when the state changes. | Function(checkedValue) | |
### Methods ### Methods
#### Checkbox #### Checkbox
| Name | Description | | Name | Description | Version |
| ------- | ------------ | | ------- | ------------ | ------- |
| blur() | remove focus | | blur() | remove focus | |
| focus() | get focus | | focus() | get focus | |

View File

@ -4,40 +4,41 @@
#### Checkbox #### Checkbox
| 参数 | 说明 | 类型 | 默认值 | | 参数 | 说明 | 类型 | 默认值 | 版本 |
| -------------- | --------------------------------------- | ------- | ------ | | -------------- | --------------------------------------- | ------- | ------ | ---- |
| autoFocus | 自动获取焦点 | boolean | false | | autoFocus | 自动获取焦点 | boolean | false | |
| checked | 指定当前是否选中 | boolean | false | | checked | 指定当前是否选中 | boolean | false | |
| defaultChecked | 初始是否选中 | boolean | false | | defaultChecked | 初始是否选中 | boolean | false | |
| disabled | 失效状态 | boolean | false | | disabled | 失效状态 | boolean | false | |
| indeterminate | 设置 indeterminate 状态,只负责样式控制 | boolean | false | | indeterminate | 设置 indeterminate 状态,只负责样式控制 | boolean | false | |
#### 事件 #### 事件
| 事件名称 | 说明 | 回调参数 | | 事件名称 | 说明 | 回调参数 | 版本 |
| -------- | -------------- | ----------------- | | -------- | -------------- | ----------------- | ---- |
| change | 变化时回调函数 | Function(e:Event) | - | | change | 变化时回调函数 | Function(e:Event) | - | |
#### Checkbox Group #### Checkbox Group
| 参数 | 说明 | 类型 | 默认值 | | 参数 | 说明 | 类型 | 默认值 | 版本 |
| --- | --- | --- | --- | | --- | --- | --- | --- | --- |
| defaultValue | 默认选中的选项 | string\[] | \[] | | defaultValue | 默认选中的选项 | string\[] | \[] | |
| disabled | 整组失效 | boolean | false | | disabled | 整组失效 | boolean | false | |
| options | 指定可选项,可以通过 slot="label" slot-scope="option" 定制`label` | string\[] \| Array&lt;{ label: string value: string disabled?: boolean, onChange?: function }> | \[] | | name | CheckboxGroup 下所有 `input[type="checkbox"]``name` 属性 | string | - | 1.5.0 |
| value | 指定选中的选项 | string\[] | \[] | | options | 指定可选项,可以通过 slot="label" slot-scope="option" 定制`label` | string\[] \| Array&lt;{ label: string value: string disabled?: boolean, onChange?: function }> | \[] | |
| value | 指定选中的选项 | string\[] | \[] | |
#### 事件 #### 事件
| 事件名称 | 说明 | 回调参数 | | 事件名称 | 说明 | 回调参数 | 版本 |
| -------- | -------------- | ---------------------- | | -------- | -------------- | ---------------------- | ---- |
| change | 变化时回调函数 | Function(checkedValue) | - | | change | 变化时回调函数 | Function(checkedValue) | - | |
### 方法 ### 方法
#### Checkbox #### Checkbox
| 名称 | 描述 | | 名称 | 描述 | 版本 |
| ------- | -------- | | ------- | -------- | ---- |
| blur() | 移除焦点 | | blur() | 移除焦点 | |
| focus() | 获取焦点 | | focus() | 获取焦点 | |

View File

@ -193,7 +193,7 @@ const Descriptions = {
}); });
}); });
}, },
beforeDestory() { beforeDestroy() {
ResponsiveObserve.unsubscribe(this.token); ResponsiveObserve.unsubscribe(this.token);
}, },
render() { render() {

View File

@ -31,4 +31,5 @@ export declare class CheckboxGroup extends AntdComponent {
* @type string[] * @type string[]
*/ */
value: string[]; value: string[];
name?: string;
} }