feature: commit checkbox-group component
This commit is contained in:
parent
ac8d638d0c
commit
aa9c8e4e65
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||||
"[typescript]": {
|
"[typescript]": {
|
||||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
"editor.defaultFormatter": "vscode.typescript-language-features"
|
||||||
},
|
},
|
||||||
"[typescriptreact]": {
|
"[typescriptreact]": {
|
||||||
"editor.defaultFormatter": "vscode.typescript-language-features"
|
"editor.defaultFormatter": "vscode.typescript-language-features"
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
};
|
|
@ -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>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
|
@ -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>;
|
|
@ -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;
|
||||||
|
|
||||||
|
}
|
|
@ -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
|
||||||
|
};
|
||||||
|
}
|
|
@ -15,10 +15,10 @@ export function changeRadio(props: RadioGroupProps, context: SetupContext, model
|
||||||
return item[props.textField];
|
return item[props.textField];
|
||||||
};
|
};
|
||||||
|
|
||||||
function onClickRadio(item, $event: Event) {
|
function onClickRadio(item: Radio, $event: Event) {
|
||||||
if (canChangeRadioButton.value) {
|
if (canChangeRadioButton.value) {
|
||||||
const newValue = getValue(item);
|
const newValue = getValue(item);
|
||||||
if (modelValue.value !== item) {
|
if (modelValue.value !== newValue) {
|
||||||
modelValue.value = newValue;
|
modelValue.value = newValue;
|
||||||
|
|
||||||
context.emit('changeValue', newValue);
|
context.emit('changeValue', newValue);
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { ExtractPropTypes, PropType } from 'vue';
|
import { ExtractPropTypes, PropType } from 'vue';
|
||||||
import { Radio } from './composition/types';
|
import { Radio } from './composition/types';
|
||||||
|
import { Observable, Subscription } from 'rxjs';
|
||||||
|
|
||||||
export const radioGroupProps = {
|
export const radioGroupProps = {
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -13,6 +13,7 @@ import Section from "./components/section.vue";
|
||||||
import Notify from "./components/notify.vue";
|
import Notify from "./components/notify.vue";
|
||||||
import Accordion from "./components/accordion.vue";
|
import Accordion from "./components/accordion.vue";
|
||||||
import ComboList from "./components/combo-list.vue";
|
import ComboList from "./components/combo-list.vue";
|
||||||
|
import CheckboxGroup from "./components/checkbox.vue";
|
||||||
|
|
||||||
const canEdit = ref(true);
|
const canEdit = ref(true);
|
||||||
const disable = ref(false);
|
const disable = ref(false);
|
||||||
|
@ -40,12 +41,13 @@ const canAutoComplete = ref(false);
|
||||||
<label for="checkbox">disable:{{ disable }}</label>
|
<label for="checkbox">disable:{{ disable }}</label>
|
||||||
<FButton :disable="disable"></FButton>
|
<FButton :disable="disable"></FButton>
|
||||||
<Switch></Switch>
|
<Switch></Switch>
|
||||||
<RadioGroup></RadioGroup>
|
|
||||||
<Section></Section>
|
<Section></Section>
|
||||||
<Notify></Notify>
|
<Notify></Notify>
|
||||||
<Accordion></Accordion>
|
<Accordion></Accordion>
|
||||||
<Tabs />
|
<Tabs />
|
||||||
<ComboList />
|
<ComboList />
|
||||||
|
<RadioGroup></RadioGroup>
|
||||||
|
<CheckboxGroup />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|
|
@ -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>
|
|
@ -9,7 +9,7 @@ const radioEnumData = ref([
|
||||||
{ value: "bb", name: "标签二" },
|
{ value: "bb", name: "标签二" },
|
||||||
{ value: "cc", name: "标签三" },
|
{ value: "cc", name: "标签三" },
|
||||||
]);
|
]);
|
||||||
const radioHorizontal = ref(false);
|
const radioHorizontal = ref(true);
|
||||||
|
|
||||||
const value = ref("aa");
|
const value = ref("aa");
|
||||||
|
|
||||||
|
@ -34,6 +34,5 @@ function testConsole(value) {
|
||||||
@change-value="testConsole"
|
@change-value="testConsole"
|
||||||
>
|
>
|
||||||
</RadioGroup>
|
</RadioGroup>
|
||||||
<br />
|
|
||||||
当前选中值: {{ value }}
|
当前选中值: {{ value }}
|
||||||
</template>
|
</template>
|
||||||
|
|
Loading…
Reference in New Issue