jvs-ppt-ui 0.0.7 → 0.0.8
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/dist/lib/jvs-ppt-ui.es.js +135068 -112688
- package/dist/lib/jvs-ppt-ui.umd.js +101 -101
- package/dist/lib/style.css +1 -1
- package/package.json +1 -1
- package/src/components/CanvasArea.vue +51 -11
- package/src/components/Header.vue +31 -20
- package/src/components/PptEditor.vue +1040 -1005
- package/src/components/PresentationMode.vue +3 -1
- package/src/components/SidebarLeft.vue +14 -7
- package/src/components/sidebar/panels/SidebarDesignPanel.vue +1341 -1336
- package/src/composables/canvas/useCanvasTable.ts +183 -146
- package/src/composables/sidebar/useSidebarTextFormat.ts +1 -1
- package/src/composables/useSlides.ts +231 -34
- package/src/index.ts +2 -1
- package/dist/lib/__vite-browser-external-CbV4tiB6.js +0 -7
- package/dist/lib/dist-DkuYVyNR.js +0 -16010
- package/dist/lib/es-CfdgxdYp.js +0 -477
- package/dist/lib/jszip.min-Kba9Mb0l.js +0 -3034
- package/dist/lib/pptxgen.es-D0HrgUe_.js +0 -2352
|
@@ -14,6 +14,16 @@ export interface TableOptions {
|
|
|
14
14
|
selectedElementHeight?: Ref<string>
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
+
interface TableMeasure {
|
|
18
|
+
ver: number
|
|
19
|
+
sig: string
|
|
20
|
+
offset: { left: number; top: number; width: number; height: number }
|
|
21
|
+
cols: number[]
|
|
22
|
+
rows: number[]
|
|
23
|
+
colDots: number[]
|
|
24
|
+
rowDots: number[]
|
|
25
|
+
}
|
|
26
|
+
|
|
17
27
|
export function useCanvasTable(options: TableOptions) {
|
|
18
28
|
const {
|
|
19
29
|
activeSlide,
|
|
@@ -54,6 +64,7 @@ export function useCanvasTable(options: TableOptions) {
|
|
|
54
64
|
|
|
55
65
|
let tableCleanupFunc: (() => void) | null = null
|
|
56
66
|
let tableSelectionActive = false
|
|
67
|
+
let updateBordersRafId = 0
|
|
57
68
|
let startCell: HTMLTableCellElement | null = null
|
|
58
69
|
let tableResizeActiveTable: HTMLTableElement | null = null
|
|
59
70
|
let tableResizeActiveEl: any = null
|
|
@@ -71,37 +82,64 @@ export function useCanvasTable(options: TableOptions) {
|
|
|
71
82
|
return { width, height }
|
|
72
83
|
}
|
|
73
84
|
|
|
74
|
-
|
|
75
|
-
|
|
85
|
+
// ---- 表格几何单遍合并测量(渲染期回流治理)----
|
|
86
|
+
// 模板每次渲染原本重复调 getTableOffset×7 + getTableInfo×5 + 行/列圆点 O(n²),
|
|
87
|
+
// 全是 offset* 强制布局读;合并为每次失效只做一次 DOM 遍历,版本号+签名双缓存。
|
|
88
|
+
const tableMeasureVersion = ref(0)
|
|
89
|
+
const tableMeasureCache = new WeakMap<object, TableMeasure>()
|
|
90
|
+
|
|
91
|
+
function bumpTableMeasure() {
|
|
92
|
+
tableMeasureVersion.value++
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// 表格内容提交统一入口:写 content + 失效测量缓存 + 落历史快照
|
|
96
|
+
function commitTableContent(targetEl: any, html: string) {
|
|
97
|
+
targetEl.content = html
|
|
98
|
+
bumpTableMeasure()
|
|
99
|
+
addHistorySnapshot()
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function getTableMeasure(el: any): TableMeasure | null {
|
|
103
|
+
if (!el) return null
|
|
104
|
+
// 显式读取 RO 尺寸 ref:表格增高引起 ref 变化时,确保依赖收集覆盖本测量
|
|
105
|
+
void selectedElementWidth?.value
|
|
106
|
+
void selectedElementHeight?.value
|
|
107
|
+
const ver = tableMeasureVersion.value
|
|
108
|
+
// 签名只含响应式输入(零 DOM 读):内容长度 + 影响排版的 style + RO 尺寸
|
|
109
|
+
const st = el.style || {}
|
|
110
|
+
const sig = `${el.content?.length || 0}|${st.fontSize || ''}|${st.fontFamily || ''}|${st.fontWeight || ''}|${st.lineHeight || ''}|${st.letterSpacing || ''}|${st.padding || ''}|${st.whiteSpace || ''}|${st.writingMode || ''}|${st.width || ''}|${st.height || ''}|${selectedElementWidth?.value || ''}|${selectedElementHeight?.value || ''}`
|
|
111
|
+
const cached = tableMeasureCache.get(el)
|
|
112
|
+
if (cached && cached.ver === ver && cached.sig === sig) return cached
|
|
113
|
+
|
|
114
|
+
const hasContent = !!el.content && typeof el.content === 'string' && el.content.includes('<table')
|
|
76
115
|
const container = document.getElementById(`editable-${el.id}`)
|
|
77
116
|
const tableEl = container?.querySelector('table')
|
|
117
|
+
|
|
118
|
+
// offset(原 getTableOffset 逐分支等价)
|
|
119
|
+
let offset: TableMeasure['offset']
|
|
78
120
|
if (tableEl) {
|
|
79
|
-
|
|
121
|
+
offset = {
|
|
80
122
|
left: tableEl.offsetLeft || 0,
|
|
81
123
|
top: tableEl.offsetTop || 0,
|
|
82
124
|
width: tableEl.offsetWidth || parseFloat(getOverlayWidth(el)) || 500,
|
|
83
125
|
height: tableEl.offsetHeight || parseFloat(getOverlayHeight(el)) || 200
|
|
84
126
|
}
|
|
127
|
+
} else {
|
|
128
|
+
offset = {
|
|
129
|
+
left: 0,
|
|
130
|
+
top: 0,
|
|
131
|
+
width: parseFloat(getOverlayWidth(el)) || 500,
|
|
132
|
+
height: parseFloat(getOverlayHeight(el)) || 200
|
|
133
|
+
}
|
|
85
134
|
}
|
|
86
|
-
return {
|
|
87
|
-
left: 0,
|
|
88
|
-
top: 0,
|
|
89
|
-
width: parseFloat(getOverlayWidth(el)) || 500,
|
|
90
|
-
height: parseFloat(getOverlayHeight(el)) || 200
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
function getTableInfo(el: any) {
|
|
95
|
-
if (!el || !el.content || typeof el.content !== 'string' || !el.content.includes('<table')) return { cols: [], rows: [] }
|
|
96
135
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
let
|
|
101
|
-
|
|
102
|
-
trs = Array.from(tableEl.rows || [])
|
|
103
|
-
}
|
|
136
|
+
// cols/rows/圆点(原 getTableInfo 与两个圆点函数逐分支等价,单遍产出)
|
|
137
|
+
let cols: number[] = []
|
|
138
|
+
let rows: number[] = []
|
|
139
|
+
let colDots: number[] = []
|
|
140
|
+
let rowDots: number[] = []
|
|
104
141
|
|
|
142
|
+
const trs: HTMLTableRowElement[] = tableEl ? Array.from(tableEl.rows || []) : []
|
|
105
143
|
if (trs.length > 0) {
|
|
106
144
|
let bestRow = trs[0]
|
|
107
145
|
for (const tr of trs) {
|
|
@@ -110,51 +148,79 @@ export function useCanvasTable(options: TableOptions) {
|
|
|
110
148
|
}
|
|
111
149
|
}
|
|
112
150
|
const cells = Array.from(bestRow.cells)
|
|
113
|
-
const cols: number[] = []
|
|
114
151
|
if (cells.length > 0) {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
cols.push(cells[i].offsetWidth)
|
|
120
|
-
}
|
|
121
|
-
}
|
|
152
|
+
cols = cells.map((c, i) => (i < cells.length - 1 ? cells[i + 1].offsetLeft - cells[i].offsetLeft : c.offsetWidth))
|
|
153
|
+
colDots = [0, ...cells.slice(1).map(c => c.offsetLeft)]
|
|
154
|
+
const lastTd = cells[cells.length - 1]
|
|
155
|
+
colDots.push(lastTd.offsetLeft + lastTd.offsetWidth)
|
|
122
156
|
}
|
|
123
157
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
158
|
+
rows = trs.map((tr, i) => (i < trs.length - 1 ? trs[i + 1].offsetTop - trs[i].offsetTop : tr.offsetHeight))
|
|
159
|
+
rowDots = [0, ...trs.slice(1).map(tr => tr.offsetTop)]
|
|
160
|
+
const lastTr = trs[trs.length - 1]
|
|
161
|
+
rowDots.push(lastTr.offsetTop + lastTr.offsetHeight)
|
|
162
|
+
} else if (hasContent) {
|
|
163
|
+
// DOM 表不在场:DOMParser 结构 + 均分(原 getTableInfo fallback / 圆点累积路径)
|
|
164
|
+
const { width: targetW, height: targetH } = getTableActualDimensions(el)
|
|
165
|
+
try {
|
|
166
|
+
const doc = new DOMParser().parseFromString(el.content, 'text/html')
|
|
167
|
+
const parsedTable = doc.querySelector('table')
|
|
168
|
+
if (parsedTable) {
|
|
169
|
+
const numRows = parsedTable.rows.length || 1
|
|
170
|
+
let bestRow = parsedTable.rows[0]
|
|
171
|
+
for (let r = 0; r < parsedTable.rows.length; r++) {
|
|
172
|
+
if (parsedTable.rows[r].cells.length > bestRow.cells.length) {
|
|
173
|
+
bestRow = parsedTable.rows[r]
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
const numCols = bestRow ? bestRow.cells.length : 1
|
|
177
|
+
cols = Array(numCols).fill(targetW / numCols)
|
|
178
|
+
rows = Array(numRows).fill(targetH / numRows)
|
|
128
179
|
} else {
|
|
129
|
-
|
|
180
|
+
cols = [targetW]
|
|
181
|
+
rows = [targetH]
|
|
130
182
|
}
|
|
183
|
+
} catch {
|
|
184
|
+
cols = [targetW]
|
|
185
|
+
rows = [targetH]
|
|
131
186
|
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
const doc = new DOMParser().parseFromString(el.content, 'text/html')
|
|
139
|
-
const parsedTable = doc.querySelector('table')
|
|
140
|
-
if (parsedTable) {
|
|
141
|
-
const numRows = parsedTable.rows.length || 1
|
|
142
|
-
let bestRow = parsedTable.rows[0]
|
|
143
|
-
for (let r = 0; r < parsedTable.rows.length; r++) {
|
|
144
|
-
if (parsedTable.rows[r].cells.length > bestRow.cells.length) {
|
|
145
|
-
bestRow = parsedTable.rows[r]
|
|
146
|
-
}
|
|
187
|
+
if (cols.length > 0) {
|
|
188
|
+
colDots = [0]
|
|
189
|
+
let cx = 0
|
|
190
|
+
for (let i = 0; i < cols.length; i++) {
|
|
191
|
+
cx += cols[i]
|
|
192
|
+
colDots.push(cx)
|
|
147
193
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
194
|
+
}
|
|
195
|
+
if (rows.length > 0) {
|
|
196
|
+
rowDots = [0]
|
|
197
|
+
let cy = 0
|
|
198
|
+
for (let i = 0; i < rows.length; i++) {
|
|
199
|
+
cy += rows[i]
|
|
200
|
+
rowDots.push(cy)
|
|
152
201
|
}
|
|
153
202
|
}
|
|
154
|
-
} catch {
|
|
155
|
-
return { cols: [targetW], rows: [targetH] }
|
|
156
203
|
}
|
|
157
|
-
|
|
204
|
+
// 与原 getTableInfo 对齐:content 不含 <table> 时 cols/rows 恒为空
|
|
205
|
+
if (!hasContent) {
|
|
206
|
+
cols = []
|
|
207
|
+
rows = []
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const entry: TableMeasure = { ver, sig, offset, cols, rows, colDots, rowDots }
|
|
211
|
+
tableMeasureCache.set(el, entry)
|
|
212
|
+
return entry
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function getTableOffset(el: any) {
|
|
216
|
+
const m = getTableMeasure(el)
|
|
217
|
+
return m ? { ...m.offset } : { left: 0, top: 0, width: 500, height: 200 }
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function getTableInfo(el: any) {
|
|
221
|
+
const m = getTableMeasure(el)
|
|
222
|
+
if (!m) return { cols: [], rows: [] }
|
|
223
|
+
return { cols: m.cols.slice(), rows: m.rows.slice() }
|
|
158
224
|
}
|
|
159
225
|
|
|
160
226
|
function reindexTable(tableEl: HTMLTableElement) {
|
|
@@ -280,6 +346,7 @@ export function useCanvasTable(options: TableOptions) {
|
|
|
280
346
|
const selectedTds = Array.from(tableEl.querySelectorAll('td.selected-cell')) as HTMLTableCellElement[]
|
|
281
347
|
selectedCellCount.value = selectedTds.length
|
|
282
348
|
tableSelectionTrigger.value++
|
|
349
|
+
bumpTableMeasure()
|
|
283
350
|
|
|
284
351
|
if (selectedTds.length === 1) {
|
|
285
352
|
const td = selectedTds[0]
|
|
@@ -574,63 +641,13 @@ export function useCanvasTable(options: TableOptions) {
|
|
|
574
641
|
}
|
|
575
642
|
|
|
576
643
|
function getColDotPositions(el: any): number[] {
|
|
577
|
-
const
|
|
578
|
-
|
|
579
|
-
if (tableEl && tableEl.rows.length > 0) {
|
|
580
|
-
let bestRow = tableEl.rows[0]
|
|
581
|
-
for (let r = 0; r < tableEl.rows.length; r++) {
|
|
582
|
-
if (tableEl.rows[r].cells.length > bestRow.cells.length) {
|
|
583
|
-
bestRow = tableEl.rows[r]
|
|
584
|
-
}
|
|
585
|
-
}
|
|
586
|
-
const cells = Array.from(bestRow.cells)
|
|
587
|
-
if (cells.length > 0) {
|
|
588
|
-
const positions: number[] = [0]
|
|
589
|
-
for (let i = 1; i < cells.length; i++) {
|
|
590
|
-
positions.push(cells[i].offsetLeft)
|
|
591
|
-
}
|
|
592
|
-
const lastTd = cells[cells.length - 1]
|
|
593
|
-
positions.push(lastTd.offsetLeft + lastTd.offsetWidth)
|
|
594
|
-
return positions
|
|
595
|
-
}
|
|
596
|
-
}
|
|
597
|
-
|
|
598
|
-
const info = getTableInfo(el)
|
|
599
|
-
if (!info.cols || info.cols.length === 0) return []
|
|
600
|
-
const positions = [0]
|
|
601
|
-
let currentX = 0
|
|
602
|
-
for (let i = 0; i < info.cols.length; i++) {
|
|
603
|
-
currentX += info.cols[i]
|
|
604
|
-
positions.push(currentX)
|
|
605
|
-
}
|
|
606
|
-
return positions
|
|
644
|
+
const m = getTableMeasure(el)
|
|
645
|
+
return m ? m.colDots.slice() : []
|
|
607
646
|
}
|
|
608
647
|
|
|
609
648
|
function getRowDotPositions(el: any): number[] {
|
|
610
|
-
const
|
|
611
|
-
|
|
612
|
-
if (tableEl && tableEl.rows.length > 0) {
|
|
613
|
-
const trs = Array.from(tableEl.rows)
|
|
614
|
-
if (trs.length > 0) {
|
|
615
|
-
const positions: number[] = [0]
|
|
616
|
-
for (let i = 1; i < trs.length; i++) {
|
|
617
|
-
positions.push(trs[i].offsetTop)
|
|
618
|
-
}
|
|
619
|
-
const lastTr = trs[trs.length - 1]
|
|
620
|
-
positions.push(lastTr.offsetTop + lastTr.offsetHeight)
|
|
621
|
-
return positions
|
|
622
|
-
}
|
|
623
|
-
}
|
|
624
|
-
|
|
625
|
-
const info = getTableInfo(el)
|
|
626
|
-
if (!info.rows || info.rows.length === 0) return []
|
|
627
|
-
const positions = [0]
|
|
628
|
-
let currentY = 0
|
|
629
|
-
for (let i = 0; i < info.rows.length; i++) {
|
|
630
|
-
currentY += info.rows[i]
|
|
631
|
-
positions.push(currentY)
|
|
632
|
-
}
|
|
633
|
-
return positions
|
|
649
|
+
const m = getTableMeasure(el)
|
|
650
|
+
return m ? m.rowDots.slice() : []
|
|
634
651
|
}
|
|
635
652
|
|
|
636
653
|
function getSelectedCellCoords(container: HTMLElement) {
|
|
@@ -805,8 +822,7 @@ export function useCanvasTable(options: TableOptions) {
|
|
|
805
822
|
|
|
806
823
|
const cloneTable = tableEl.cloneNode(true) as HTMLTableElement
|
|
807
824
|
cleanTableDOMForSaving(cloneTable)
|
|
808
|
-
targetEl
|
|
809
|
-
addHistorySnapshot()
|
|
825
|
+
commitTableContent(targetEl, cloneTable.outerHTML)
|
|
810
826
|
|
|
811
827
|
nextTick(() => {
|
|
812
828
|
const freshContainer = document.getElementById(`editable-${targetEl.id}`)
|
|
@@ -932,8 +948,7 @@ export function useCanvasTable(options: TableOptions) {
|
|
|
932
948
|
|
|
933
949
|
const cloneTable = tableEl.cloneNode(true) as HTMLTableElement
|
|
934
950
|
cleanTableDOMForSaving(cloneTable)
|
|
935
|
-
targetEl
|
|
936
|
-
addHistorySnapshot()
|
|
951
|
+
commitTableContent(targetEl, cloneTable.outerHTML)
|
|
937
952
|
|
|
938
953
|
nextTick(() => {
|
|
939
954
|
const freshContainer = document.getElementById(`editable-${targetEl.id}`)
|
|
@@ -995,8 +1010,7 @@ export function useCanvasTable(options: TableOptions) {
|
|
|
995
1010
|
|
|
996
1011
|
const cloneTable = tableEl.cloneNode(true) as HTMLTableElement
|
|
997
1012
|
cleanTableDOMForSaving(cloneTable)
|
|
998
|
-
targetEl
|
|
999
|
-
addHistorySnapshot()
|
|
1013
|
+
commitTableContent(targetEl, cloneTable.outerHTML)
|
|
1000
1014
|
|
|
1001
1015
|
nextTick(() => {
|
|
1002
1016
|
const freshContainer = document.getElementById(`editable-${targetEl.id}`)
|
|
@@ -1064,8 +1078,7 @@ export function useCanvasTable(options: TableOptions) {
|
|
|
1064
1078
|
|
|
1065
1079
|
const cloneTable = tableEl.cloneNode(true) as HTMLTableElement
|
|
1066
1080
|
cleanTableDOMForSaving(cloneTable)
|
|
1067
|
-
targetEl
|
|
1068
|
-
addHistorySnapshot()
|
|
1081
|
+
commitTableContent(targetEl, cloneTable.outerHTML)
|
|
1069
1082
|
|
|
1070
1083
|
nextTick(() => {
|
|
1071
1084
|
const freshContainer = document.getElementById(`editable-${targetEl.id}`)
|
|
@@ -1131,8 +1144,7 @@ export function useCanvasTable(options: TableOptions) {
|
|
|
1131
1144
|
|
|
1132
1145
|
const cloneTable = tableEl.cloneNode(true) as HTMLTableElement
|
|
1133
1146
|
cleanTableDOMForSaving(cloneTable)
|
|
1134
|
-
targetEl
|
|
1135
|
-
addHistorySnapshot()
|
|
1147
|
+
commitTableContent(targetEl, cloneTable.outerHTML)
|
|
1136
1148
|
|
|
1137
1149
|
nextTick(() => {
|
|
1138
1150
|
const freshContainer = document.getElementById(`editable-${targetEl.id}`)
|
|
@@ -1234,8 +1246,7 @@ export function useCanvasTable(options: TableOptions) {
|
|
|
1234
1246
|
|
|
1235
1247
|
const cloneTable = tableEl.cloneNode(true) as HTMLTableElement
|
|
1236
1248
|
cleanTableDOMForSaving(cloneTable)
|
|
1237
|
-
targetEl
|
|
1238
|
-
addHistorySnapshot()
|
|
1249
|
+
commitTableContent(targetEl, cloneTable.outerHTML)
|
|
1239
1250
|
|
|
1240
1251
|
nextTick(() => {
|
|
1241
1252
|
const freshContainer = document.getElementById(`editable-${targetEl.id}`)
|
|
@@ -1332,12 +1343,21 @@ export function useCanvasTable(options: TableOptions) {
|
|
|
1332
1343
|
selectedElementWidth.value = `${sumW.toFixed(1)}px`
|
|
1333
1344
|
}
|
|
1334
1345
|
}
|
|
1335
|
-
|
|
1346
|
+
// rAF 节流:高轮询率鼠标下避免每 move 一次边框重算
|
|
1347
|
+
if (updateBordersRafId) cancelAnimationFrame(updateBordersRafId)
|
|
1348
|
+
updateBordersRafId = requestAnimationFrame(() => {
|
|
1349
|
+
updateBordersRafId = 0
|
|
1350
|
+
if (isResizingTable.value) updateSelectionBorders(tableEl)
|
|
1351
|
+
})
|
|
1336
1352
|
}
|
|
1337
1353
|
|
|
1338
1354
|
const onMouseUp = () => {
|
|
1339
1355
|
window.removeEventListener('mousemove', onMouseMove)
|
|
1340
1356
|
window.removeEventListener('mouseup', onMouseUp)
|
|
1357
|
+
if (updateBordersRafId) {
|
|
1358
|
+
cancelAnimationFrame(updateBordersRafId)
|
|
1359
|
+
updateBordersRafId = 0
|
|
1360
|
+
}
|
|
1341
1361
|
isResizingTable.value = false
|
|
1342
1362
|
tableResizeType.value = null
|
|
1343
1363
|
tableResizeTd.value = null
|
|
@@ -1345,8 +1365,7 @@ export function useCanvasTable(options: TableOptions) {
|
|
|
1345
1365
|
|
|
1346
1366
|
const cloneTable = tableEl.cloneNode(true) as HTMLTableElement
|
|
1347
1367
|
cleanTableDOMForSaving(cloneTable)
|
|
1348
|
-
el
|
|
1349
|
-
addHistorySnapshot()
|
|
1368
|
+
commitTableContent(el, cloneTable.outerHTML)
|
|
1350
1369
|
}
|
|
1351
1370
|
|
|
1352
1371
|
window.addEventListener('mousemove', onMouseMove)
|
|
@@ -1417,12 +1436,21 @@ export function useCanvasTable(options: TableOptions) {
|
|
|
1417
1436
|
selectedElementHeight.value = `${sumH.toFixed(1)}px`
|
|
1418
1437
|
}
|
|
1419
1438
|
}
|
|
1420
|
-
|
|
1439
|
+
// rAF 节流:高轮询率鼠标下避免每 move 一次边框重算
|
|
1440
|
+
if (updateBordersRafId) cancelAnimationFrame(updateBordersRafId)
|
|
1441
|
+
updateBordersRafId = requestAnimationFrame(() => {
|
|
1442
|
+
updateBordersRafId = 0
|
|
1443
|
+
if (isResizingTable.value) updateSelectionBorders(tableEl)
|
|
1444
|
+
})
|
|
1421
1445
|
}
|
|
1422
1446
|
|
|
1423
1447
|
const onMouseUp = () => {
|
|
1424
1448
|
window.removeEventListener('mousemove', onMouseMove)
|
|
1425
1449
|
window.removeEventListener('mouseup', onMouseUp)
|
|
1450
|
+
if (updateBordersRafId) {
|
|
1451
|
+
cancelAnimationFrame(updateBordersRafId)
|
|
1452
|
+
updateBordersRafId = 0
|
|
1453
|
+
}
|
|
1426
1454
|
isResizingTable.value = false
|
|
1427
1455
|
tableResizeType.value = null
|
|
1428
1456
|
tableResizeTd.value = null
|
|
@@ -1430,8 +1458,7 @@ export function useCanvasTable(options: TableOptions) {
|
|
|
1430
1458
|
|
|
1431
1459
|
const cloneTable = tableEl.cloneNode(true) as HTMLTableElement
|
|
1432
1460
|
cleanTableDOMForSaving(cloneTable)
|
|
1433
|
-
el
|
|
1434
|
-
addHistorySnapshot()
|
|
1461
|
+
commitTableContent(el, cloneTable.outerHTML)
|
|
1435
1462
|
}
|
|
1436
1463
|
|
|
1437
1464
|
window.addEventListener('mousemove', onMouseMove)
|
|
@@ -1456,26 +1483,34 @@ export function useCanvasTable(options: TableOptions) {
|
|
|
1456
1483
|
reindexTable(tableEl)
|
|
1457
1484
|
const borderTolerance = 6
|
|
1458
1485
|
|
|
1486
|
+
let mousemoveRafId = 0
|
|
1459
1487
|
const mousemoveHandler = (e: MouseEvent) => {
|
|
1460
1488
|
if (isResizingTable.value) return
|
|
1489
|
+
// rAF 节流:每帧最多一次 getBoundingClientRect,消除高频 mousemove 的强制回流
|
|
1490
|
+
if (mousemoveRafId) return
|
|
1491
|
+
const clientX = e.clientX
|
|
1492
|
+
const clientY = e.clientY
|
|
1461
1493
|
const target = e.target as HTMLElement
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1494
|
+
mousemoveRafId = requestAnimationFrame(() => {
|
|
1495
|
+
mousemoveRafId = 0
|
|
1496
|
+
const td = target.closest('td') as HTMLTableCellElement | null
|
|
1497
|
+
if (!td || !tableEl.contains(td)) {
|
|
1498
|
+
tableEl.style.cursor = 'default'
|
|
1499
|
+
return
|
|
1500
|
+
}
|
|
1467
1501
|
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1502
|
+
const rect = td.getBoundingClientRect()
|
|
1503
|
+
const distRight = Math.abs(rect.right - clientX)
|
|
1504
|
+
const distBottom = Math.abs(rect.bottom - clientY)
|
|
1471
1505
|
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1506
|
+
if (distRight <= borderTolerance && distRight <= distBottom) {
|
|
1507
|
+
tableEl.style.cursor = 'col-resize'
|
|
1508
|
+
} else if (distBottom <= borderTolerance) {
|
|
1509
|
+
tableEl.style.cursor = 'row-resize'
|
|
1510
|
+
} else {
|
|
1511
|
+
tableEl.style.cursor = 'default'
|
|
1512
|
+
}
|
|
1513
|
+
})
|
|
1479
1514
|
}
|
|
1480
1515
|
|
|
1481
1516
|
const mousedownHandler = (e: MouseEvent) => {
|
|
@@ -1536,6 +1571,10 @@ export function useCanvasTable(options: TableOptions) {
|
|
|
1536
1571
|
window.addEventListener('mouseup', mouseupHandler)
|
|
1537
1572
|
|
|
1538
1573
|
const cleanup = () => {
|
|
1574
|
+
if (mousemoveRafId) {
|
|
1575
|
+
cancelAnimationFrame(mousemoveRafId)
|
|
1576
|
+
mousemoveRafId = 0
|
|
1577
|
+
}
|
|
1539
1578
|
tableEl.removeEventListener('mousemove', mousemoveHandler)
|
|
1540
1579
|
tableEl.removeEventListener('mousedown', mousedownHandler)
|
|
1541
1580
|
tableEl.removeEventListener('mouseover', mouseoverHandler)
|
|
@@ -1610,9 +1649,8 @@ export function useCanvasTable(options: TableOptions) {
|
|
|
1610
1649
|
}
|
|
1611
1650
|
}
|
|
1612
1651
|
|
|
1613
|
-
el.content = div.innerHTML
|
|
1614
1652
|
if (selectedElementHeight) selectedElementHeight.value = `${totalHeight}px`
|
|
1615
|
-
|
|
1653
|
+
commitTableContent(el, div.innerHTML)
|
|
1616
1654
|
}
|
|
1617
1655
|
|
|
1618
1656
|
function equalizeTableColWidths() {
|
|
@@ -1638,9 +1676,8 @@ export function useCanvasTable(options: TableOptions) {
|
|
|
1638
1676
|
}
|
|
1639
1677
|
}
|
|
1640
1678
|
|
|
1641
|
-
el.content = div.innerHTML
|
|
1642
1679
|
if (selectedElementWidth) selectedElementWidth.value = `${totalWidth}px`
|
|
1643
|
-
|
|
1680
|
+
commitTableContent(el, div.innerHTML)
|
|
1644
1681
|
}
|
|
1645
1682
|
|
|
1646
1683
|
return {
|
|
@@ -32,7 +32,7 @@ export function useSidebarTextFormat(
|
|
|
32
32
|
activeSlide: Ref<any>,
|
|
33
33
|
slides: Ref<any[]>,
|
|
34
34
|
activeIndex: Ref<number>,
|
|
35
|
-
historyStack: Ref<string[]>,
|
|
35
|
+
historyStack: Ref<string[][]>,
|
|
36
36
|
historyIndex: Ref<number>,
|
|
37
37
|
globalFontColor: Ref<string>,
|
|
38
38
|
shapeFormatPainter: Ref<any>,
|