feature: commit checkbox-group component

This commit is contained in:
wang-xh 2022-10-09 18:16:17 +08:00
parent ac8d638d0c
commit aa9c8e4e65
11 changed files with 389 additions and 6 deletions

View File

@ -1,7 +1,7 @@
{
"editor.defaultFormatter": "esbenp.prettier-vscode",
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
"editor.defaultFormatter": "vscode.typescript-language-features"
},
"[typescriptreact]": {
"editor.defaultFormatter": "vscode.typescript-language-features"

View File

@ -0,0 +1,12 @@
import type { App } from 'vue';
import CheckBoxGroup from './src/checkbox-group.component';
export * from './src/checkbox-group.props';
export { CheckBoxGroup };
export default {
install(app: App): void {
app.component(CheckBoxGroup.name, CheckBoxGroup);
}
};

View File

@ -0,0 +1,56 @@
import { defineComponent, computed, ref } from 'vue';
import type { SetupContext } from 'vue';
import { CheckboxGroupProps, checkboxGroupProps } from './checkbox-group.props';
import { useCheckboxGroup } from './composition/use-checkbox-group';
export default defineComponent({
name: 'FCheckboxGroup',
props: checkboxGroupProps,
emits: [
'changeValue',
'update:modelValue',
],
setup(props: CheckboxGroupProps, context: SetupContext) {
const modelValue = ref(props.modelValue);
const { enumData, onClickCheckbox, getValue, getText, checked, loadData } = useCheckboxGroup(props, context, modelValue);
// 异步数据
loadData();
const horizontalClass = computed(() => ({
'farris-checkradio-hor': props.horizontal
}));
return () => {
return (
<div class={['farris-input-wrap', horizontalClass.value]}>
{
enumData.value.map((item, index) => {
const id = 'checkbox_' + props.name + index;
return (
<div class="custom-control custom-checkbox" >
<input
type="checkbox"
class="custom-control-input"
name={props.name}
id={id}
value={getValue(item)}
checked={checked(item)}
disabled={props.disable}
tabindex={props.tabIndex}
onClick={(event: MouseEvent) => onClickCheckbox(item, event)}
/>
<label class="custom-control-label" for={id} title={getText(item)}>
{getText(item)}
</label>
</div>
);
})
}
</div>
);
};
},
});

View File

@ -0,0 +1,61 @@
import { ExtractPropTypes } from 'vue';
import { Checkbox } from './composition/types';
export const checkboxGroupProps = {
/**
*
*/
id: String,
/**
*
*/
name: { type: String, default: '' },
/**
*
*/
enumData: Array<Checkbox>,
/**
* key值
*/
textField: { type: String, default: 'name' },
/**
* key值
*/
valueField: { type: String, default: 'value' },
/**
*
*/
horizontal: { type: Boolean, default: false },
/**
*
*/
disable: { type: Boolean, default: false },
/**
*
*/
modelValue: [String, Array<string>],
/**
* Tab键索引
*/
tabIndex: { type: Number, default: 0 },
/**
*
*/
separator: { type: String, default: ',' },
/**
*
*/
isStringValue: { type: Boolean, default: true },
/**
*
*/
// loadData: () => Observable < { data: Array<Checkbox> } >
loadData: { type: Function }
};
export type CheckboxGroupProps = ExtractPropTypes<typeof checkboxGroupProps>;

View File

@ -0,0 +1,37 @@
import { ComputedRef, Ref } from 'vue';
export interface Checkbox {
/**
*
*/
value: ComputedRef<any>;
/**
*
*/
name: ComputedRef<any>;
}
export interface ChangeCheckbox {
enumData: ComputedRef<Array<Checkbox>>;
/**
*
*/
getValue(item: Checkbox): any;
/**
*
*/
getText(item: Checkbox): any;
/**
*
*/
checked(item: Checkbox): boolean;
/**
*
*/
onClickCheckbox: (item: Checkbox, $event: Event) => void;
}

View File

@ -0,0 +1,107 @@
import { ChangeCheckbox, Checkbox } from './types';
import { computed, Ref, SetupContext, ref } from 'vue';
import { CheckboxGroupProps } from '../checkbox-group.props';
export function useCheckboxGroup(props: CheckboxGroupProps, context: SetupContext, modelValue: Ref<string>): ChangeCheckbox {
const canChangeRadioButton = computed(() => !props.disable);
const enumData = ref(props.enumData || []);
function getValue(item: Checkbox): any {
return item[props.valueField];
};
function getText(item: Checkbox): any {
return item[props.textField];
};
/**
*
*/
function transformToArr(value: any): string[] {
if (!value) {
return [];
}
if (!props.isStringValue) {
return value;
}
return value.split(props.separator);
}
/**
*
*/
function transformToStr(value: Array<string>) {
const allVals = enumData.value.map(n => getValue(n));
const r = [];
allVals.forEach(n => {
if (value.some(item => item === n)) {
r.push(n);
}
});
if (!props.isStringValue) {
return r;
}
return r.join(props.separator);
}
/**
*
*/
function checked(item: Checkbox) {
const val = String(getValue(item));
const checkedValue = transformToArr(modelValue.value);
// 多值
return checkedValue.some(item => item === val);
}
/**
*
*/
function onClickCheckbox(item: Checkbox, $event: Event) {
if (canChangeRadioButton.value) {
let arrValue = transformToArr(modelValue.value) || [];
const val = String(getValue(item));
if (!arrValue || !arrValue.length) {
arrValue.push(val);
} else if (arrValue.some(item => item === val)) {
arrValue = arrValue.filter(n => n !== val);
} else {
arrValue.push(val);
}
// 更新value值
modelValue.value = transformToStr(arrValue);
context.emit('changeValue', modelValue.value);
// 不可少,用于更新组件绑定值
context.emit('update:modelValue', modelValue.value);
}
$event.stopPropagation();
}
function loadData() {
if (props.loadData) {
props.loadData().subscribe(res => {
enumData.value = res.data || [];
});
}
}
return {
enumData,
getValue,
getText,
checked,
onClickCheckbox,
loadData
};
}

View File

@ -15,10 +15,10 @@ export function changeRadio(props: RadioGroupProps, context: SetupContext, model
return item[props.textField];
};
function onClickRadio(item, $event: Event) {
function onClickRadio(item: Radio, $event: Event) {
if (canChangeRadioButton.value) {
const newValue = getValue(item);
if (modelValue.value !== item) {
if (modelValue.value !== newValue) {
modelValue.value = newValue;
context.emit('changeValue', newValue);

View File

@ -1,5 +1,6 @@
import { ExtractPropTypes, PropType } from 'vue';
import { Radio } from './composition/types';
import { Observable, Subscription } from 'rxjs';
export const radioGroupProps = {
/**

View File

@ -13,6 +13,7 @@ import Section from "./components/section.vue";
import Notify from "./components/notify.vue";
import Accordion from "./components/accordion.vue";
import ComboList from "./components/combo-list.vue";
import CheckboxGroup from "./components/checkbox.vue";
const canEdit = ref(true);
const disable = ref(false);
@ -40,12 +41,13 @@ const canAutoComplete = ref(false);
<label for="checkbox">disable:{{ disable }}</label>
<FButton :disable="disable"></FButton>
<Switch></Switch>
<RadioGroup></RadioGroup>
<Section></Section>
<Notify></Notify>
<Accordion></Accordion>
<Tabs />
<ComboList />
<RadioGroup></RadioGroup>
<CheckboxGroup />
</template>
<style scoped>

View File

@ -0,0 +1,108 @@
<script setup lang="ts">
import { ref } from "vue";
import { of, delay } from "rxjs";
import CheckboxGroup from "../../components/checkbox/src/checkbox-group.component";
const checkboxDisabled = ref(false);
const checkEnumData = ref([
{ value: "aa", name: "标签一" },
{ value: "bb", name: "标签二" },
{ value: "cc", name: "标签三" },
]);
const checkHorizontal = ref(true);
const valueString = ref("aa");
const valueArray = ref(["bb"]);
const valueDynamic = ref("value1,value2");
function loadCheckboxEnumData() {
return of({
data: [
{ value: "value1", name: "标签一" },
{ value: "value2", name: "标签二" },
{ value: "value3", name: "标签三" },
{ value: "value4", name: "标签四" },
],
}).pipe(delay(1000));
}
</script>
<template>
<p></p>
<label for="checkbox_disabled" class="mr-1">是否禁用复选组</label>
<input type="checkbox" id="checkbox_disabled" v-model="checkboxDisabled" />
<label for="check_horizontaol" class="mr-1 ml-3">是否水平排列</label>
<input type="checkbox" id="check_horizontaol" v-model="checkHorizontal" />
<br />
<div class="f-form-layout farris-form farris-form-controls-inline farris-form-auto">
<div class="col-9">
<div class="farris-group-wrap">
<div class="form-group farris-form-group form-group--has-tips">
<label class="col-form-label">
<span class="farris-label-text">绑定值为字符串</span>
</label>
<div class="farris-input-wrap">
<CheckboxGroup
:disable="checkboxDisabled"
:enum-data="checkEnumData"
:horizontal="checkHorizontal"
v-model="valueString"
name="check_string"
separator=";"
>
</CheckboxGroup>
当前选中值: {{ valueString }}
</div>
</div>
</div>
</div>
<div class="col-9">
<div class="farris-group-wrap">
<div class="form-group farris-form-group form-group--has-tips">
<label class="col-form-label">
<span class="farris-label-text">绑定值为数组</span>
</label>
<div class="farris-input-wrap">
<CheckboxGroup
:disable="checkboxDisabled"
:enum-data="checkEnumData"
:horizontal="checkHorizontal"
:is-string-value="false"
name="check_array"
v-model="valueArray"
>
</CheckboxGroup>
当前选中值: {{ valueArray }}
</div>
</div>
</div>
</div>
<div class="col-9">
<div class="farris-group-wrap">
<div class="form-group farris-form-group form-group--has-tips">
<label class="col-form-label">
<span class="farris-label-text">异步加载枚举数据</span>
</label>
<div class="farris-input-wrap">
<CheckboxGroup
:disable="checkboxDisabled"
:horizontal="checkHorizontal"
name="check_dynamic"
v-model="valueDynamic"
:load-data="loadCheckboxEnumData"
>
</CheckboxGroup>
当前选中值: {{ valueDynamic }}
</div>
</div>
</div>
</div>
</div>
<br />
</template>

View File

@ -9,7 +9,7 @@ const radioEnumData = ref([
{ value: "bb", name: "标签二" },
{ value: "cc", name: "标签三" },
]);
const radioHorizontal = ref(false);
const radioHorizontal = ref(true);
const value = ref("aa");
@ -34,6 +34,5 @@ function testConsole(value) {
@change-value="testConsole"
>
</RadioGroup>
<br />
当前选中值: {{ value }}
</template>