diff --git a/packages/vant/src/checkbox/Checkbox.tsx b/packages/vant/src/checkbox/Checkbox.tsx index c6f672e34..d5da36af6 100644 --- a/packages/vant/src/checkbox/Checkbox.tsx +++ b/packages/vant/src/checkbox/Checkbox.tsx @@ -25,6 +25,10 @@ const [name, bem] = createNamespace('checkbox'); export const checkboxProps = extend({}, checkerProps, { shape: String as PropType, bindGroup: truthProp, + indeterminate: { + type: Boolean as PropType, + default: null, + }, }); export type CheckboxProps = ExtractPropTypes; @@ -80,11 +84,15 @@ export default defineComponent({ } else { emit('update:modelValue', newValue); } + + if (props.indeterminate !== null) emit('change', newValue); }; watch( () => props.modelValue, - (value) => emit('change', value), + (value) => { + if (props.indeterminate === null) emit('change', value); + }, ); useExpose({ toggle, props, checked }); diff --git a/packages/vant/src/checkbox/Checker.tsx b/packages/vant/src/checkbox/Checker.tsx index 17bede19d..6c0e6d69f 100644 --- a/packages/vant/src/checkbox/Checker.tsx +++ b/packages/vant/src/checkbox/Checker.tsx @@ -45,6 +45,10 @@ export default defineComponent({ parent: Object as PropType, checked: Boolean, bindGroup: truthProp, + indeterminate: { + type: Boolean as PropType, + default: null, + }, }), emits: ['click', 'toggle'], @@ -106,7 +110,7 @@ export default defineComponent({ }; const renderIcon = () => { - const { bem, checked } = props; + const { bem, checked, indeterminate } = props; const iconSize = props.iconSize || getParentProp('iconSize'); return ( @@ -114,7 +118,7 @@ export default defineComponent({ ref={iconRef} class={bem('icon', [ shape.value, - { disabled: disabled.value, checked }, + { disabled: disabled.value, checked, indeterminate }, ])} style={ shape.value !== 'dot' @@ -129,7 +133,10 @@ export default defineComponent({ {slots.icon ? ( slots.icon({ checked, disabled: disabled.value }) ) : shape.value !== 'dot' ? ( - + ) : (
+ Check All + + + + + Checkbox {{ item }} + + +``` + +```js +import { ref } from 'vue'; + +export default { + setup() { + const list = ['a', 'b', 'c', 'd'] + + const isCheckAll = ref(false); + const checkedResult = ref(['a', 'b', 'd']); + const isIndeterminate = ref(true); + + const checkAllChange = (val: boolean) => { + checkedResult.value = val ? list : [] + isIndeterminate.value = false + } + + const checkedResultChange = (value: string[]) => { + const checkedCount = value.length + isCheckAll.value = checkedCount === list.length + isIndeterminate.value = checkedCount > 0 && checkedCount < list.length + } + + return { + list, + isCheckAll, + checkedResult, + checkAllChange, + isIndeterminate, + checkedResultChange + }; + }, +}; +``` + ## API ### Checkbox Props @@ -280,6 +332,7 @@ export default { | icon-size | Icon size | _number \| string_ | `20px` | | checked-color | Checked color | _string_ | `#1989fa` | | bind-group | Whether to bind with CheckboxGroup | _boolean_ | `true` | +| indeterminate | Whether indeterminate status | _boolean_ | `false` | ### CheckboxGroup Props diff --git a/packages/vant/src/checkbox/README.zh-CN.md b/packages/vant/src/checkbox/README.zh-CN.md index f33b53c5d..947f03385 100644 --- a/packages/vant/src/checkbox/README.zh-CN.md +++ b/packages/vant/src/checkbox/README.zh-CN.md @@ -282,6 +282,60 @@ export default { }; ``` +### 不确定状态 + +通过 `indeterminate` 设置复选框是否为不确定状态。 + +```html + + 全选 + + + + + 复选框 {{ item }} + + +``` + +```js +import { ref } from 'vue'; + +export default { + setup() { + const list = ['a', 'b', 'c', 'd'] + + const isCheckAll = ref(false); + const checkedResult = ref(['a', 'b', 'd']); + const isIndeterminate = ref(true); + + const checkAllChange = (val: boolean) => { + checkedResult.value = val ? list : [] + isIndeterminate.value = false + } + + const checkedResultChange = (value: string[]) => { + const checkedCount = value.length + isCheckAll.value = checkedCount === list.length + isIndeterminate.value = checkedCount > 0 && checkedCount < list.length + } + + return { + list, + isCheckAll, + checkedResult, + checkAllChange, + isIndeterminate, + checkedResultChange + }; + }, +}; +``` + ## API ### Checkbox Props @@ -297,6 +351,7 @@ export default { | icon-size | 图标大小,默认单位为 `px` | _number \| string_ | `20px` | | checked-color | 选中状态颜色 | _string_ | `#1989fa` | | bind-group | 是否与复选框组绑定 | _boolean_ | `true` | +| indeterminate | 是否为不确定状态 | _boolean_ | `false` | ### CheckboxGroup Props diff --git a/packages/vant/src/checkbox/demo/index.vue b/packages/vant/src/checkbox/demo/index.vue index d6a08f537..745f57d5e 100644 --- a/packages/vant/src/checkbox/demo/index.vue +++ b/packages/vant/src/checkbox/demo/index.vue @@ -26,6 +26,7 @@ const t = useTranslate({ inverse: '反选', horizontal: '水平排列', disableLabel: '禁用文本点击', + indeterminate: '不确定状态', }, 'en-US': { checkbox: 'Checkbox', @@ -42,6 +43,7 @@ const t = useTranslate({ inverse: 'Inverse', horizontal: 'Horizontal', disableLabel: 'Disable label click', + indeterminate: 'indeterminate', }, }); @@ -49,6 +51,8 @@ const state = reactive({ checkbox1: true, checkbox2: true, checkbox3: true, + isCheckAll: false, + isIndeterminate: true, checkboxLabel: true, checkboxIcon: true, leftLabel: false, @@ -57,10 +61,13 @@ const state = reactive({ checkboxShape: ['a', 'b'], result2: [], result3: [], + result4: ['a', 'b', 'd'], checkAllResult: [], horizontalResult: [], }); +const list = ['a', 'b', 'c', 'd']; + const activeIcon = cdnURL('user-active.png'); const inactiveIcon = cdnURL('user-inactive.png'); @@ -78,6 +85,17 @@ const checkAll = () => { const toggleAll = () => { group.value?.toggleAll(); }; + +const checkAllChange = (val: boolean) => { + state.result4 = val ? list : []; + state.isIndeterminate = false; +}; + +const checkedResultChange = (value: string[]) => { + const checkedCount = value.length; + state.isCheckAll = checkedCount === list.length; + state.isIndeterminate = checkedCount > 0 && checkedCount < list.length; +}; diff --git a/packages/vant/src/checkbox/index.less b/packages/vant/src/checkbox/index.less index f64a42e98..9ef71cd7d 100644 --- a/packages/vant/src/checkbox/index.less +++ b/packages/vant/src/checkbox/index.less @@ -56,6 +56,17 @@ } } + &--indeterminate { + .van-icon { + display: flex; + align-items: center; + justify-content: center; + color: var(--van-white); + border-color: var(--van-checkbox-checked-icon-color); + background-color: var(--van-checkbox-checked-icon-color); + } + } + &--checked { .van-icon { color: var(--van-white); diff --git a/packages/vant/src/checkbox/test/__snapshots__/demo-ssr.spec.ts.snap b/packages/vant/src/checkbox/test/__snapshots__/demo-ssr.spec.ts.snap index fc07e09d8..dfe53d717 100644 --- a/packages/vant/src/checkbox/test/__snapshots__/demo-ssr.spec.ts.snap +++ b/packages/vant/src/checkbox/test/__snapshots__/demo-ssr.spec.ts.snap @@ -611,4 +611,128 @@ exports[`should render demo and match snapshot 1`] = `
+
+ + +
+
+
+ + + + + + +
+
`; diff --git a/packages/vant/src/checkbox/test/__snapshots__/demo.spec.ts.snap b/packages/vant/src/checkbox/test/__snapshots__/demo.spec.ts.snap index c82b16ea5..2a202ba6a 100644 --- a/packages/vant/src/checkbox/test/__snapshots__/demo.spec.ts.snap +++ b/packages/vant/src/checkbox/test/__snapshots__/demo.spec.ts.snap @@ -390,4 +390,80 @@ exports[`should render demo and match snapshot 1`] = ` +
+ +
+
+
+ + + + +
+
`;