feature: commit checkbox-group component
This commit is contained in:
parent
ac8d638d0c
commit
aa9c8e4e65
|
@ -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"
|
||||
|
|
|
@ -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];
|
||||
};
|
||||
|
||||
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);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { ExtractPropTypes, PropType } from 'vue';
|
||||
import { Radio } from './composition/types';
|
||||
import { Observable, Subscription } from 'rxjs';
|
||||
|
||||
export const radioGroupProps = {
|
||||
/**
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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: "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>
|
||||
|
|
Loading…
Reference in New Issue