Skip to content

Commit

Permalink
feat(checkbox): support options and slots
Browse files Browse the repository at this point in the history
  • Loading branch information
chaishi committed Jul 16, 2023
1 parent 8470748 commit 65254ff
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 10 deletions.
20 changes: 18 additions & 2 deletions src/checkbox/_example/group.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
</t-space>

<!-- key 是避免重复渲染的关键;Checkbox.key is the key point of list render -->
<!-- 数据量大的情况下,不建议使用这种方式:因父组件 CheckboxGroup 选中项变化,子组件 Checkbox 一定重新渲染。 -->
<t-space direction="vertical">
<div>方式二:组件内置全选功能,使用插槽定义选项。选中值: {{ value2.join(', ') }}</div>
<t-checkbox-group v-model="value2" @change="onChange2">
Expand All @@ -19,14 +20,21 @@
</t-checkbox-group>
</t-space>

<!-- 数据量大的情况下,建议使用这种方式,可以避免选中项重复渲染 -->
<t-space direction="vertical">
<div>方式三:组件内置全选功能,使用 `options` 定义选项。选中值: {{ value3.join(', ') }}</div>
<t-checkbox-group v-model="value3" :options="options2" @change="onChange3" />
</t-space>

<!-- 数据量大的情况下,建议使用这种方式,可以避免选中项重复渲染 -->
<t-space direction="vertical">
<div>方式四:组件内置全选功能,非受控用法</div>
<t-checkbox-group :defaultValue="['选项一']" :options="options2" />
<div>方式四:组件内置全选功能,`options` 定义选项列表,插槽定义选项内容</div>
<t-checkbox-group :defaultValue="['选项一']" :options="options3">
<template #label="{ option: { label, value, checkAll }, index }">
<span v-if="checkAll">{{ label }}</span>
<span v-else> {{ label }}({{ value }}/{{ index }}) </span>
</template>
</t-checkbox-group>
</t-space>
</t-space>
</template>
Expand All @@ -40,6 +48,13 @@ const OPTION_LIST = [
{ value: '选项三', label: '选项三' },
];
const OPTION_LIST3 = [
{ label: '全选', checkAll: true },
{ value: 'optionA', label: '选项一' },
{ value: 'optionB', label: '选项二' },
{ value: 'optionC', label: '选项三' },
];
export default {
data() {
return {
Expand All @@ -54,6 +69,7 @@ export default {
value2: ['选项一'],
value3: ['选项一', '选项二', '选项三'],
options2: [...OPTION_LIST],
options3: OPTION_LIST3,
};
},
computed: {
Expand Down
15 changes: 13 additions & 2 deletions src/checkbox/checkbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {
} from '@vue/composition-api';
import props from './props';
import useVModel from '../hooks/useVModel';
import { renderContent, useFormDisabled } from '../hooks';
import { renderContent, renderTNodeJSX, useFormDisabled } from '../hooks';

Check warning on line 6 in src/checkbox/checkbox.tsx

View workflow job for this annotation

GitHub Actions / call-test-build / test

'renderContent' is defined but never used
import { useCommonClassName, usePrefixClass } from '../hooks/useConfig';
import { CheckboxGroupInjectionKey } from './constants';
import { getCheckboxStore, ObserverListenerParams } from './store';
Expand All @@ -16,6 +16,7 @@ export default defineComponent({
...props,
stopLabelTrigger: Boolean,
storeKey: String,
index: Number,
},

model: {
Expand All @@ -27,6 +28,7 @@ export default defineComponent({
const checkboxStore = getCheckboxStore(props.storeKey);
const labelRef = ref<HTMLElement>();
const { STATUS } = useCommonClassName();
const checkboxGroupExist = ref(false);

const {
checked, indeterminate, disabled, value, lazyLoad,
Expand Down Expand Up @@ -56,6 +58,7 @@ export default defineComponent({
} else {
tChecked.value = parentChecked.includes(value);
}
checkboxGroupExist.value = checkboxStore.parentExist;
};

watch(
Expand All @@ -64,6 +67,8 @@ export default defineComponent({
// CheckboxGroup does not exist, self checked works
if (!checkboxStore.parentExist) {
tChecked.value = innerChecked.value;
} else {
checkboxGroupExist.value = true;
}
},
{ immediate: true },
Expand Down Expand Up @@ -181,6 +186,7 @@ export default defineComponent({
showCheckbox,
formDisabled,
STATUS,
checkboxGroupExist,
handleChange,
handleLabelClick,
onCheckboxFocus,
Expand All @@ -193,6 +199,10 @@ export default defineComponent({
const classes = this.labelClasses.concat({
[this.STATUS.disabled]: disabled,
});
const slotsPrams = {
option: this.$options.propsData,
index: this.index,
};
return (
<label
ref="labelRef"
Expand All @@ -219,7 +229,8 @@ export default defineComponent({
></input>,
<span class={`${this.COMPONENT_NAME}__input`} key="input-span"></span>,
<span class={`${this.COMPONENT_NAME}__label`} key="label" onClick={this.handleLabelClick}>
{renderContent(this, 'default', 'label')}
{renderTNodeJSX(this, 'default', { params: slotsPrams })
|| renderTNodeJSX(this, 'label', { params: slotsPrams, slotFirst: this.checkboxGroupExist })}
</span>,
]}
</label>
Expand Down
8 changes: 4 additions & 4 deletions src/checkbox/group.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,7 @@ import Checkbox from './checkbox';
import props from './checkbox-group-props';
import { CheckboxOptionObj, TdCheckboxProps, CheckboxGroupValue } from './type';
import { CheckboxGroupInjectionKey } from './constants';
import {
usePrefixClass, useVModel, useChildComponentSlots, renderTNodeJSX,
} from '../hooks';
import { usePrefixClass, useVModel, useChildComponentSlots } from '../hooks';
import { getCheckboxStore } from './store';

export default defineComponent({
Expand Down Expand Up @@ -195,12 +193,14 @@ export default defineComponent({
<Checkbox
key={option.value ?? index}
props={option}
index={index}
checked={this.innerValue.includes(option.value)}
storeKey={this.storeKey}
scopedSlots={this.$scopedSlots}
></Checkbox>
));
} else {
const nodes = renderTNodeJSX(this, 'default');
const nodes = this.$scopedSlots.default?.(null);
this.optionList = this.getOptionListBySlots();
nodes.forEach((vNode: VNode) => {
// eslint-disable-next-line
Expand Down
5 changes: 3 additions & 2 deletions src/utils/render-tnode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import {
PropType, CreateElement, VNode, VNodeChildren, RenderContext,
} from 'vue/types/umd';
import { ScopedSlotReturnValue } from 'vue/types/vnode';
// import isObject from 'lodash/isObject';
import camelCase from 'lodash/camelCase';
import kebabCase from 'lodash/kebabCase';
import { TNode } from '../common';
Expand Down Expand Up @@ -91,6 +90,7 @@ interface JSXRenderContext {
params?: Record<string, any>;
// 是否不打印 LOG
silent?: boolean;
slotFirst?: boolean;
}

/**
Expand All @@ -110,6 +110,7 @@ export const renderTNodeJSX = (vm: VmType, name: string, options?: ScopedSlotRet
// console.warn(`Both $scopedSlots.${name} and $props.${name} exist, $props.${name} is preferred`);
// }
const params = typeof options === 'object' && 'params' in options ? options.params : null;
const slotFirst = typeof options === 'object' && 'slotFirst' in options ? options.slotFirst : false;
const defaultNode = typeof options === 'object' && 'defaultNode' in options ? options.defaultNode : options;
const propsNode = vm[name];
if (propsNode === false) return;
Expand All @@ -121,7 +122,7 @@ export const renderTNodeJSX = (vm: VmType, name: string, options?: ScopedSlotRet
}
const isPropsEmpty = [undefined, params, ''].includes(propsNode);
// Props 为空,但插槽存在
if (isPropsEmpty && (vm.$scopedSlots[camelCase(name)] || vm.$scopedSlots[kebabCase(name)])) {
if ((isPropsEmpty || slotFirst) && (vm.$scopedSlots[camelCase(name)] || vm.$scopedSlots[kebabCase(name)])) {
return handleSlots(vm, params, name);
}
return propsNode;
Expand Down

0 comments on commit 65254ff

Please sign in to comment.