mixin.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.default = void 0;
  6. var _xeUtils = _interopRequireDefault(require("xe-utils"));
  7. var _util = require("../../src/util");
  8. var _dom = require("../../../ui/src/dom");
  9. function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
  10. function getCheckboxRangeRows($xeTable, evnt, params, targetTrElem, trRect, offsetClientTop, moveRange) {
  11. const props = $xeTable;
  12. const reactData = $xeTable;
  13. const internalData = $xeTable;
  14. const {
  15. showOverflow
  16. } = props;
  17. const {
  18. fullAllDataRowIdData,
  19. isResizeCellHeight
  20. } = internalData;
  21. const rowOpts = $xeTable.computeRowOpts;
  22. const cellOpts = $xeTable.computeCellOpts;
  23. const defaultRowHeight = $xeTable.computeDefaultRowHeight;
  24. const {
  25. row
  26. } = params;
  27. let countHeight = 0;
  28. let rangeRows = [];
  29. let moveSize = 0;
  30. const isDown = moveRange > 0;
  31. const {
  32. scrollYLoad
  33. } = reactData;
  34. const {
  35. afterFullData
  36. } = internalData;
  37. if (isDown) {
  38. moveSize = offsetClientTop + moveRange;
  39. } else {
  40. moveSize = trRect.height - offsetClientTop + Math.abs(moveRange);
  41. }
  42. if (scrollYLoad) {
  43. const _rowIndex = $xeTable.getVTRowIndex(row);
  44. const isCustomCellHeight = isResizeCellHeight || cellOpts.height || rowOpts.height;
  45. if (!isCustomCellHeight && showOverflow) {
  46. if (isDown) {
  47. rangeRows = afterFullData.slice(_rowIndex, _rowIndex + Math.ceil(moveSize / defaultRowHeight));
  48. } else {
  49. rangeRows = afterFullData.slice(_rowIndex - Math.floor(moveSize / defaultRowHeight), _rowIndex + 1);
  50. }
  51. } else {
  52. if (isDown) {
  53. for (let i = _rowIndex; i < afterFullData.length; i++) {
  54. const item = afterFullData[i];
  55. const rowid = $xeTable.getRowid(item);
  56. const rowRest = fullAllDataRowIdData[rowid] || {};
  57. countHeight += rowRest.resizeHeight || cellOpts.height || rowOpts.height || rowRest.height || defaultRowHeight;
  58. rangeRows.push(item);
  59. if (countHeight > moveSize) {
  60. return rangeRows;
  61. }
  62. }
  63. } else {
  64. for (let len = _rowIndex; len >= 0; len--) {
  65. const item = afterFullData[len];
  66. const rowid = $xeTable.getRowid(item);
  67. const rowRest = fullAllDataRowIdData[rowid] || {};
  68. countHeight += rowRest.resizeHeight || cellOpts.height || rowOpts.height || rowRest.height || defaultRowHeight;
  69. rangeRows.push(item);
  70. if (countHeight > moveSize) {
  71. return rangeRows;
  72. }
  73. }
  74. }
  75. }
  76. } else {
  77. const siblingProp = isDown ? 'next' : 'previous';
  78. while (targetTrElem && countHeight < moveSize) {
  79. const rowNodeRest = $xeTable.getRowNode(targetTrElem);
  80. if (rowNodeRest) {
  81. rangeRows.push(rowNodeRest.item);
  82. countHeight += targetTrElem.offsetHeight;
  83. targetTrElem = targetTrElem[`${siblingProp}ElementSibling`];
  84. }
  85. }
  86. }
  87. return rangeRows;
  88. }
  89. function handleMoveSelected($xeTable, evnt, args, isLeftArrow, isUpArrow, isRightArrow, isDwArrow) {
  90. const internalData = $xeTable;
  91. const {
  92. afterFullData,
  93. visibleColumn
  94. } = internalData;
  95. const params = Object.assign({}, args);
  96. const _rowIndex = $xeTable.getVTRowIndex(params.row);
  97. const _columnIndex = $xeTable.getVTColumnIndex(params.column);
  98. evnt.preventDefault();
  99. if (isUpArrow && _rowIndex > 0) {
  100. // 移动到上一行
  101. params.rowIndex = _rowIndex - 1;
  102. params.row = afterFullData[params.rowIndex];
  103. } else if (isDwArrow && _rowIndex < afterFullData.length - 1) {
  104. // 移动到下一行
  105. params.rowIndex = _rowIndex + 1;
  106. params.row = afterFullData[params.rowIndex];
  107. } else if (isLeftArrow && _columnIndex) {
  108. // 移动到左侧单元格
  109. params.columnIndex = _columnIndex - 1;
  110. params.column = visibleColumn[params.columnIndex];
  111. } else if (isRightArrow && _columnIndex < visibleColumn.length - 1) {
  112. // 移动到右侧单元格
  113. params.columnIndex = _columnIndex + 1;
  114. params.column = visibleColumn[params.columnIndex];
  115. }
  116. $xeTable.scrollToRow(params.row, params.column).then(() => {
  117. params.cell = $xeTable.getCellElement(params.row, params.column);
  118. $xeTable.handleSelected(params, evnt);
  119. });
  120. return params;
  121. }
  122. function handleCheckboxRangeEvent($xeTable, evnt, params) {
  123. const internalData = $xeTable;
  124. const {
  125. elemStore
  126. } = internalData;
  127. const bodyScrollElem = (0, _util.getRefElem)(elemStore['main-body-scroll']);
  128. const leftScrollElem = (0, _util.getRefElem)(elemStore['left-body-scroll']);
  129. const rightScrollElem = (0, _util.getRefElem)(elemStore['right-body-scroll']);
  130. const {
  131. column,
  132. cell
  133. } = params;
  134. if (column.type === 'checkbox') {
  135. let bodyWrapperElem = bodyScrollElem;
  136. if (leftScrollElem && column.fixed === 'left') {
  137. bodyWrapperElem = leftScrollElem;
  138. } else if (rightScrollElem && column.fixed === 'right') {
  139. bodyWrapperElem = rightScrollElem;
  140. }
  141. if (!bodyWrapperElem) {
  142. return;
  143. }
  144. const bodyRect = bodyWrapperElem.getBoundingClientRect();
  145. const el = $xeTable.$refs.refElem;
  146. const disX = evnt.clientX;
  147. const disY = evnt.clientY;
  148. const checkboxRangeElem = bodyWrapperElem.querySelector('.vxe-table--checkbox-range');
  149. const trElem = cell.parentNode;
  150. const selectRecords = $xeTable.getCheckboxRecords();
  151. let lastRangeRows = [];
  152. const marginSize = 1;
  153. const startTop = evnt.clientY - bodyRect.y + bodyWrapperElem.scrollTop;
  154. const startLeft = evnt.clientX - bodyRect.x + bodyWrapperElem.scrollLeft;
  155. const startScrollTop = bodyWrapperElem.scrollTop;
  156. const rowHeight = trElem.offsetHeight;
  157. const trRect = trElem.getBoundingClientRect();
  158. const offsetClientTop = disY - trRect.y;
  159. let mouseScrollTimeout = null;
  160. let isMouseScrollDown = false;
  161. let mouseScrollSpaceSize = 1;
  162. const triggerEvent = (type, evnt) => {
  163. $xeTable.dispatchEvent(`checkbox-range-${type}`, {
  164. records: () => $xeTable.getCheckboxRecords(),
  165. reserves: () => $xeTable.getCheckboxReserveRecords()
  166. }, evnt);
  167. };
  168. const handleChecked = evnt => {
  169. const {
  170. clientX,
  171. clientY
  172. } = evnt;
  173. const offsetLeft = clientX - disX;
  174. const offsetTop = clientY - disY + (bodyWrapperElem.scrollTop - startScrollTop);
  175. let rangeHeight = Math.abs(offsetTop);
  176. let rangeWidth = Math.abs(offsetLeft);
  177. let rangeTop = startTop;
  178. let rangeLeft = startLeft;
  179. if (offsetTop < marginSize) {
  180. // 向上
  181. rangeTop += offsetTop;
  182. if (rangeTop < marginSize) {
  183. rangeTop = marginSize;
  184. rangeHeight = startTop;
  185. }
  186. } else {
  187. // 向下
  188. rangeHeight = Math.min(rangeHeight, bodyWrapperElem.scrollHeight - startTop - marginSize);
  189. }
  190. if (offsetLeft < marginSize) {
  191. // 向左
  192. rangeLeft += offsetLeft;
  193. if (rangeWidth > startLeft) {
  194. rangeLeft = marginSize;
  195. rangeWidth = startLeft;
  196. }
  197. } else {
  198. // 向右
  199. rangeWidth = Math.min(rangeWidth, bodyWrapperElem.clientWidth - startLeft - marginSize);
  200. }
  201. checkboxRangeElem.style.height = `${rangeHeight}px`;
  202. checkboxRangeElem.style.width = `${rangeWidth}px`;
  203. checkboxRangeElem.style.left = `${rangeLeft}px`;
  204. checkboxRangeElem.style.top = `${rangeTop}px`;
  205. checkboxRangeElem.style.display = 'block';
  206. const rangeRows = getCheckboxRangeRows($xeTable, evnt, params, trElem, trRect, offsetClientTop, offsetTop < marginSize ? -rangeHeight : rangeHeight);
  207. // 至少滑动 10px 才能有效匹配
  208. if (rangeHeight > 10 && rangeRows.length !== lastRangeRows.length) {
  209. const isControlKey = (0, _dom.hasControlKey)(evnt);
  210. lastRangeRows = rangeRows;
  211. if (isControlKey) {
  212. rangeRows.forEach(row => {
  213. $xeTable.handleBatchSelectRows([row], selectRecords.indexOf(row) === -1);
  214. });
  215. } else {
  216. $xeTable.setAllCheckboxRow(false);
  217. $xeTable.handleCheckedCheckboxRow(rangeRows, true, false);
  218. }
  219. triggerEvent('change', evnt);
  220. }
  221. };
  222. // 停止鼠标滚动
  223. const stopMouseScroll = () => {
  224. clearTimeout(mouseScrollTimeout);
  225. mouseScrollTimeout = null;
  226. };
  227. // 开始鼠标滚动
  228. const startMouseScroll = evnt => {
  229. stopMouseScroll();
  230. mouseScrollTimeout = setTimeout(() => {
  231. if (mouseScrollTimeout) {
  232. const {
  233. scrollLeft,
  234. scrollTop,
  235. clientHeight,
  236. scrollHeight
  237. } = bodyWrapperElem;
  238. const topSize = Math.ceil(mouseScrollSpaceSize * 50 / rowHeight);
  239. if (isMouseScrollDown) {
  240. if (scrollTop + clientHeight < scrollHeight) {
  241. $xeTable.scrollTo(scrollLeft, scrollTop + topSize);
  242. startMouseScroll(evnt);
  243. handleChecked(evnt);
  244. } else {
  245. stopMouseScroll();
  246. }
  247. } else {
  248. if (scrollTop) {
  249. $xeTable.scrollTo(scrollLeft, scrollTop - topSize);
  250. startMouseScroll(evnt);
  251. handleChecked(evnt);
  252. } else {
  253. stopMouseScroll();
  254. }
  255. }
  256. }
  257. }, 50);
  258. };
  259. (0, _dom.addClass)(el, 'drag--range');
  260. document.onmousemove = evnt => {
  261. evnt.preventDefault();
  262. evnt.stopPropagation();
  263. const {
  264. clientY
  265. } = evnt;
  266. const {
  267. boundingTop
  268. } = (0, _dom.getAbsolutePos)(bodyWrapperElem);
  269. // 如果超过可视区,触发滚动
  270. if (clientY < boundingTop) {
  271. isMouseScrollDown = false;
  272. mouseScrollSpaceSize = boundingTop - clientY;
  273. if (!mouseScrollTimeout) {
  274. startMouseScroll(evnt);
  275. }
  276. } else if (clientY > boundingTop + bodyWrapperElem.clientHeight) {
  277. isMouseScrollDown = true;
  278. mouseScrollSpaceSize = clientY - boundingTop - bodyWrapperElem.clientHeight;
  279. if (!mouseScrollTimeout) {
  280. startMouseScroll(evnt);
  281. }
  282. } else if (mouseScrollTimeout) {
  283. stopMouseScroll();
  284. }
  285. handleChecked(evnt);
  286. };
  287. document.onmouseup = evnt => {
  288. stopMouseScroll();
  289. (0, _dom.removeClass)(el, 'drag--range');
  290. checkboxRangeElem.removeAttribute('style');
  291. document.onmousemove = null;
  292. document.onmouseup = null;
  293. triggerEvent('end', evnt);
  294. };
  295. triggerEvent('start', evnt);
  296. }
  297. }
  298. var _default = exports.default = {
  299. methods: {
  300. // 处理 Tab 键移动
  301. moveTabSelected(args, isLeft, evnt) {
  302. const $xeTable = this;
  303. const props = $xeTable;
  304. const internalData = $xeTable;
  305. const {
  306. editConfig
  307. } = props;
  308. const {
  309. afterFullData,
  310. visibleColumn
  311. } = internalData;
  312. const editOpts = $xeTable.computeEditOpts;
  313. const rowOpts = $xeTable.computeRowOpts;
  314. const currentRowOpts = $xeTable.computeCurrentRowOpts;
  315. const columnOpts = $xeTable.computeColumnOpts;
  316. const currentColumnOpts = $xeTable.computeCurrentColumnOpts;
  317. let targetRow;
  318. let targetRowIndex;
  319. let targetColumnIndex;
  320. const params = Object.assign({}, args);
  321. const _rowIndex = $xeTable.getVTRowIndex(params.row);
  322. const _columnIndex = $xeTable.getVTColumnIndex(params.column);
  323. evnt.preventDefault();
  324. if (isLeft) {
  325. // 向左
  326. if (_columnIndex <= 0) {
  327. // 如果已经是第一列,则移动到上一行
  328. if (_rowIndex > 0) {
  329. targetRowIndex = _rowIndex - 1;
  330. targetRow = afterFullData[targetRowIndex];
  331. targetColumnIndex = visibleColumn.length - 1;
  332. }
  333. } else {
  334. targetColumnIndex = _columnIndex - 1;
  335. }
  336. } else {
  337. if (_columnIndex >= visibleColumn.length - 1) {
  338. // 如果已经是第一列,则移动到上一行
  339. if (_rowIndex < afterFullData.length - 1) {
  340. targetRowIndex = _rowIndex + 1;
  341. targetRow = afterFullData[targetRowIndex];
  342. targetColumnIndex = 0;
  343. }
  344. } else {
  345. targetColumnIndex = _columnIndex + 1;
  346. }
  347. }
  348. const targetColumn = visibleColumn[targetColumnIndex];
  349. if (targetColumn) {
  350. if (targetRow) {
  351. params.rowIndex = targetRowIndex;
  352. params.row = targetRow;
  353. } else {
  354. params.rowIndex = _rowIndex;
  355. }
  356. params.columnIndex = targetColumnIndex;
  357. params.column = targetColumn;
  358. params.cell = $xeTable.getCellElement(params.row, params.column);
  359. if (rowOpts.isCurrent && currentRowOpts.isFollowSelected) {
  360. $xeTable.triggerCurrentRowEvent(evnt, params);
  361. }
  362. if (columnOpts.isCurrent && currentColumnOpts.isFollowSelected) {
  363. $xeTable.triggerCurrentColumnEvent(evnt, params);
  364. }
  365. if (editConfig) {
  366. if (editOpts.trigger === 'click' || editOpts.trigger === 'dblclick') {
  367. if (editOpts.mode === 'row') {
  368. $xeTable.handleEdit(params, evnt);
  369. } else {
  370. $xeTable.scrollToRow(params.row, params.column).then(() => {
  371. $xeTable.handleSelected(params, evnt);
  372. });
  373. }
  374. }
  375. } else {
  376. $xeTable.scrollToRow(params.row, params.column).then(() => {
  377. $xeTable.handleSelected(params, evnt);
  378. });
  379. }
  380. }
  381. },
  382. // 处理当前行方向键移动
  383. moveCurrentRow(isUpArrow, isDwArrow, evnt) {
  384. const $xeTable = this;
  385. const props = $xeTable;
  386. const reactData = $xeTable;
  387. const internalData = $xeTable;
  388. const {
  389. treeConfig
  390. } = props;
  391. const {
  392. currentRow
  393. } = reactData;
  394. const {
  395. afterFullData
  396. } = internalData;
  397. const treeOpts = $xeTable.computeTreeOpts;
  398. const childrenField = treeOpts.children || treeOpts.childrenField;
  399. let targetRow;
  400. if (currentRow) {
  401. if (treeConfig) {
  402. const {
  403. index,
  404. items
  405. } = _xeUtils.default.findTree(afterFullData, item => item === currentRow, {
  406. children: childrenField
  407. });
  408. if (isUpArrow && index > 0) {
  409. targetRow = items[index - 1];
  410. } else if (isDwArrow && index < items.length - 1) {
  411. targetRow = items[index + 1];
  412. }
  413. } else {
  414. const _rowIndex = $xeTable.getVTRowIndex(currentRow);
  415. if (isUpArrow && _rowIndex > 0) {
  416. targetRow = afterFullData[_rowIndex - 1];
  417. } else if (isDwArrow && _rowIndex < afterFullData.length - 1) {
  418. targetRow = afterFullData[_rowIndex + 1];
  419. }
  420. }
  421. } else {
  422. targetRow = afterFullData[0];
  423. }
  424. if (targetRow) {
  425. evnt.preventDefault();
  426. const params = {
  427. $table: $xeTable,
  428. row: targetRow,
  429. rowIndex: $xeTable.getRowIndex(targetRow),
  430. $rowIndex: $xeTable.getVMRowIndex(targetRow)
  431. };
  432. $xeTable.scrollToRow(targetRow).then(() => $xeTable.triggerCurrentRowEvent(evnt, params));
  433. }
  434. },
  435. // 处理当前列方向键移动
  436. moveCurrentColumn(isLeftArrow, isRightArrow, evnt) {
  437. const $xeTable = this;
  438. const reactData = $xeTable;
  439. const internalData = $xeTable;
  440. const {
  441. currentColumn
  442. } = reactData;
  443. const {
  444. visibleColumn
  445. } = internalData;
  446. let targetCol = null;
  447. if (currentColumn) {
  448. const _columnIndex = $xeTable.getVTColumnIndex(currentColumn);
  449. if (isLeftArrow && _columnIndex > 0) {
  450. targetCol = visibleColumn[_columnIndex - 1];
  451. } else if (isRightArrow && _columnIndex < visibleColumn.length - 1) {
  452. targetCol = visibleColumn[_columnIndex + 1];
  453. }
  454. } else {
  455. targetCol = visibleColumn[0];
  456. }
  457. if (targetCol) {
  458. evnt.preventDefault();
  459. const params = {
  460. $table: $xeTable,
  461. column: targetCol,
  462. columnIndex: $xeTable.getColumnIndex(targetCol),
  463. $columnIndex: $xeTable.getVMColumnIndex(targetCol)
  464. };
  465. $xeTable.scrollToColumn(targetCol).then(() => $xeTable.triggerCurrentColumnEvent(evnt, params));
  466. }
  467. },
  468. // 处理可编辑方向键移动
  469. moveArrowSelected(args, isLeftArrow, isUpArrow, isRightArrow, isDwArrow, evnt) {
  470. const $xeTable = this;
  471. const props = $xeTable;
  472. const {
  473. highlightCurrentRow,
  474. highlightCurrentColumn
  475. } = props;
  476. const rowOpts = $xeTable.computeRowOpts;
  477. const currentRowOpts = $xeTable.computeCurrentRowOpts;
  478. const columnOpts = $xeTable.computeColumnOpts;
  479. const currentColumnOpts = $xeTable.computeCurrentColumnOpts;
  480. const params = handleMoveSelected($xeTable, evnt, args, isLeftArrow, isUpArrow, isRightArrow, isDwArrow);
  481. if (rowOpts.isCurrent || highlightCurrentRow) {
  482. if (currentRowOpts.isFollowSelected) {
  483. $xeTable.triggerCurrentRowEvent(evnt, params);
  484. } else {
  485. // 当前行按键上下移动
  486. if ((isUpArrow || isDwArrow) && (rowOpts.isCurrent || highlightCurrentRow)) {
  487. $xeTable.moveCurrentRow(isUpArrow, isDwArrow, evnt);
  488. }
  489. }
  490. }
  491. if (columnOpts.isCurrent || highlightCurrentColumn) {
  492. if (currentColumnOpts.isFollowSelected) {
  493. $xeTable.triggerCurrentColumnEvent(evnt, params);
  494. } else {
  495. // 当前行按键左右移动
  496. if ((isLeftArrow || isRightArrow) && (columnOpts.isCurrent || highlightCurrentColumn)) {
  497. $xeTable.moveCurrentColumn(isLeftArrow, isRightArrow, evnt);
  498. }
  499. }
  500. }
  501. },
  502. moveEnterSelected(args, isLeftArrow, isUpArrow, isRightArrow, isDwArrow, evnt) {
  503. const $xeTable = this;
  504. const props = $xeTable;
  505. const {
  506. highlightCurrentRow,
  507. highlightCurrentColumn
  508. } = props;
  509. const rowOpts = $xeTable.computeRowOpts;
  510. const currentRowOpts = $xeTable.computeCurrentRowOpts;
  511. const columnOpts = $xeTable.computeColumnOpts;
  512. const currentColumnOpts = $xeTable.computeCurrentColumnOpts;
  513. const params = handleMoveSelected($xeTable, evnt, args, isLeftArrow, isUpArrow, isRightArrow, isDwArrow);
  514. if ((rowOpts.isCurrent || highlightCurrentRow) && currentRowOpts.isFollowSelected) {
  515. $xeTable.triggerCurrentRowEvent(evnt, params);
  516. }
  517. if ((columnOpts.isCurrent || highlightCurrentColumn) && currentColumnOpts.isFollowSelected) {
  518. $xeTable.triggerCurrentColumnEvent(evnt, params);
  519. }
  520. },
  521. // 处理可编辑方向键移动
  522. moveSelected(args, isLeftArrow, isUpArrow, isRightArrow, isDwArrow, evnt) {
  523. const $xeTable = this;
  524. handleMoveSelected($xeTable, evnt, args, isLeftArrow, isUpArrow, isRightArrow, isDwArrow);
  525. },
  526. handleCellMousedownEvent(evnt, params) {
  527. const $xeTable = this;
  528. const props = $xeTable;
  529. const {
  530. editConfig,
  531. checkboxConfig,
  532. mouseConfig
  533. } = props;
  534. const checkboxOpts = $xeTable.computeCheckboxOpts;
  535. const mouseOpts = $xeTable.computeMouseOpts;
  536. const editOpts = $xeTable.computeEditOpts;
  537. if (mouseConfig && mouseOpts.area && $xeTable.triggerCellAreaModnEvent) {
  538. return $xeTable.triggerCellAreaModnEvent(evnt, params);
  539. } else {
  540. if (checkboxConfig && checkboxOpts.range) {
  541. handleCheckboxRangeEvent($xeTable, evnt, params);
  542. }
  543. if (mouseConfig && mouseOpts.selected) {
  544. if (!editConfig || editOpts.mode === 'cell') {
  545. $xeTable.handleSelected(params, evnt);
  546. }
  547. }
  548. }
  549. }
  550. }
  551. };