Browse Source

perf(components): 优化下拉表格组件,支持搜索

shizhongming 2 years ago
parent
commit
74982207b6
  1. 172
      src/components/Form/src/smart-boot/components/SmartPulldownTable.tsx
  2. 27
      src/components/Form/src/smart-boot/components/style/SmartPullownTable.less

172
src/components/Form/src/smart-boot/components/SmartPulldownTable.tsx

@ -6,6 +6,7 @@ import { Icon } from '@/components/Icon';
import './style/SmartPullownTable.less';
import { useRuleFormItem } from '@/hooks/component/useFormItem';
import { Row, Col } from 'ant-design-vue';
/**
* 下拉表格
@ -28,14 +29,74 @@ export default defineComponent({
api: {
type: Function as PropType<() => Promise<any>>,
},
showSearch: propTypes.bool.def(true),
allowClear: propTypes.bool.def(true),
filterOption: {
type: Function as PropType<(searchValue: string, row: Recordable) => boolean>,
},
searchIgnoreCase: propTypes.bool.def(true),
// 弹窗高度
height: propTypes.number,
},
emits: ['select', 'change', 'update:value'],
emits: ['select', 'change', 'update:value', 'visible-change'],
setup(props, { emit, slots, attrs }) {
const { showField, dropdownWidth, value: valueRef } = toRefs(props);
const {
showField,
dropdownWidth,
value: valueRef,
showSearch: showSearchRef,
allowClear: allowClearRef,
height: heightRef,
} = toRefs(props);
const pulldownRef = ref<VxePulldownInstance>();
const dataLoadingRef = ref<boolean>(false);
const tableDataRef = ref<Recordable[]>([]);
const tableRef = ref();
const searchValueRef = ref<string>('');
const filterOptionFunction = props.filterOption
? props.filterOption
: (searchValue: string, row: Recordable) => {
if (!searchValue || searchValue.trim().length === 0) {
return true;
}
const searchValueTrim = searchValue.trim();
let showValue = '';
if (props.showFunction) {
showValue = props.showFunction(row);
} else {
showValue = row[props.showField];
}
if (
(props.searchIgnoreCase ? showValue.toUpperCase() : showValue).includes(searchValueTrim)
) {
return true;
}
const fieldValue: string = row[props.valueField].toString();
return (props.searchIgnoreCase ? fieldValue.toUpperCase() : fieldValue).includes(
searchValueTrim,
);
};
const computeTableData = computed(() => {
const tableData = unref(tableDataRef);
if (tableData.length === 0) {
return tableData;
}
const searchValue = unref(searchValueRef);
if (!searchValue) {
return tableData;
}
return tableData.filter((item) =>
filterOptionFunction(
props.searchIgnoreCase ? searchValue.toUpperCase() : searchValue,
item,
),
);
});
/**
* 下拉框是否显示
*/
const isVisibleRef = ref(false);
// 选中的行
const selectRowRef = ref<Recordable | null>(null);
const computedSelectRowValue = computed(() => {
@ -85,46 +146,67 @@ export default defineComponent({
* 下拉容器样式
*/
const computedDropdownContainerStyle = computed(() => {
return {
const style: Recordable = {
width: unref(dropdownWidth) + 'px',
};
const height = unref(heightRef);
if (height) {
style.height = `${height}px`;
}
return style;
});
watch([valueRef, tableDataRef], ([value, tableData]) => {
const tableInstance: VxeGridInstance = unref(tableRef)?.tableAction.getTableInstance();
let row: Recordable | null = null;
if (!value) {
tableInstance && tableInstance.clearCurrentRow();
selectRowRef.value = null;
return;
}
const selectRows = tableData.filter(
(item) => item[props.valueField].toString() === value.toString(),
);
if (selectRows.length === 0) {
tableInstance && tableInstance.clearCurrentRow();
} else {
row = selectRows[0];
tableInstance && tableInstance.setCurrentRow(selectRows[0]);
if (value) {
const selectRows = tableData.filter(
(item) => item[props.valueField].toString() === value.toString(),
);
if (selectRows.length > 0) {
row = selectRows[0];
}
}
selectRowRef.value = row;
setCurrentRow();
});
/**
* 显示弹窗
*/
const handleShow = async () => {
isVisibleRef.value = true;
unref(pulldownRef)?.showPanel();
if (props.alwaysLoad) {
await loadTableData();
}
emit('visible-change', true);
setCurrentRow();
};
/**
* 设置当前行
*/
const setCurrentRow = () => {
nextTick(() => {
const tableInstance: VxeGridInstance = unref(tableRef)?.tableAction.getTableInstance();
if (!tableInstance) {
return;
}
const row = unref(selectRowRef);
row && tableInstance && tableInstance.setCurrentRow(row);
if (!row) {
tableInstance.clearCurrentRow();
} else {
tableInstance.setCurrentRow(row);
}
});
};
const handleHide = () => {
isVisibleRef.value = false;
searchValueRef.value = '';
emit('visible-change', false);
};
const dropdownTableProps = {
size: 'mini',
...props.tableProps,
@ -135,6 +217,7 @@ export default defineComponent({
onCellClick: ({ row }) => {
changeValue(row);
unref(pulldownRef)?.hidePanel();
handleHide();
},
};
@ -143,20 +226,58 @@ export default defineComponent({
state.value = row?.[props.valueField];
};
const inputIconSlots = {
addonAfter: () => <Icon onClick={handleShow} icon="ant-design:table-outlined" />,
clearIcon: () => <Icon onClick={() => changeValue()} icon="ant-design:close-circle-filled" />,
/**
* 搜索框变化触发
* @param value
*/
const handleSearchChange = (value: string) => {
searchValueRef.value = value;
setCurrentRow();
};
// const inputIconSlots = {
// addonAfter: () => <Icon onClick={handleShow} icon="ant-design:table-outlined" />,
// clearIcon: () => <Icon onClick={() => changeValue()} icon="ant-design:close-circle-filled" />,
// };
//
// const selectSlots = {
// suffixIcon: () => <Icon onClick={handleShow} icon="ant-design:table-outlined" />,
// };
const handleUpdateValue = () => {
changeValue();
handleShow();
};
const pulldownSlots = {
default: () => (
<a-input onFocus={handleShow} value={unref(computedSelectRowValue)} {...attrs}>
{inputIconSlots}
</a-input>
// <div>
// <a-input onFocus={handleShow} value={unref(computedSelectRowValue)} {...attrs}>
// {inputIconSlots}
// </a-input>
// <span>abc</span>
// </div>
<Row type="flex" class={unref(isVisibleRef) ? 'smart-pulldown-open' : ''}>
<Col class="select">
<a-select
allowClear={unref(allowClearRef)}
showSearch={unref(showSearchRef)}
onFocus={handleShow}
open={false}
onUpdate:value={handleUpdateValue}
searchValue={unref(searchValueRef)}
onSearch={handleSearchChange}
value={unref(computedSelectRowValue)}
></a-select>
</Col>
<Col class="suffix-icon">
<Icon onClick={handleShow} icon="ant-design:table-outlined" />
</Col>
</Row>
),
dropdown: () => (
<div style={unref(computedDropdownContainerStyle)}>
<SmartTable data={unref(tableDataRef)} ref={tableRef} {...dropdownTableProps} />
<SmartTable data={unref(computeTableData)} ref={tableRef} {...dropdownTableProps} />
</div>
),
...slots,
@ -164,6 +285,7 @@ export default defineComponent({
return () => (
<vxe-pulldown
ref={pulldownRef}
onHidePanel={handleHide}
{...attrs}
popup-class-name="smart-pullown-table"
class-name="smart-pullown-input"

27
src/components/Form/src/smart-boot/components/style/SmartPullownTable.less

@ -15,6 +15,33 @@
}
}
@suffix-icon-width: 30px;
.smart-pullown-input {
width: 100%;
.select {
width: calc(100% - @suffix-icon-width);
}
.suffix-icon {
width: @suffix-icon-width;
border: 1px solid #d9d9d9;
border-left: 0;
border-radius: 0 4px 4px 0;
background-color: rgb(0 0 0 / 2%);
text-align: center;
cursor: pointer;
}
.ant-select-selector {
border-top-right-radius: 0 !important;
border-bottom-right-radius: 0 !important;
}
.smart-pulldown-open {
.ant-select-selection-item {
color: rgb(0 0 0 / 25%);
}
}
}

Loading…
Cancel
Save