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 './style/SmartPullownTable.less';
import { useRuleFormItem } from '@/hooks/component/useFormItem'; import { useRuleFormItem } from '@/hooks/component/useFormItem';
import { Row, Col } from 'ant-design-vue';
/** /**
* 下拉表格 * 下拉表格
@ -28,14 +29,74 @@ export default defineComponent({
api: { api: {
type: Function as PropType<() => Promise<any>>, 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 }) { 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 pulldownRef = ref<VxePulldownInstance>();
const dataLoadingRef = ref<boolean>(false); const dataLoadingRef = ref<boolean>(false);
const tableDataRef = ref<Recordable[]>([]); const tableDataRef = ref<Recordable[]>([]);
const tableRef = ref(); 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 selectRowRef = ref<Recordable | null>(null);
const computedSelectRowValue = computed(() => { const computedSelectRowValue = computed(() => {
@ -85,46 +146,67 @@ export default defineComponent({
* 下拉容器样式 * 下拉容器样式
*/ */
const computedDropdownContainerStyle = computed(() => { const computedDropdownContainerStyle = computed(() => {
return { const style: Recordable = {
width: unref(dropdownWidth) + 'px', width: unref(dropdownWidth) + 'px',
}; };
const height = unref(heightRef);
if (height) {
style.height = `${height}px`;
}
return style;
}); });
watch([valueRef, tableDataRef], ([value, tableData]) => { watch([valueRef, tableDataRef], ([value, tableData]) => {
const tableInstance: VxeGridInstance = unref(tableRef)?.tableAction.getTableInstance();
let row: Recordable | null = null; let row: Recordable | null = null;
if (!value) { if (value) {
tableInstance && tableInstance.clearCurrentRow(); const selectRows = tableData.filter(
selectRowRef.value = null; (item) => item[props.valueField].toString() === value.toString(),
return; );
} if (selectRows.length > 0) {
const selectRows = tableData.filter( row = selectRows[0];
(item) => item[props.valueField].toString() === value.toString(), }
);
if (selectRows.length === 0) {
tableInstance && tableInstance.clearCurrentRow();
} else {
row = selectRows[0];
tableInstance && tableInstance.setCurrentRow(selectRows[0]);
} }
selectRowRef.value = row; selectRowRef.value = row;
setCurrentRow();
}); });
/** /**
* 显示弹窗 * 显示弹窗
*/ */
const handleShow = async () => { const handleShow = async () => {
isVisibleRef.value = true;
unref(pulldownRef)?.showPanel(); unref(pulldownRef)?.showPanel();
if (props.alwaysLoad) { if (props.alwaysLoad) {
await loadTableData(); await loadTableData();
} }
emit('visible-change', true);
setCurrentRow();
};
/**
* 设置当前行
*/
const setCurrentRow = () => {
nextTick(() => { nextTick(() => {
const tableInstance: VxeGridInstance = unref(tableRef)?.tableAction.getTableInstance(); const tableInstance: VxeGridInstance = unref(tableRef)?.tableAction.getTableInstance();
if (!tableInstance) {
return;
}
const row = unref(selectRowRef); 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 = { const dropdownTableProps = {
size: 'mini', size: 'mini',
...props.tableProps, ...props.tableProps,
@ -135,6 +217,7 @@ export default defineComponent({
onCellClick: ({ row }) => { onCellClick: ({ row }) => {
changeValue(row); changeValue(row);
unref(pulldownRef)?.hidePanel(); unref(pulldownRef)?.hidePanel();
handleHide();
}, },
}; };
@ -143,20 +226,58 @@ export default defineComponent({
state.value = row?.[props.valueField]; 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 = { const pulldownSlots = {
default: () => ( default: () => (
<a-input onFocus={handleShow} value={unref(computedSelectRowValue)} {...attrs}> // <div>
{inputIconSlots} // <a-input onFocus={handleShow} value={unref(computedSelectRowValue)} {...attrs}>
</a-input> // {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: () => ( dropdown: () => (
<div style={unref(computedDropdownContainerStyle)}> <div style={unref(computedDropdownContainerStyle)}>
<SmartTable data={unref(tableDataRef)} ref={tableRef} {...dropdownTableProps} /> <SmartTable data={unref(computeTableData)} ref={tableRef} {...dropdownTableProps} />
</div> </div>
), ),
...slots, ...slots,
@ -164,6 +285,7 @@ export default defineComponent({
return () => ( return () => (
<vxe-pulldown <vxe-pulldown
ref={pulldownRef} ref={pulldownRef}
onHidePanel={handleHide}
{...attrs} {...attrs}
popup-class-name="smart-pullown-table" popup-class-name="smart-pullown-table"
class-name="smart-pullown-input" 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 { .smart-pullown-input {
width: 100%; 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