vxe-table
Version:
A PC-end table component based on Vxe UI, supporting copy-paste, data pivot table, and high-performance virtual list table solution.
658 lines (657 loc) • 28.9 kB
JavaScript
import { h, ref, computed, inject, createCommentVNode, reactive, nextTick, onUnmounted } from 'vue';
import { defineVxeComponent } from '../../ui/src/comp';
import XEUtils from 'xe-utils';
import { VxeUI } from '../../ui';
import { getSlotVNs } from '../../ui/src/vn';
import { warnLog, errLog } from '../../ui/src/log';
const { getConfig, getIcon, getI18n, renderer, commands, createEvent, useFns } = VxeUI;
function createInternalData() {
return {
connectTable: null
};
}
export default defineVxeComponent({
name: 'VxeToolbar',
props: {
loading: Boolean,
refresh: [Boolean, Object],
refreshOptions: Object,
import: [Boolean, Object],
importOptions: Object,
export: [Boolean, Object],
exportOptions: Object,
print: [Boolean, Object],
printOptions: Object,
zoom: [Boolean, Object],
zoomOptions: Object,
custom: [Boolean, Object],
customOptions: Object,
buttons: {
type: Array,
default: () => getConfig().toolbar.buttons
},
tools: {
type: Array,
default: () => getConfig().toolbar.tools
},
perfect: {
type: Boolean,
default: () => getConfig().toolbar.perfect
},
size: {
type: String,
default: () => getConfig().toolbar.size || getConfig().size
},
className: [String, Function]
},
emits: [
'button-click',
'tool-click'
],
setup(props, context) {
const { slots, emit } = context;
const xID = XEUtils.uniqueId();
// 使用已安装的组件,如果未安装则不渲染
const VxeUIButtonComponent = VxeUI.getComponent('VxeButton');
const { computeSize } = useFns.useSize(props);
const reactData = reactive({
isRefresh: false,
connectFlag: 0,
columns: []
});
const internalData = createInternalData();
const refElem = ref();
const refMaps = {
refElem
};
const $xeToolbar = {
xID,
props,
context,
reactData,
internalData,
getRefMaps: () => refMaps
};
let toolbarMethods = {};
const $xeGrid = inject('$xeGrid', null);
const computeRefreshOpts = computed(() => {
return Object.assign({}, XEUtils.clone(getConfig().toolbar.refresh, true), props.refreshOptions, props.refresh);
});
const computeImportOpts = computed(() => {
return Object.assign({}, XEUtils.clone(getConfig().toolbar.import, true), props.importOptions, props.import);
});
const computeExportOpts = computed(() => {
return Object.assign({}, XEUtils.clone(getConfig().toolbar.export, true), props.exportOptions, props.export);
});
const computePrintOpts = computed(() => {
return Object.assign({}, XEUtils.clone(getConfig().toolbar.print, true), props.printOptions, props.print);
});
const computeZoomOpts = computed(() => {
return Object.assign({}, XEUtils.clone(getConfig().toolbar.zoom, true), props.zoomOptions, props.zoom);
});
const computeCustomOpts = computed(() => {
return Object.assign({}, XEUtils.clone(getConfig().toolbar.custom, true), props.customOptions, props.custom);
});
const computeTableCustomOpts = computed(() => {
const { connectTable } = internalData;
const $table = connectTable;
if (reactData.connectFlag || $table) {
if ($table) {
const { computeCustomOpts } = $table.getComputeMaps();
return computeCustomOpts.value;
}
}
return { trigger: '' };
});
const computeTrigger = computed(() => {
const tableCustomOpts = computeTableCustomOpts.value;
return tableCustomOpts.trigger;
});
const checkTable = () => {
const { connectTable } = internalData;
const $table = connectTable;
if ($table) {
return true;
}
errLog('vxe.error.barUnableLink');
};
const handleClickSettingEvent = ({ $event }) => {
const { connectTable } = internalData;
const $table = connectTable;
if ($table) {
if ($table.triggerCustomEvent) {
$table.triggerCustomEvent($event);
}
}
};
const handleMouseenterSettingEvent = ({ $event }) => {
const { connectTable } = internalData;
const $table = connectTable;
if ($table) {
$table.customOpenEvent($event);
}
};
const handleMouseleaveSettingEvent = ({ $event }) => {
const { connectTable } = internalData;
const $table = connectTable;
if ($table) {
const { customStore } = $table.reactData;
customStore.activeBtn = false;
setTimeout(() => {
if (!customStore.activeBtn && !customStore.activeWrapper) {
$table.customCloseEvent($event);
}
}, 350);
}
};
const refreshEvent = ({ $event }) => {
const { isRefresh } = reactData;
const refreshOpts = computeRefreshOpts.value;
if (!isRefresh) {
const queryMethod = refreshOpts.queryMethod || refreshOpts.query;
if (queryMethod) {
reactData.isRefresh = true;
try {
Promise.resolve(queryMethod({})).catch((e) => e).then(() => {
reactData.isRefresh = false;
});
}
catch (e) {
reactData.isRefresh = false;
}
}
else if ($xeGrid) {
reactData.isRefresh = true;
$xeGrid.triggerToolbarCommitEvent({ code: refreshOpts.code || 'reload' }, $event).catch((e) => e).then(() => {
reactData.isRefresh = false;
});
}
}
};
const zoomEvent = ({ $event }) => {
if ($xeGrid) {
$xeGrid.triggerZoomEvent($event);
}
else {
warnLog('vxe.error.notProp', ['zoom']);
}
};
const importEvent = () => {
if (checkTable()) {
const { connectTable } = internalData;
const $table = connectTable;
if ($table) {
$table.importData();
}
}
};
const openImportEvent = () => {
if (checkTable()) {
const { connectTable } = internalData;
const $table = connectTable;
if ($table) {
$table.openImport();
}
}
};
const exportEvent = () => {
if (checkTable()) {
const { connectTable } = internalData;
const $table = connectTable;
if ($table) {
$table.exportData();
}
}
};
const openExportEvent = () => {
if (checkTable()) {
const { connectTable } = internalData;
const $table = connectTable;
if ($table) {
$table.openExport();
}
}
};
const printEvent = () => {
if (checkTable()) {
const { connectTable } = internalData;
const $table = connectTable;
if ($table) {
$table.print();
}
}
};
const openPrintEvent = () => {
if (checkTable()) {
const { connectTable } = internalData;
const $table = connectTable;
if ($table) {
$table.openPrint();
}
}
};
const handleDefaultCodeEvent = (eventParams, item, cb) => {
switch (item.code) {
case 'print':
printEvent();
break;
case 'open_print':
openPrintEvent();
break;
case 'custom':
handleClickSettingEvent(eventParams);
break;
case 'export':
exportEvent();
break;
case 'open_export':
openExportEvent();
break;
case 'import':
importEvent();
break;
case 'open_import':
openImportEvent();
break;
case 'zoom':
zoomEvent(eventParams);
break;
case 'refresh':
refreshEvent(eventParams);
break;
default:
cb();
break;
}
};
const btnEvent = (eventParams, item) => {
const { $event } = eventParams;
const { connectTable } = internalData;
const $table = connectTable;
const { code } = item;
if (code) {
handleDefaultCodeEvent(eventParams, item, () => {
if ($xeGrid) {
$xeGrid.triggerToolbarBtnEvent(item, $event);
}
else {
const gCommandOpts = commands.get(code);
const params = { code, button: item, $table: $table, $grid: $xeGrid, $gantt: null, $event };
if (gCommandOpts) {
const tCommandMethod = gCommandOpts.tableCommandMethod || gCommandOpts.commandMethod;
if (tCommandMethod) {
tCommandMethod(params);
}
else {
errLog('vxe.error.notCommands', [code]);
}
}
$xeToolbar.dispatchEvent('button-click', params, $event);
}
});
}
};
const tolEvent = (eventParams, item) => {
const { $event } = eventParams;
const { connectTable } = internalData;
const $table = connectTable;
const { code } = item;
if (code) {
handleDefaultCodeEvent(eventParams, item, () => {
if ($xeGrid) {
$xeGrid.triggerToolbarTolEvent(item, $event);
}
else {
const gCommandOpts = commands.get(code);
const params = { code, button: null, tool: item, $table: $table, $grid: $xeGrid, $gantt: null, $event };
if (gCommandOpts) {
const tCommandMethod = gCommandOpts.tableCommandMethod || gCommandOpts.commandMethod;
if (tCommandMethod) {
tCommandMethod(params);
}
else {
errLog('vxe.error.notCommands', [code]);
}
}
$xeToolbar.dispatchEvent('tool-click', params, $event);
}
});
}
};
const dispatchEvent = (type, params, evnt) => {
emit(type, createEvent(evnt, { $toolbar: $xeToolbar }, params));
};
toolbarMethods = {
dispatchEvent,
syncUpdate(params) {
internalData.connectTable = params.$table;
reactData.columns = params.collectColumn;
reactData.connectFlag++;
}
};
Object.assign($xeToolbar, toolbarMethods);
const renderDropdowns = (item, isBtn) => {
const { dropdowns } = item;
const downVNs = [];
if (dropdowns) {
return dropdowns.map((child, index) => {
if (child.visible === false) {
return createCommentVNode();
}
return VxeUIButtonComponent
? h(VxeUIButtonComponent, {
key: index,
disabled: child.disabled,
loading: child.loading,
type: child.type,
mode: child.mode,
icon: child.icon,
circle: child.circle,
round: child.round,
status: child.status,
content: child.name,
title: child.title,
routerLink: child.routerLink,
permissionCode: child.permissionCode,
prefixTooltip: child.prefixTooltip,
suffixTooltip: child.suffixTooltip,
onClick: (eventParams) => isBtn ? btnEvent(eventParams, child) : tolEvent(eventParams, child)
})
: createCommentVNode();
});
}
return downVNs;
};
/**
* 渲染按钮
*/
const renderLeftBtns = () => {
const { buttons } = props;
const { connectTable } = internalData;
const $table = connectTable;
const buttonPrefixSlot = slots.buttonPrefix || slots['button-prefix'];
const buttonSuffixSlot = slots.buttonSuffix || slots['button-suffix'];
const btnVNs = [];
if (buttonPrefixSlot) {
btnVNs.push(...getSlotVNs(buttonPrefixSlot({ buttons: buttons || [], $grid: $xeGrid, $table: $table })));
}
if (buttons) {
buttons.forEach((item, index) => {
const { dropdowns, buttonRender } = item;
if (item.visible !== false) {
const compConf = buttonRender ? renderer.get(buttonRender.name) : null;
if (buttonRender && compConf && compConf.renderToolbarButton) {
const toolbarButtonClassName = compConf.toolbarButtonClassName;
const params = { $grid: $xeGrid, $table: $table, button: item };
btnVNs.push(h('span', {
key: `br${item.code || index}`,
class: ['vxe-button--item', toolbarButtonClassName ? (XEUtils.isFunction(toolbarButtonClassName) ? toolbarButtonClassName(params) : toolbarButtonClassName) : '']
}, getSlotVNs(compConf.renderToolbarButton(buttonRender, params))));
}
else {
if (VxeUIButtonComponent) {
btnVNs.push(h(VxeUIButtonComponent, {
key: `bd${item.code || index}`,
disabled: item.disabled,
loading: item.loading,
type: item.type,
mode: item.mode,
icon: item.icon,
circle: item.circle,
round: item.round,
status: item.status,
content: item.name,
title: item.title,
routerLink: item.routerLink,
permissionCode: item.permissionCode,
prefixTooltip: item.prefixTooltip,
suffixTooltip: item.suffixTooltip,
destroyOnClose: item.destroyOnClose,
placement: item.placement,
transfer: item.transfer,
onClick: (eventParams) => btnEvent(eventParams, item)
}, dropdowns && dropdowns.length
? {
dropdowns: () => renderDropdowns(item, true)
}
: {}));
}
}
}
});
}
if (buttonSuffixSlot) {
btnVNs.push(...getSlotVNs(buttonSuffixSlot({ buttons: buttons || [], $grid: $xeGrid, $table: $table })));
}
return btnVNs;
};
/**
* 渲染右侧工具
*/
const renderRightTools = () => {
const { tools } = props;
const { connectTable } = internalData;
const $table = connectTable;
const toolPrefixSlot = slots.toolPrefix || slots['tool-prefix'];
const toolSuffixSlot = slots.toolSuffix || slots['tool-suffix'];
const btnVNs = [];
if (toolPrefixSlot) {
btnVNs.push(...getSlotVNs(toolPrefixSlot({ tools: tools || [], $grid: $xeGrid, $table: $table })));
}
if (tools) {
tools.forEach((item, tIndex) => {
const { dropdowns, toolRender } = item;
if (item.visible !== false) {
const rdName = toolRender ? toolRender.name : null;
const compConf = toolRender ? renderer.get(rdName) : null;
if (toolRender && compConf && compConf.renderToolbarTool) {
const toolbarToolClassName = compConf.toolbarToolClassName;
const params = { $grid: $xeGrid, $table: $table, tool: item };
btnVNs.push(h('span', {
key: rdName,
class: ['vxe-tool--item', toolbarToolClassName ? (XEUtils.isFunction(toolbarToolClassName) ? toolbarToolClassName(params) : toolbarToolClassName) : '']
}, getSlotVNs(compConf.renderToolbarTool(toolRender, params))));
}
else {
if (VxeUIButtonComponent) {
btnVNs.push(h(VxeUIButtonComponent, {
key: tIndex,
disabled: item.disabled,
loading: item.loading,
type: item.type,
mode: item.mode,
icon: item.icon,
circle: item.circle,
round: item.round,
status: item.status,
content: item.name,
title: item.title,
routerLink: item.routerLink,
permissionCode: item.permissionCode,
prefixTooltip: item.prefixTooltip,
suffixTooltip: item.suffixTooltip,
destroyOnClose: item.destroyOnClose,
placement: item.placement,
transfer: item.transfer,
onClick: (eventParams) => tolEvent(eventParams, item)
}, dropdowns && dropdowns.length
? {
dropdowns: () => renderDropdowns(item, false)
}
: {}));
}
}
}
});
}
if (toolSuffixSlot) {
btnVNs.push(...getSlotVNs(toolSuffixSlot({ tools: tools || [], $grid: $xeGrid, $table: $table })));
}
return btnVNs;
};
const renderToolImport = () => {
const importOpts = computeImportOpts.value;
return VxeUIButtonComponent
? h(VxeUIButtonComponent, {
key: 'import',
circle: true,
icon: importOpts.icon || getIcon().TOOLBAR_TOOLS_IMPORT,
title: getI18n('vxe.toolbar.import'),
onClick: openImportEvent
})
: createCommentVNode();
};
const renderToolExport = () => {
const exportOpts = computeExportOpts.value;
return VxeUIButtonComponent
? h(VxeUIButtonComponent, {
key: 'export',
circle: true,
icon: exportOpts.icon || getIcon().TOOLBAR_TOOLS_EXPORT,
title: getI18n('vxe.toolbar.export'),
onClick: openExportEvent
})
: createCommentVNode();
};
const renderToolPrint = () => {
const printOpts = computePrintOpts.value;
return VxeUIButtonComponent
? h(VxeUIButtonComponent, {
key: 'print',
circle: true,
icon: printOpts.icon || getIcon().TOOLBAR_TOOLS_PRINT,
title: getI18n('vxe.toolbar.print'),
onClick: openPrintEvent
})
: createCommentVNode();
};
const renderToolRefresh = () => {
const refreshOpts = computeRefreshOpts.value;
return VxeUIButtonComponent
? h(VxeUIButtonComponent, {
key: 'refresh',
circle: true,
icon: reactData.isRefresh ? (refreshOpts.iconLoading || getIcon().TOOLBAR_TOOLS_REFRESH_LOADING) : (refreshOpts.icon || getIcon().TOOLBAR_TOOLS_REFRESH),
title: getI18n('vxe.toolbar.refresh'),
onClick: refreshEvent
})
: createCommentVNode();
};
const renderToolZoom = () => {
const zoomOpts = computeZoomOpts.value;
return $xeGrid && VxeUIButtonComponent
? h(VxeUIButtonComponent, {
key: 'zoom',
circle: true,
icon: $xeGrid.isMaximized() ? (zoomOpts.iconOut || getIcon().TOOLBAR_TOOLS_MINIMIZE) : (zoomOpts.iconIn || getIcon().TOOLBAR_TOOLS_FULLSCREEN),
title: getI18n(`vxe.toolbar.zoom${$xeGrid.isMaximized() ? 'Out' : 'In'}`),
onClick: zoomEvent
})
: createCommentVNode();
};
const renderToolCustom = () => {
const customOpts = computeCustomOpts.value;
const btnTrigger = computeTrigger.value;
const customBtnOns = {};
if (btnTrigger === 'manual') {
// 手动触发
}
else if (btnTrigger === 'hover') {
// hover 触发
customBtnOns.onMouseenter = handleMouseenterSettingEvent;
customBtnOns.onMouseleave = handleMouseleaveSettingEvent;
}
else {
// 点击触发
customBtnOns.onClick = handleClickSettingEvent;
}
return VxeUIButtonComponent
? h(VxeUIButtonComponent, Object.assign({ key: 'custom', circle: true, icon: customOpts.icon || getIcon().TOOLBAR_TOOLS_CUSTOM, title: getI18n('vxe.toolbar.custom'), className: 'vxe-toolbar-custom-target' }, customBtnOns))
: createCommentVNode();
};
const renderVN = () => {
const { perfect, loading, refresh, zoom, custom, className } = props;
const { connectTable } = internalData;
const vSize = computeSize.value;
const toolsSlot = slots.tools;
const buttonsSlot = slots.buttons;
const $table = connectTable;
return h('div', {
ref: refElem,
class: ['vxe-toolbar', className ? (XEUtils.isFunction(className) ? className({ $toolbar: $xeToolbar }) : className) : '', {
[`size--${vSize}`]: vSize,
'is--perfect': perfect,
'is--loading': loading
}]
}, [
h('div', {
class: 'vxe-buttons--wrapper'
}, buttonsSlot ? buttonsSlot({ $grid: $xeGrid, $table: $table }) : renderLeftBtns()),
h('div', {
class: 'vxe-tools--wrapper'
}, toolsSlot ? toolsSlot({ $grid: $xeGrid, $table: $table }) : renderRightTools()),
h('div', {
class: 'vxe-tools--operate'
}, [
props.import ? renderToolImport() : createCommentVNode(),
props.export ? renderToolExport() : createCommentVNode(),
props.print ? renderToolPrint() : createCommentVNode(),
refresh ? renderToolRefresh() : createCommentVNode(),
zoom && $xeGrid ? renderToolZoom() : createCommentVNode(),
custom ? renderToolCustom() : createCommentVNode()
])
]);
};
$xeToolbar.renderVN = renderVN;
nextTick(() => {
const refreshOpts = computeRefreshOpts.value;
const queryMethod = refreshOpts.queryMethod || refreshOpts.query;
if (props.refresh && !$xeGrid && !queryMethod) {
warnLog('vxe.error.notFunc', ['queryMethod']);
}
if (XEUtils.isPlainObject(props.custom)) {
warnLog('vxe.error.delProp', ['custom={...}', 'custom=boolean & custom-options={...}']);
}
if (XEUtils.isPlainObject(props.print)) {
warnLog('vxe.error.delProp', ['print={...}', 'print=boolean & print-options={...}']);
}
if (XEUtils.isPlainObject(props.export)) {
warnLog('vxe.error.delProp', ['export={...}', 'export=boolean & export-options={...}']);
}
if (XEUtils.isPlainObject(props.import)) {
warnLog('vxe.error.delProp', ['import={...}', 'import=boolean & import-options={...}']);
}
if (XEUtils.isPlainObject(props.refresh)) {
warnLog('vxe.error.delProp', ['refresh={...}', 'refresh=boolean & refresh-options={...}']);
}
if (XEUtils.isPlainObject(props.refresh)) {
warnLog('vxe.error.delProp', ['zoom={...}', 'zoom=boolean & zoom-options={...}']);
}
const customOpts = computeCustomOpts.value;
if (customOpts.isFooter) {
warnLog('vxe.error.delProp', ['toolbar.custom.isFooter', 'table.custom-config.showFooter']);
}
if (customOpts.showFooter) {
warnLog('vxe.error.delProp', ['toolbar.custom.showFooter', 'table.custom-config.showFooter']);
}
if (customOpts.immediate) {
warnLog('vxe.error.delProp', ['toolbar.custom.immediate', 'table.custom-config.immediate']);
}
if (customOpts.trigger) {
warnLog('vxe.error.delProp', ['toolbar.custom.trigger', 'table.custom-config.trigger']);
}
if (props.refresh || props.import || props.export || props.print || props.zoom) {
if (!VxeUIButtonComponent) {
errLog('vxe.error.reqComp', ['vxe-button']);
}
}
});
onUnmounted(() => {
XEUtils.assign(internalData, createInternalData());
});
return $xeToolbar;
},
render() {
return this.renderVN();
}
});