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.
400 lines (399 loc) • 14.6 kB
JavaScript
"use strict";
var _vue = require("vue");
var _xeUtils = _interopRequireDefault(require("xe-utils"));
var _ui = require("../../../ui");
var _dom = require("../../../ui/src/dom");
var _utils = require("../../../ui/src/utils");
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
const {
menus,
hooks,
globalEvents,
GLOBAL_EVENT_KEYS
} = _ui.VxeUI;
const tableMenuMethodKeys = ['closeMenu'];
hooks.add('tableMenuModule', {
setupTable($xeTable) {
const {
xID,
props,
reactData,
internalData
} = $xeTable;
const {
refElem,
refTableFilter,
refTableMenu
} = $xeTable.getRefMaps();
const {
computeMouseOpts,
computeIsContentMenu,
computeMenuOpts
} = $xeTable.getComputeMaps();
const $xeGrid = $xeTable.xeGrid;
const $xeGantt = $xeTable.xeGantt;
const $xeGGWrapper = $xeGrid || $xeGantt;
let menuMethods = {};
let menuPrivateMethods = {};
/**
* 显示快捷菜单
*/
const handleOpenMenuEvent = (evnt, type, params) => {
const {
ctxMenuStore
} = reactData;
const isContentMenu = computeIsContentMenu.value;
const menuOpts = computeMenuOpts.value;
const config = menuOpts[type];
const {
transfer,
visibleMethod
} = menuOpts;
if (config) {
const {
options,
disabled
} = config;
if (disabled) {
evnt.preventDefault();
} else if (isContentMenu && options && options.length) {
params.options = options;
$xeTable.preventEvent(evnt, 'event.showMenu', params, () => {
if (!visibleMethod || visibleMethod(params)) {
evnt.preventDefault();
$xeTable.updateZindex();
const el = $xeGGWrapper ? $xeGGWrapper.getRefMaps().refElem.value : refElem.value;
if (!el) {
return;
}
const tableRect = el.getBoundingClientRect();
const {
scrollTop,
scrollLeft,
visibleHeight,
visibleWidth
} = (0, _dom.getDomNode)();
let top = evnt.clientY - tableRect.y;
let left = evnt.clientX - tableRect.x;
if (transfer) {
top = evnt.clientY + scrollTop;
left = evnt.clientX + scrollLeft;
}
const handleVisible = () => {
internalData._currMenuParams = params;
Object.assign(ctxMenuStore, {
visible: true,
list: options,
selected: null,
selectChild: null,
showChild: false,
style: {
zIndex: internalData.tZindex,
top: `${top}px`,
left: `${left}px`
}
});
(0, _vue.nextTick)(() => {
const tableMenu = refTableMenu.value;
const ctxElem = tableMenu.getRefMaps().refElem.value;
const clientHeight = ctxElem.clientHeight;
const clientWidth = ctxElem.clientWidth;
const {
boundingTop,
boundingLeft
} = (0, _dom.getAbsolutePos)(ctxElem);
const offsetTop = boundingTop + clientHeight - visibleHeight;
const offsetLeft = boundingLeft + clientWidth - visibleWidth;
if (offsetTop > -10) {
ctxMenuStore.style.top = `${Math.max(scrollTop + 2, top - clientHeight - 2)}px`;
}
if (offsetLeft > -10) {
ctxMenuStore.style.left = `${Math.max(scrollLeft + 2, left - clientWidth - 2)}px`;
}
});
};
const {
keyboard,
row,
column
} = params;
if (keyboard && row && column) {
$xeTable.scrollToRow(row, column).then(() => {
const cell = $xeTable.getCellElement(row, column);
if (cell) {
const {
boundingTop,
boundingLeft
} = (0, _dom.getAbsolutePos)(cell);
top = boundingTop + scrollTop + Math.floor(cell.offsetHeight / 2);
left = boundingLeft + scrollLeft + Math.floor(cell.offsetWidth / 2);
}
handleVisible();
});
} else {
handleVisible();
}
} else {
menuMethods.closeMenu();
}
});
}
}
$xeTable.closeFilter();
};
menuMethods = {
/**
* 关闭快捷菜单
*/
closeMenu() {
Object.assign(reactData.ctxMenuStore, {
visible: false,
selected: null,
selectChild: null,
showChild: false
});
return (0, _vue.nextTick)();
}
};
menuPrivateMethods = {
/**
* 处理菜单的移动
*/
moveCtxMenu(evnt, ctxMenuStore, property, hasOper, operRest, menuList) {
let selectItem;
const selectIndex = _xeUtils.default.findIndexOf(menuList, item => ctxMenuStore[property] === item);
if (hasOper) {
if (operRest && (0, _utils.hasChildrenList)(ctxMenuStore.selected)) {
ctxMenuStore.showChild = true;
} else {
ctxMenuStore.showChild = false;
ctxMenuStore.selectChild = null;
}
} else if (globalEvents.hasKey(evnt, GLOBAL_EVENT_KEYS.ARROW_UP)) {
for (let len = selectIndex - 1; len >= 0; len--) {
if (menuList[len].visible !== false) {
selectItem = menuList[len];
break;
}
}
ctxMenuStore[property] = selectItem || menuList[menuList.length - 1];
} else if (globalEvents.hasKey(evnt, GLOBAL_EVENT_KEYS.ARROW_DOWN)) {
for (let index = selectIndex + 1; index < menuList.length; index++) {
if (menuList[index].visible !== false) {
selectItem = menuList[index];
break;
}
}
ctxMenuStore[property] = selectItem || menuList[0];
} else if (ctxMenuStore[property] && (globalEvents.hasKey(evnt, GLOBAL_EVENT_KEYS.ENTER) || globalEvents.hasKey(evnt, GLOBAL_EVENT_KEYS.SPACEBAR))) {
$xeTable.ctxMenuLinkEvent(evnt, ctxMenuStore[property]);
}
},
handleOpenMenuEvent,
/**
* 快捷菜单事件处理
*/
handleGlobalContextmenuEvent(evnt) {
const $xeGrid = $xeTable.xeGrid;
const $xeGantt = $xeTable.xeGantt;
const {
mouseConfig,
menuConfig
} = props;
const {
editStore,
ctxMenuStore
} = reactData;
const {
visibleColumn
} = internalData;
const tableFilter = refTableFilter.value;
const tableMenu = refTableMenu.value;
const mouseOpts = computeMouseOpts.value;
const menuOpts = computeMenuOpts.value;
const el = refElem.value;
const {
selected
} = editStore;
const layoutList = ['header', 'body', 'footer'];
if ((0, _utils.isEnableConf)(menuConfig)) {
if (ctxMenuStore.visible && tableMenu && (0, _dom.getEventTargetNode)(evnt, tableMenu.getRefMaps().refElem.value).flag) {
evnt.preventDefault();
return;
}
if (internalData._keyCtx) {
const type = 'body';
const params = {
source: 'table',
type,
$table: $xeTable,
$grid: $xeGrid,
$gantt: $xeGantt,
keyboard: true,
columns: visibleColumn.slice(0),
$event: evnt
};
// 如果开启单元格区域
if (mouseConfig && mouseOpts.area) {
const activeArea = $xeTable.getActiveCellArea();
if (activeArea && activeArea.row && activeArea.column) {
params.row = activeArea.row;
params.column = activeArea.column;
handleOpenMenuEvent(evnt, type, params);
return;
}
} else if (mouseConfig && mouseOpts.selected) {
// 如果启用键盘导航且已选中单元格
if (selected.row && selected.column) {
params.row = selected.row;
params.column = selected.column;
handleOpenMenuEvent(evnt, type, params);
return;
}
}
}
// 分别匹配表尾、内容、表尾的快捷菜单
for (let index = 0; index < layoutList.length; index++) {
const layout = layoutList[index];
const columnTargetNode = (0, _dom.getEventTargetNode)(evnt, el, `vxe-${layout}--column`, target => {
// target=td|th,直接向上找 table 去匹配即可
return target.parentNode.parentNode.parentNode.getAttribute('xid') === xID;
});
const params = {
source: 'table',
type: layout,
$table: $xeTable,
$grid: $xeGrid,
$gantt: $xeGantt,
columns: visibleColumn.slice(0),
$event: evnt
};
if (columnTargetNode.flag) {
const cell = columnTargetNode.targetElem;
const columnNodeRest = $xeTable.getColumnNode(cell);
const column = columnNodeRest ? columnNodeRest.item : null;
let typePrefix = `${layout}-`;
if (column) {
Object.assign(params, {
column,
columnIndex: $xeTable.getColumnIndex(column),
cell
});
}
if (layout === 'body') {
const rowNodeRest = $xeTable.getRowNode(cell.parentNode);
const row = rowNodeRest ? rowNodeRest.item : null;
typePrefix = '';
if (row) {
params.row = row;
params.rowIndex = $xeTable.getRowIndex(row);
}
}
const eventType = `${typePrefix}cell-menu`;
handleOpenMenuEvent(evnt, layout, params);
$xeTable.dispatchEvent(eventType, params, evnt);
return;
} else if ((0, _dom.getEventTargetNode)(evnt, el, `vxe-table--${layout}-wrapper`, target => target.getAttribute('xid') === xID).flag || layout === 'body' && (0, _dom.getEventTargetNode)(evnt, el, 'vxe-table--empty-place-wrapper', target => target.getAttribute('xid') === xID).flag) {
if (menuOpts.trigger === 'cell') {
evnt.preventDefault();
} else {
handleOpenMenuEvent(evnt, layout, params);
}
return;
}
}
}
if (tableFilter && !(0, _dom.getEventTargetNode)(evnt, tableFilter.getRefMaps().refElem.value).flag) {
$xeTable.closeFilter();
}
menuMethods.closeMenu();
},
ctxMenuMouseoverEvent(evnt, item, child) {
const menuElem = evnt.currentTarget;
const {
ctxMenuStore
} = reactData;
evnt.preventDefault();
evnt.stopPropagation();
ctxMenuStore.selected = item;
ctxMenuStore.selectChild = child;
if (!child) {
ctxMenuStore.showChild = (0, _utils.hasChildrenList)(item);
if (ctxMenuStore.showChild) {
(0, _vue.nextTick)(() => {
const childWrapperElem = menuElem.nextElementSibling;
if (childWrapperElem) {
const {
boundingTop,
boundingLeft,
visibleHeight,
visibleWidth
} = (0, _dom.getAbsolutePos)(menuElem);
const posTop = boundingTop + menuElem.offsetHeight;
const posLeft = boundingLeft + menuElem.offsetWidth;
let left = '';
let right = '';
// 是否超出右侧
if (posLeft + childWrapperElem.offsetWidth > visibleWidth - 10) {
left = 'auto';
right = `${menuElem.offsetWidth}px`;
}
// 是否超出底部
let top = '';
let bottom = '';
if (posTop + childWrapperElem.offsetHeight > visibleHeight - 10) {
top = 'auto';
bottom = '0';
}
childWrapperElem.style.left = left;
childWrapperElem.style.right = right;
childWrapperElem.style.top = top;
childWrapperElem.style.bottom = bottom;
}
});
}
}
},
ctxMenuMouseoutEvent(evnt, item) {
const {
ctxMenuStore
} = reactData;
if (!item.children) {
ctxMenuStore.selected = null;
}
ctxMenuStore.selectChild = null;
},
/**
* 快捷菜单点击事件
*/
ctxMenuLinkEvent(evnt, menu) {
const $xeGrid = $xeTable.xeGrid;
const $xeGantt = $xeTable.xeGantt;
// 如果一级菜单有配置 code 则允许点击,否则不能点击
if (!menu.loading && !menu.disabled && (menu.code || !menu.children || !menu.children.length)) {
const gMenuOpts = menus.get(menu.code);
const params = Object.assign({}, internalData._currMenuParams, {
menu,
$table: $xeTable,
$grid: $xeGrid,
$gantt: $xeGantt,
$event: evnt
});
const tmMethod = gMenuOpts ? gMenuOpts.tableMenuMethod || gMenuOpts.menuMethod : null;
if (tmMethod) {
tmMethod(params, evnt);
}
$xeTable.dispatchEvent('menu-click', params, evnt);
menuMethods.closeMenu();
}
}
};
return Object.assign(Object.assign({}, menuMethods), menuPrivateMethods);
},
setupGrid($xeGrid) {
return $xeGrid.extendTableMethods(tableMenuMethodKeys);
},
setupGantt($xeGantt) {
return $xeGantt.extendTableMethods(tableMenuMethodKeys);
}
});