stk-table-vue 1.0.1 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -24,6 +24,8 @@ Support Vue3 and Vue2.7
24
24
  ## Documentation
25
25
  ### [Stk Table Vue Official](https://ja-plus.github.io/stk-table-vue/)
26
26
  ### [Stk Table React Official](https://ja-plus.github.io/stk-table-react/)
27
+ ### [Stk Table Svelte Official](https://ja-plus.github.io/stk-table-svelte/)
28
+ ### [Stk Table Solid Official](https://ja-plus.github.io/stk-table-solid/)
27
29
 
28
30
 
29
31
  ## Repo:
@@ -1,12 +1,12 @@
1
1
  /**
2
2
  * name: stk-table-vue
3
- * version: v1.0.0
3
+ * version: v1.0.2
4
4
  * description: High performance realtime virtual table for vue3 and vue2.7
5
5
  * author: japlus
6
6
  * homepage: https://ja-plus.github.io/stk-table-vue/
7
7
  * license: MIT
8
8
  */
9
- import { t as StkTable_default } from "./StkTable-BK4VNsvG.js";
9
+ import { t as StkTable_default } from "./StkTable-CoLDxW4i.js";
10
10
  import { createElementBlock, createElementVNode, createVNode, defineComponent, h, nextTick, normalizeClass, normalizeStyle, onMounted, onUnmounted, openBlock, reactive, ref, withModifiers } from "vue";
11
11
  //#region src/StkTable/custom-cells/FilterCell/Dropdown/index.vue?vue&type=script&setup=true&lang.ts
12
12
  var DROPDOWN_DEFAULT_WIDTH = 300;
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * name: stk-table-vue
3
- * version: v1.0.0
3
+ * version: v1.0.2
4
4
  * description: High performance realtime virtual table for vue3 and vue2.7
5
5
  * author: japlus
6
6
  * homepage: https://ja-plus.github.io/stk-table-vue/
@@ -1312,11 +1312,11 @@ var TagType = {
1312
1312
  /**
1313
1313
  * 窗口变化自动重置虚拟滚动
1314
1314
  * @param tableContainerRef
1315
- * @param initVirtualScroll
1315
+ * @param onResize 容器尺寸变化后的重算逻辑(虚拟滚动、固定列等)
1316
1316
  * @param props
1317
1317
  * @param debounceMs
1318
1318
  */
1319
- function useAutoResize(tableContainerRef, initVirtualScroll, props, debounceMs) {
1319
+ function useAutoResize(tableContainerRef, onResize, props, debounceMs) {
1320
1320
  let resizeObserver = null;
1321
1321
  let isObserved = false;
1322
1322
  watch(() => props.virtual, (v) => {
@@ -1361,7 +1361,7 @@ function useAutoResize(tableContainerRef, initVirtualScroll, props, debounceMs)
1361
1361
  if (debounceTime) window.clearTimeout(debounceTime);
1362
1362
  debounceTime = window.setTimeout(() => {
1363
1363
  if (props.autoResize) {
1364
- initVirtualScroll();
1364
+ onResize();
1365
1365
  if (typeof props.autoResize === "function") props.autoResize();
1366
1366
  }
1367
1367
  debounceTime = 0;
@@ -1519,11 +1519,17 @@ function useFixedCol(props, colKeyGen, getFixedColPosition, tableHeaders, tableH
1519
1519
  const fixedShadowCols = shallowRef([]);
1520
1520
  /** 正在被固定的列 */
1521
1521
  const fixedCols = shallowRef([]);
1522
+ /**
1523
+ * 需要自行绘制左边框的右固定列。
1524
+ * 单元格的左边框由左侧相邻单元格的 border-right 提供,右固定列吸附遮挡内容后两者不再相邻,因此需要自行绘制。
1525
+ */
1526
+ const fixedBorderLeftCols = shallowRef([]);
1522
1527
  /** 固定列的class */
1523
1528
  const fixedColClassMap = computed(() => {
1524
1529
  const colMap = /* @__PURE__ */ new Map();
1525
1530
  const fixedShadowColsValue = fixedShadowCols.value;
1526
1531
  const fixedColsValue = fixedCols.value;
1532
+ const fixedBorderLeftColsValue = fixedBorderLeftCols.value;
1527
1533
  const colKeyFn = colKeyGen.value;
1528
1534
  const fixedColShadow = props.fixedColShadow;
1529
1535
  const headers = tableHeaders.value;
@@ -1540,6 +1546,7 @@ function useFixedCol(props, colKeyGen, getFixedColPosition, tableHeaders, tableH
1540
1546
  classList.push("fixed-cell--" + fixed);
1541
1547
  }
1542
1548
  if (showShadow) classList.push("fixed-cell--shadow");
1549
+ if (fixed === "right" && fixedBorderLeftColsValue.includes(col)) classList.push("fixed-cell--border-left");
1543
1550
  colMap.set(colKeyFn(col), classList);
1544
1551
  }
1545
1552
  }
@@ -1576,6 +1583,13 @@ function useFixedCol(props, colKeyGen, getFixedColPosition, tableHeaders, tableH
1576
1583
  for (let level = 0; level < len; level++) {
1577
1584
  const row = tableHeadersForCalc.value[level];
1578
1585
  /**
1586
+ * 最右侧连续 fixed:right 列的起始下标。
1587
+ * 这些列的固定偏移只由其右侧固定列宽度决定,不依赖中间列的声明宽度,
1588
+ * 且 sticky/relative 在无横向溢出时偏移为0无副作用,因此无需判断滚动位置,始终固定。
1589
+ */
1590
+ let rightSuffixStart = row.length;
1591
+ while (rightSuffixStart > 0 && row[rightSuffixStart - 1].fixed === "right") rightSuffixStart--;
1592
+ /**
1579
1593
  * 左侧第n个fixed:left 计算要加上前面所有left 的列宽。
1580
1594
  */
1581
1595
  let left = 0;
@@ -1589,13 +1603,16 @@ function useFixedCol(props, colKeyGen, getFixedColPosition, tableHeaders, tableH
1589
1603
  leftShadowCol[level] = col;
1590
1604
  }
1591
1605
  left += getCalculatedColWidth(col);
1592
- if (isFixedRight && scrollLeft + clientWidth - left < position) {
1593
- fixedColsTemp.push(col);
1594
- if (!rightShadowCol[level]) rightShadowCol[level] = col;
1606
+ if (isFixedRight) {
1607
+ /** 是否需要固定。依赖列声明宽度累加,声明宽度与实际渲染宽度不一致时会失真 */
1608
+ const needFix = scrollLeft + clientWidth - left < position;
1609
+ if (i >= rightSuffixStart || needFix) fixedColsTemp.push(col);
1610
+ if (needFix && !rightShadowCol[level]) rightShadowCol[level] = col;
1595
1611
  }
1596
1612
  }
1597
1613
  }
1598
1614
  if (props.fixedColShadow) fixedShadowCols.value = leftShadowCol.concat(rightShadowCol).filter(Boolean);
1615
+ fixedBorderLeftCols.value = rightShadowCol.filter(Boolean);
1599
1616
  fixedCols.value = fixedColsTemp;
1600
1617
  }
1601
1618
  return [
@@ -3558,33 +3575,34 @@ function useWheeling(resetDelay = 500) {
3558
3575
  var _hoisted_1 = ["tabindex"];
3559
3576
  var _hoisted_2 = { class: "stk-table-scroll-container" };
3560
3577
  var _hoisted_3 = { key: 0 };
3561
- var _hoisted_4 = ["onClick"];
3562
- var _hoisted_5 = ["onMousedown"];
3563
- var _hoisted_6 = { class: "table-header-title" };
3564
- var _hoisted_7 = ["onMousedown"];
3565
- var _hoisted_8 = ["colspan"];
3566
- var _hoisted_9 = ["title"];
3567
- var _hoisted_10 = { key: 0 };
3568
- var _hoisted_11 = ["colspan"];
3578
+ var _hoisted_4 = { key: 1 };
3579
+ var _hoisted_5 = ["onClick"];
3580
+ var _hoisted_6 = ["onMousedown"];
3581
+ var _hoisted_7 = { class: "table-header-title" };
3582
+ var _hoisted_8 = ["onMousedown"];
3583
+ var _hoisted_9 = ["colspan"];
3584
+ var _hoisted_10 = ["title"];
3585
+ var _hoisted_11 = { key: 0 };
3569
3586
  var _hoisted_12 = ["colspan"];
3570
- var _hoisted_13 = {
3587
+ var _hoisted_13 = ["colspan"];
3588
+ var _hoisted_14 = {
3571
3589
  class: "table-cell-wrapper",
3572
3590
  tabindex: "-1"
3573
3591
  };
3574
- var _hoisted_14 = {
3592
+ var _hoisted_15 = {
3575
3593
  key: 0,
3576
3594
  class: "vt-x-left"
3577
3595
  };
3578
- var _hoisted_15 = ["colspan"];
3579
- var _hoisted_16 = ["title"];
3580
- var _hoisted_17 = {
3596
+ var _hoisted_16 = ["colspan"];
3597
+ var _hoisted_17 = ["title"];
3598
+ var _hoisted_18 = {
3581
3599
  key: 2,
3582
3600
  class: "table-cell-wrapper",
3583
3601
  tabindex: "-1"
3584
3602
  };
3585
- var _hoisted_18 = ["title"];
3586
- var _hoisted_19 = { key: 2 };
3587
- var _hoisted_20 = {
3603
+ var _hoisted_19 = ["title"];
3604
+ var _hoisted_20 = { key: 2 };
3605
+ var _hoisted_21 = {
3588
3606
  key: 1,
3589
3607
  class: "vt-x-right"
3590
3608
  };
@@ -3897,7 +3915,6 @@ var StkTable_default = /* @__PURE__ */ defineComponent({
3897
3915
  const getFixedColPosition = useGetFixedColPosition(tableHeadersForCalc, colKeyGen);
3898
3916
  const getFixedStyle = useFixedStyle(props, isRelativeMode, getFixedColPosition, virtualScroll, virtualScrollX, virtualX_on, virtualX_offsetRight);
3899
3917
  const [highlightSteps, setHighlightDimRow, setHighlightDimCell] = useHighlight(props, stkTableId, tableContainerRef);
3900
- if (props.autoResize) useAutoResize(tableContainerRef, initVirtualScroll, props, 200);
3901
3918
  function getRowIndex(row) {
3902
3919
  const targetKey = rowKeyGen(row);
3903
3920
  return dataSourceCopy.value.findIndex((item) => rowKeyGen(item) === targetKey);
@@ -3911,6 +3928,10 @@ var StkTable_default = /* @__PURE__ */ defineComponent({
3911
3928
  useKeyboardArrowScroll(tableContainerRef, props, scrollTo, virtualScroll, virtualScrollX, tableHeaders, virtual_on, areaSelectionConfig);
3912
3929
  /** 固定列处理 */
3913
3930
  const [fixedCols, fixedColClassMap, updateFixedShadow] = useFixedCol(props, colKeyGen, getFixedColPosition, tableHeaders, tableHeadersForCalc, tableContainerRef);
3931
+ if (props.autoResize) useAutoResize(tableContainerRef, () => {
3932
+ initVirtualScroll();
3933
+ updateFixedShadow();
3934
+ }, props, 200);
3914
3935
  const [colResizeOn, isColResizing, onThResizeMouseDown] = useColResize(props, emits, tableContainerRef, tableHeaderLast, colResizeIndicatorRef, colKeyGen, fixedCols, clearColWidthCache);
3915
3936
  const [toggleExpandRow, setRowExpand] = useRowExpand(emits, dataSourceCopy, rowKeyGen, onDataSourceChange);
3916
3937
  const [toggleTreeNode, setTreeExpand, flatTreeData] = useTree(props, dataSourceCopy, rowKeyGen, emits, onDataSourceChange);
@@ -4055,6 +4076,15 @@ var StkTable_default = /* @__PURE__ */ defineComponent({
4055
4076
  [TagType.TF]: tfMap
4056
4077
  };
4057
4078
  });
4079
+ /**
4080
+ * fixed 模式下 colgroup 中单个 col 的样式。
4081
+ * 仅取叶子列的 width(与 cellStyleMap 中 --cw 保持一致);未设置 width 的列不声明宽度,
4082
+ * 由 table-layout:fixed 将剩余空间平分,符合“一列固定、其余列平分”的预期。
4083
+ */
4084
+ function getColGroupColStyle(col) {
4085
+ const width = transformWidthToStr(col.width);
4086
+ return width ? `width:${width}` : null;
4087
+ }
4058
4088
  function getAbsoluteRowIndex(rowIndex) {
4059
4089
  return rowIndex + virtualScroll.value.startIndex;
4060
4090
  }
@@ -4672,7 +4702,13 @@ var StkTable_default = /* @__PURE__ */ defineComponent({
4672
4702
  onContextmenu: onRowMenu,
4673
4703
  onMouseover: onTrMouseOver
4674
4704
  }, [
4675
- !__props.headless ? (openBlock(), createElementBlock("thead", _hoisted_3, [(openBlock(true), createElementBlock(Fragment, null, renderList(unref(virtualX_on) ? unref(virtualX_tableHeaders) : unref(tableHeaders), (row, rowIndex) => {
4705
+ props.fixedMode && !unref(virtualX_on) ? (openBlock(), createElementBlock("colgroup", _hoisted_3, [(openBlock(true), createElementBlock(Fragment, null, renderList(tableHeaderLast.value, (col) => {
4706
+ return openBlock(), createElementBlock("col", {
4707
+ key: colKeyGen.value(col),
4708
+ style: normalizeStyle(getColGroupColStyle(col))
4709
+ }, null, 4);
4710
+ }), 128))])) : createCommentVNode("", true),
4711
+ !__props.headless ? (openBlock(), createElementBlock("thead", _hoisted_4, [(openBlock(true), createElementBlock(Fragment, null, renderList(unref(virtualX_on) ? unref(virtualX_tableHeaders) : unref(tableHeaders), (row, rowIndex) => {
4676
4712
  return openBlock(), createElementBlock("tr", {
4677
4713
  key: rowIndex,
4678
4714
  onContextmenu: _cache[3] || (_cache[3] = ($event) => onHeaderMenu($event))
@@ -4693,7 +4729,7 @@ var StkTable_default = /* @__PURE__ */ defineComponent({
4693
4729
  key: 0,
4694
4730
  class: "table-header-resizer left",
4695
4731
  onMousedown: ($event) => unref(onThResizeMouseDown)($event, col, true)
4696
- }, null, 40, _hoisted_5)) : createCommentVNode("", true),
4732
+ }, null, 40, _hoisted_6)) : createCommentVNode("", true),
4697
4733
  createElementVNode("div", {
4698
4734
  class: "table-header-cell-wrapper",
4699
4735
  style: normalizeStyle(col.__R_SP__ ? `--row-span:${col.__R_SP__}` : null)
@@ -4709,7 +4745,7 @@ var StkTable_default = /* @__PURE__ */ defineComponent({
4709
4745
  ])) : renderSlot(_ctx.$slots, "tableHeader", {
4710
4746
  key: 1,
4711
4747
  col
4712
- }, () => [createElementVNode("span", _hoisted_6, toDisplayString(col.title), 1)]), col.sorter ? (openBlock(), createBlock(SortIcon_default, {
4748
+ }, () => [createElementVNode("span", _hoisted_7, toDisplayString(col.title), 1)]), col.sorter ? (openBlock(), createBlock(SortIcon_default, {
4713
4749
  key: 2,
4714
4750
  class: "table-header-sorter"
4715
4751
  })) : createCommentVNode("", true)], 4),
@@ -4717,8 +4753,8 @@ var StkTable_default = /* @__PURE__ */ defineComponent({
4717
4753
  key: 1,
4718
4754
  class: "table-header-resizer right",
4719
4755
  onMousedown: ($event) => unref(onThResizeMouseDown)($event, col)
4720
- }, null, 40, _hoisted_7)) : createCommentVNode("", true)
4721
- ], 16, _hoisted_4);
4756
+ }, null, 40, _hoisted_8)) : createCommentVNode("", true)
4757
+ ], 16, _hoisted_5);
4722
4758
  }), 128)),
4723
4759
  unref(virtualX_on) ? (openBlock(), createElementBlock("th", {
4724
4760
  key: 1,
@@ -4728,7 +4764,7 @@ var StkTable_default = /* @__PURE__ */ defineComponent({
4728
4764
  ], 32);
4729
4765
  }), 128))])) : createCommentVNode("", true),
4730
4766
  __props.footerData && __props.footerData.length > 0 ? (openBlock(), createBlock(resolveDynamicComponent(footerTagName.value), {
4731
- key: 1,
4767
+ key: 2,
4732
4768
  class: "stk-footer",
4733
4769
  style: normalizeStyle(isFooterTop.value ? `top:${unref(tableHeaderHeight)}px` : "")
4734
4770
  }, {
@@ -4744,7 +4780,7 @@ var StkTable_default = /* @__PURE__ */ defineComponent({
4744
4780
  key: 0,
4745
4781
  class: "vt-x-spacer",
4746
4782
  colspan: col.__VT_C_SP__
4747
- }, null, 8, _hoisted_8)) : (openBlock(), createElementBlock("td", mergeProps({
4783
+ }, null, 8, _hoisted_9)) : (openBlock(), createElementBlock("td", mergeProps({
4748
4784
  key: 1,
4749
4785
  ref_for: true
4750
4786
  }, getTFProps(col)), [col.customFooterCell ? (openBlock(), createBlock(resolveDynamicComponent(col.customFooterCell), {
@@ -4764,7 +4800,7 @@ var StkTable_default = /* @__PURE__ */ defineComponent({
4764
4800
  class: "table-cell-wrapper",
4765
4801
  tabindex: "-1",
4766
4802
  title: footRow[col.dataIndex] || ""
4767
- }, [footRow[col.dataIndex] != null ? (openBlock(), createElementBlock("span", _hoisted_10, toDisplayString(footRow[col.dataIndex]), 1)) : createCommentVNode("", true)], 8, _hoisted_9)], 16))], 64);
4803
+ }, [footRow[col.dataIndex] != null ? (openBlock(), createElementBlock("span", _hoisted_11, toDisplayString(footRow[col.dataIndex]), 1)) : createCommentVNode("", true)], 8, _hoisted_10)], 16))], 64);
4768
4804
  }), 128)),
4769
4805
  unref(virtualX_on) ? (openBlock(), createElementBlock("td", {
4770
4806
  key: 1,
@@ -4799,7 +4835,7 @@ var StkTable_default = /* @__PURE__ */ defineComponent({
4799
4835
  key: 0,
4800
4836
  class: "vt-x-spacer",
4801
4837
  colspan: col.__VT_C_SP__
4802
- }, null, 8, _hoisted_11)) : (openBlock(), createElementBlock("td", {
4838
+ }, null, 8, _hoisted_12)) : (openBlock(), createElementBlock("td", {
4803
4839
  key: 1,
4804
4840
  style: normalizeStyle(cellStyleMap.value[unref(TagType).TD].get(colKeyGen.value(col)))
4805
4841
  }, null, 4))], 64);
@@ -4819,17 +4855,17 @@ var StkTable_default = /* @__PURE__ */ defineComponent({
4819
4855
  }, { ref_for: true }, getTRProps(row, rowIndex)), [row && row.__EXP_R__ ? (openBlock(), createElementBlock("td", {
4820
4856
  key: 0,
4821
4857
  colspan: unref(expandRowColspan)
4822
- }, [createElementVNode("div", _hoisted_13, [renderSlot(_ctx.$slots, "expand", {
4858
+ }, [createElementVNode("div", _hoisted_14, [renderSlot(_ctx.$slots, "expand", {
4823
4859
  row: row.__EXP_R__,
4824
4860
  col: row.__EXP_C__
4825
- }, () => [createTextVNode(toDisplayString(row.__EXP_R__ && row.__EXP_C__ && row.__EXP_R__[row.__EXP_C__.dataIndex] || ""), 1)])])], 8, _hoisted_12)) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [
4826
- unref(virtualX_on) ? (openBlock(), createElementBlock("td", _hoisted_14)) : createCommentVNode("", true),
4861
+ }, () => [createTextVNode(toDisplayString(row.__EXP_R__ && row.__EXP_C__ && row.__EXP_R__[row.__EXP_C__.dataIndex] || ""), 1)])])], 8, _hoisted_13)) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [
4862
+ unref(virtualX_on) ? (openBlock(), createElementBlock("td", _hoisted_15)) : createCommentVNode("", true),
4827
4863
  (openBlock(true), createElementBlock(Fragment, null, renderList(unref(virtualX_columnPart), (col, _colIdx) => {
4828
4864
  return openBlock(), createElementBlock(Fragment, { key: col.__VT_C_SP__ ? `spacer-${_colIdx}` : colKeyGen.value(col) }, [col.__VT_C_SP__ ? (openBlock(), createElementBlock("td", {
4829
4865
  key: 0,
4830
4866
  class: "vt-x-spacer",
4831
4867
  colspan: col.__VT_C_SP__
4832
- }, null, 8, _hoisted_15)) : !shouldHideCell(row, col) ? (openBlock(), createElementBlock("td", mergeProps({
4868
+ }, null, 8, _hoisted_16)) : !shouldHideCell(row, col) ? (openBlock(), createElementBlock("td", mergeProps({
4833
4869
  key: 1,
4834
4870
  ref_for: true
4835
4871
  }, getTDProps(row, col, rowIndex, col.__LF_S__ ?? 0)), [col.customCell ? (openBlock(), createBlock(resolveDynamicComponent(col.customCell), {
@@ -4860,7 +4896,7 @@ var StkTable_default = /* @__PURE__ */ defineComponent({
4860
4896
  class: "table-cell-wrapper",
4861
4897
  tabindex: "-1",
4862
4898
  title: row[col.dataIndex] || ""
4863
- }, toDisplayString((row && row[col.dataIndex]) != null ? row && row[col.dataIndex] : getEmptyCellText.value(col, row)), 9, _hoisted_16)) : col.type === "seq" ? (openBlock(), createElementBlock("div", _hoisted_17, toDisplayString((props.seqConfig.startIndex || 0) + getAbsoluteRowIndex(rowIndex) + 1), 1)) : col.type === "tree-node" ? (openBlock(), createBlock(TreeNodeCell_default, {
4899
+ }, toDisplayString((row && row[col.dataIndex]) != null ? row && row[col.dataIndex] : getEmptyCellText.value(col, row)), 9, _hoisted_17)) : col.type === "seq" ? (openBlock(), createElementBlock("div", _hoisted_18, toDisplayString((props.seqConfig.startIndex || 0) + getAbsoluteRowIndex(rowIndex) + 1), 1)) : col.type === "tree-node" ? (openBlock(), createBlock(TreeNodeCell_default, {
4864
4900
  key: 3,
4865
4901
  class: "table-cell-wrapper",
4866
4902
  tabindex: "-1",
@@ -4874,9 +4910,9 @@ var StkTable_default = /* @__PURE__ */ defineComponent({
4874
4910
  }, [col.type === "dragRow" ? (openBlock(), createBlock(DragHandle_default, {
4875
4911
  key: 0,
4876
4912
  onDragstart: ($event) => unref(onTrDragStart)($event, getAbsoluteRowIndex(rowIndex))
4877
- }, null, 8, ["onDragstart"])) : col.type === "expand" ? (openBlock(), createBlock(TriangleIcon_default, { key: 1 })) : createCommentVNode("", true), row[col.dataIndex] != null ? (openBlock(), createElementBlock("span", _hoisted_19, toDisplayString(row[col.dataIndex]), 1)) : createCommentVNode("", true)], 8, _hoisted_18))], 16)) : createCommentVNode("", true)], 64);
4913
+ }, null, 8, ["onDragstart"])) : col.type === "expand" ? (openBlock(), createBlock(TriangleIcon_default, { key: 1 })) : createCommentVNode("", true), row[col.dataIndex] != null ? (openBlock(), createElementBlock("span", _hoisted_20, toDisplayString(row[col.dataIndex]), 1)) : createCommentVNode("", true)], 8, _hoisted_19))], 16)) : createCommentVNode("", true)], 64);
4878
4914
  }), 128)),
4879
- unref(virtualX_on) ? (openBlock(), createElementBlock("td", _hoisted_20)) : createCommentVNode("", true)
4915
+ unref(virtualX_on) ? (openBlock(), createElementBlock("td", _hoisted_21)) : createCommentVNode("", true)
4880
4916
  ], 64))], 16);
4881
4917
  }), 128)),
4882
4918
  !isExperimentalScrollY.value ? (openBlock(), createElementBlock(Fragment, { key: 1 }, [unref(virtual_on) && !unref(isSRBRActive) ? (openBlock(), createElementBlock("tr", {
@@ -3,8 +3,8 @@ import { Ref } from 'vue';
3
3
  /**
4
4
  * 窗口变化自动重置虚拟滚动
5
5
  * @param tableContainerRef
6
- * @param initVirtualScroll
6
+ * @param onResize 容器尺寸变化后的重算逻辑(虚拟滚动、固定列等)
7
7
  * @param props
8
8
  * @param debounceMs
9
9
  */
10
- export declare function useAutoResize(tableContainerRef: Ref<HTMLElement | undefined>, initVirtualScroll: () => void, props: any, debounceMs: number): void;
10
+ export declare function useAutoResize(tableContainerRef: Ref<HTMLElement | undefined>, onResize: () => void, props: any, debounceMs: number): void;
@@ -1,12 +1,12 @@
1
1
  /**
2
2
  * name: stk-table-vue
3
- * version: v1.0.0
3
+ * version: v1.0.2
4
4
  * description: High performance realtime virtual table for vue3 and vue2.7
5
5
  * author: japlus
6
6
  * homepage: https://ja-plus.github.io/stk-table-vue/
7
7
  * license: MIT
8
8
  */
9
- import { a as insertToOrderedArray, i as binarySearch, n as registerFeature, o as strCompare, r as useAreaSelection, s as tableSort, t as StkTable_default } from "./StkTable-BK4VNsvG.js";
9
+ import { a as insertToOrderedArray, i as binarySearch, n as registerFeature, o as strCompare, r as useAreaSelection, s as tableSort, t as StkTable_default } from "./StkTable-CoLDxW4i.js";
10
10
  import { Fragment, computed, createApp, createBlock, createElementBlock, createElementVNode, createTextVNode, defineComponent, getCurrentInstance, h, markRaw, nextTick, normalizeClass, openBlock, ref, renderSlot, resolveDynamicComponent, toDisplayString, watch, withModifiers } from "vue";
11
11
  //#region src/StkTable/custom-cells/FilterCell/Dropdown/index.ts
12
12
  var DropdownIns = null;
@@ -15,7 +15,7 @@ async function getDropdownIns() {
15
15
  const div = document.createElement("div");
16
16
  div.classList.add("stk-filter-dropdown-wrapper");
17
17
  document.body.appendChild(div);
18
- DropdownIns = createApp(await import("./Dropdown-wEI6qpCx.js").then((module) => module.default)).mount(div);
18
+ DropdownIns = createApp(await import("./Dropdown-gzfyZN4Y.js").then((module) => module.default)).mount(div);
19
19
  }
20
20
  return DropdownIns;
21
21
  }
package/lib/style.css CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * name: stk-table-vue
3
- * version: v1.0.0
3
+ * version: v1.0.2
4
4
  * description: High performance realtime virtual table for vue3 and vue2.7
5
5
  * author: japlus
6
6
  * homepage: https://ja-plus.github.io/stk-table-vue/
@@ -291,6 +291,13 @@
291
291
  .stk-table.bordered thead tr:first-child th{
292
292
  background-image:var(--bg-border-top), var(--bg-border-right), var(--bg-border-bottom);
293
293
  }
294
+ .stk-table.bordered th.fixed-cell--border-left,
295
+ .stk-table.bordered td.fixed-cell--border-left{
296
+ background-image:var(--bg-border-left), var(--bg-border-right), var(--bg-border-bottom);
297
+ }
298
+ .stk-table.bordered thead tr:first-child th.fixed-cell--border-left{
299
+ background-image:var(--bg-border-left), var(--bg-border-top), var(--bg-border-right), var(--bg-border-bottom);
300
+ }
294
301
  .stk-table.bordered-h{
295
302
  border-left:none;
296
303
  --bg-border-right:linear-gradient(transparent, transparent);
@@ -305,6 +312,7 @@
305
312
  }
306
313
  .stk-table.bordered-body-h tbody{
307
314
  --bg-border-right:linear-gradient(transparent, transparent);
315
+ --bg-border-left:linear-gradient(transparent, transparent);
308
316
  }
309
317
  .stk-table.stripe:not(.vt-on) .stk-tbody-main tr:nth-child(even){
310
318
  background-color:var(--stripe-bgc);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stk-table-vue",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "High performance realtime virtual table for vue3 and vue2.7",
5
5
  "main": "./lib/stk-table-vue.js",
6
6
  "types": "./lib/src/StkTable/index.d.ts",
@@ -61,6 +61,11 @@
61
61
  @contextmenu="onRowMenu"
62
62
  @mouseover="onTrMouseOver"
63
63
  >
64
+ <!-- table-layout:fixed 下浏览器仅依据首行/colgroup 决定列宽,多级表头时子列宽度位于非首行会被忽略。
65
+ 故固定模式下通过 colgroup 显式声明每个叶子列宽度,保证子列 width 生效。 -->
66
+ <colgroup v-if="props.fixedMode && !virtualX_on">
67
+ <col v-for="col in tableHeaderLast" :key="colKeyGen(col)" :style="getColGroupColStyle(col)" />
68
+ </colgroup>
64
69
  <thead v-if="!headless">
65
70
  <tr
66
71
  v-for="(row, rowIndex) in virtualX_on ? virtualX_tableHeaders : tableHeaders"
@@ -911,10 +916,6 @@ const getFixedStyle = useFixedStyle<DT>(props, isRelativeMode, getFixedColPositi
911
916
 
912
917
  const [highlightSteps, setHighlightDimRow, setHighlightDimCell] = useHighlight(props, stkTableId, tableContainerRef);
913
918
 
914
- if (props.autoResize) {
915
- useAutoResize(tableContainerRef, initVirtualScroll, props, 200);
916
- }
917
-
918
919
  function getRowIndex(row: DT): number {
919
920
  const targetKey = rowKeyGen(row);
920
921
  return dataSourceCopy.value.findIndex(item => rowKeyGen(item) === targetKey);
@@ -963,6 +964,19 @@ const [fixedCols, fixedColClassMap, updateFixedShadow] = useFixedCol(
963
964
  tableContainerRef,
964
965
  );
965
966
 
967
+ if (props.autoResize) {
968
+ useAutoResize(
969
+ tableContainerRef,
970
+ () => {
971
+ initVirtualScroll();
972
+ // 容器宽度变化后,需重新计算固定列状态
973
+ updateFixedShadow();
974
+ },
975
+ props,
976
+ 200,
977
+ );
978
+ }
979
+
966
980
  const [colResizeOn, isColResizing, onThResizeMouseDown] = useColResize(
967
981
  props,
968
982
  emits,
@@ -1190,6 +1204,16 @@ const cellStyleMap = computed(() => {
1190
1204
  };
1191
1205
  });
1192
1206
 
1207
+ /**
1208
+ * fixed 模式下 colgroup 中单个 col 的样式。
1209
+ * 仅取叶子列的 width(与 cellStyleMap 中 --cw 保持一致);未设置 width 的列不声明宽度,
1210
+ * 由 table-layout:fixed 将剩余空间平分,符合“一列固定、其余列平分”的预期。
1211
+ */
1212
+ function getColGroupColStyle(col: PrivateStkTableColumn<DT>) {
1213
+ const width = transformWidthToStr(col.width);
1214
+ return width ? `width:${width}` : null;
1215
+ }
1216
+
1193
1217
  function getAbsoluteRowIndex(rowIndex: number) {
1194
1218
  return rowIndex + virtualScroll.value.startIndex;
1195
1219
  }
@@ -184,6 +184,19 @@
184
184
  thead tr:first-child th {
185
185
  background-image: var(--bg-border-top), var(--bg-border-right), var(--bg-border-bottom);
186
186
  }
187
+
188
+ /**
189
+ * 单元格的左边框由左侧相邻单元格的 border-right 提供。
190
+ * 右固定列吸附遮挡内容后,与左侧单元格不再相邻,因此需要自行绘制 border-left。
191
+ */
192
+ th.fixed-cell--border-left,
193
+ td.fixed-cell--border-left {
194
+ background-image: var(--bg-border-left), var(--bg-border-right), var(--bg-border-bottom);
195
+ }
196
+
197
+ thead tr:first-child th.fixed-cell--border-left {
198
+ background-image: var(--bg-border-left), var(--bg-border-top), var(--bg-border-right), var(--bg-border-bottom);
199
+ }
187
200
  }
188
201
 
189
202
  &.bordered-h {
@@ -206,6 +219,7 @@
206
219
  &.bordered-body-h {
207
220
  tbody {
208
221
  --bg-border-right: linear-gradient(transparent, transparent);
222
+ --bg-border-left: linear-gradient(transparent, transparent);
209
223
  }
210
224
  }
211
225
 
@@ -3,11 +3,11 @@ import { Ref, onBeforeUnmount, onMounted, watch } from 'vue';
3
3
  /**
4
4
  * 窗口变化自动重置虚拟滚动
5
5
  * @param tableContainerRef
6
- * @param initVirtualScroll
6
+ * @param onResize 容器尺寸变化后的重算逻辑(虚拟滚动、固定列等)
7
7
  * @param props
8
8
  * @param debounceMs
9
9
  */
10
- export function useAutoResize(tableContainerRef: Ref<HTMLElement | undefined>, initVirtualScroll: () => void, props: any, debounceMs: number) {
10
+ export function useAutoResize(tableContainerRef: Ref<HTMLElement | undefined>, onResize: () => void, props: any, debounceMs: number) {
11
11
  let resizeObserver: ResizeObserver | null = null;
12
12
  let isObserved = false;
13
13
  watch(
@@ -76,7 +76,7 @@ export function useAutoResize(tableContainerRef: Ref<HTMLElement | undefined>, i
76
76
  }
77
77
  debounceTime = window.setTimeout(() => {
78
78
  if (props.autoResize) {
79
- initVirtualScroll();
79
+ onResize();
80
80
  if (typeof props.autoResize === 'function') {
81
81
  props.autoResize();
82
82
  }
@@ -21,11 +21,18 @@ export function useFixedCol<DT extends Record<string, any>>(
21
21
  /** 正在被固定的列 */
22
22
  const fixedCols = shallowRef<StkTableColumn<DT>[]>([]);
23
23
 
24
+ /**
25
+ * 需要自行绘制左边框的右固定列。
26
+ * 单元格的左边框由左侧相邻单元格的 border-right 提供,右固定列吸附遮挡内容后两者不再相邻,因此需要自行绘制。
27
+ */
28
+ const fixedBorderLeftCols = shallowRef<StkTableColumn<DT>[]>([]);
29
+
24
30
  /** 固定列的class */
25
31
  const fixedColClassMap = computed(() => {
26
32
  const colMap = new Map();
27
33
  const fixedShadowColsValue = fixedShadowCols.value;
28
34
  const fixedColsValue = fixedCols.value;
35
+ const fixedBorderLeftColsValue = fixedBorderLeftCols.value;
29
36
  const colKeyFn = colKeyGen.value;
30
37
  const fixedColShadow = props.fixedColShadow;
31
38
  const headers = tableHeaders.value;
@@ -49,6 +56,9 @@ export function useFixedCol<DT extends Record<string, any>>(
49
56
  if (showShadow) {
50
57
  classList.push('fixed-cell--shadow');
51
58
  }
59
+ if (fixed === 'right' && fixedBorderLeftColsValue.includes(col)) {
60
+ classList.push('fixed-cell--border-left');
61
+ }
52
62
  colMap.set(colKeyFn(col), classList);
53
63
  }
54
64
  }
@@ -104,6 +114,15 @@ export function useFixedCol<DT extends Record<string, any>>(
104
114
  const len = tableHeadersForCalc.value.length;
105
115
  for (let level = 0; level < len; level++) {
106
116
  const row = tableHeadersForCalc.value[level];
117
+ /**
118
+ * 最右侧连续 fixed:right 列的起始下标。
119
+ * 这些列的固定偏移只由其右侧固定列宽度决定,不依赖中间列的声明宽度,
120
+ * 且 sticky/relative 在无横向溢出时偏移为0无副作用,因此无需判断滚动位置,始终固定。
121
+ */
122
+ let rightSuffixStart = row.length;
123
+ while (rightSuffixStart > 0 && row[rightSuffixStart - 1].fixed === 'right') {
124
+ rightSuffixStart--;
125
+ }
107
126
  /**
108
127
  * 左侧第n个fixed:left 计算要加上前面所有left 的列宽。
109
128
  */
@@ -121,10 +140,14 @@ export function useFixedCol<DT extends Record<string, any>>(
121
140
 
122
141
  left += getCalculatedColWidth(col);
123
142
 
124
- if (isFixedRight && scrollLeft + clientWidth - left < position) {
125
- fixedColsTemp.push(col);
126
- // 右固定列阴影,只要第一列
127
- if (!rightShadowCol[level]) {
143
+ if (isFixedRight) {
144
+ /** 是否需要固定。依赖列声明宽度累加,声明宽度与实际渲染宽度不一致时会失真 */
145
+ const needFix = scrollLeft + clientWidth - left < position;
146
+ if (i >= rightSuffixStart || needFix) {
147
+ fixedColsTemp.push(col);
148
+ }
149
+ // 右固定列阴影,只要第一列。阴影仍按滚动位置判断,避免未遮挡时也显示阴影
150
+ if (needFix && !rightShadowCol[level]) {
128
151
  rightShadowCol[level] = col;
129
152
  }
130
153
  }
@@ -135,6 +158,9 @@ export function useFixedCol<DT extends Record<string, any>>(
135
158
  fixedShadowCols.value = leftShadowCol.concat(rightShadowCol).filter(Boolean) as StkTableColumn<DT>[];
136
159
  }
137
160
 
161
+ // rightShadowCol 是每层最靠左的、已遮挡内容的右固定列,正是需要绘制左边框的列
162
+ fixedBorderLeftCols.value = rightShadowCol.filter(Boolean) as StkTableColumn<DT>[];
163
+
138
164
  fixedCols.value = fixedColsTemp;
139
165
  }
140
166