mirror of
https://github.com/pipipi-pikachu/PPTist.git
synced 2025-04-15 02:20:00 +08:00
feat: 支持粘贴来自PPT表格的数据
This commit is contained in:
parent
83e9871c80
commit
7f4400f34d
@ -70,3 +70,29 @@ export const pasteExcelClipboardString = (text: string): string[][] | null => {
|
|||||||
}
|
}
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 尝试解析剪贴板内容是否为HTML table代码
|
||||||
|
export const pasteHTMLTableClipboardString = (text: string): string[][] | null => {
|
||||||
|
const parser = new DOMParser()
|
||||||
|
const doc = parser.parseFromString(text, 'text/html')
|
||||||
|
const table = doc.querySelector('table')
|
||||||
|
const data: string[][] = []
|
||||||
|
|
||||||
|
if (!table) return data
|
||||||
|
|
||||||
|
const rows = table.querySelectorAll('tr')
|
||||||
|
for (const row of rows) {
|
||||||
|
const rowData = []
|
||||||
|
const cells = row.querySelectorAll('td, th')
|
||||||
|
for (const cell of cells) {
|
||||||
|
const text = cell.textContent ? cell.textContent.trim() : ''
|
||||||
|
const colspan = parseInt(cell.getAttribute('colspan') || '1', 10)
|
||||||
|
for (let i = 0; i < colspan; i++) {
|
||||||
|
rowData.push(text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
data.push(rowData)
|
||||||
|
}
|
||||||
|
|
||||||
|
return data
|
||||||
|
}
|
@ -95,7 +95,7 @@ import { computed, onMounted, onUnmounted, ref } from 'vue'
|
|||||||
import type { ChartData, ChartType } from '@/types/slides'
|
import type { ChartData, ChartType } from '@/types/slides'
|
||||||
import { KEYS } from '@/configs/hotkey'
|
import { KEYS } from '@/configs/hotkey'
|
||||||
import { CHART_TYPE_MAP } from '@/configs/chart'
|
import { CHART_TYPE_MAP } from '@/configs/chart'
|
||||||
import { pasteCustomClipboardString, pasteExcelClipboardString } from '@/utils/clipboard'
|
import { pasteCustomClipboardString, pasteExcelClipboardString, pasteHTMLTableClipboardString } from '@/utils/clipboard'
|
||||||
import Button from '@/components/Button.vue'
|
import Button from '@/components/Button.vue'
|
||||||
import Popover from '@/components/Popover.vue'
|
import Popover from '@/components/Popover.vue'
|
||||||
import PopoverMenuItem from '@/components/PopoverMenuItem.vue'
|
import PopoverMenuItem from '@/components/PopoverMenuItem.vue'
|
||||||
@ -265,6 +265,18 @@ const clear = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const fillTableData = (data: string[][], rowIndex: number, colIndex: number) => {
|
||||||
|
const maxRow = rowIndex + data.length
|
||||||
|
const maxCol = colIndex + data[0].length
|
||||||
|
for (let i = rowIndex; i < maxRow; i++) {
|
||||||
|
for (let j = colIndex; j < maxCol; j++) {
|
||||||
|
const inputRef = document.querySelector(`#cell-${i}-${j}`) as HTMLInputElement
|
||||||
|
if (!inputRef) continue
|
||||||
|
inputRef.value = data[i - rowIndex][j - colIndex]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 自定义粘贴事件(尝试读取剪贴板中的表格数据)
|
// 自定义粘贴事件(尝试读取剪贴板中的表格数据)
|
||||||
const handlePaste = (e: ClipboardEvent, rowIndex: number, colIndex: number) => {
|
const handlePaste = (e: ClipboardEvent, rowIndex: number, colIndex: number) => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
@ -273,25 +285,23 @@ const handlePaste = (e: ClipboardEvent, rowIndex: number, colIndex: number) => {
|
|||||||
|
|
||||||
const clipboardDataFirstItem = e.clipboardData.items[0]
|
const clipboardDataFirstItem = e.clipboardData.items[0]
|
||||||
|
|
||||||
if (clipboardDataFirstItem && clipboardDataFirstItem.kind === 'string' && clipboardDataFirstItem.type === 'text/plain') {
|
if (clipboardDataFirstItem && clipboardDataFirstItem.kind === 'string') {
|
||||||
|
if (clipboardDataFirstItem.type === 'text/plain') {
|
||||||
clipboardDataFirstItem.getAsString(text => {
|
clipboardDataFirstItem.getAsString(text => {
|
||||||
const clipboardData = pasteCustomClipboardString(text)
|
const clipboardData = pasteCustomClipboardString(text)
|
||||||
if (typeof clipboardData === 'object') return
|
if (typeof clipboardData === 'object') return
|
||||||
|
|
||||||
const excelData = pasteExcelClipboardString(text)
|
const excelData = pasteExcelClipboardString(text)
|
||||||
if (excelData) {
|
if (excelData) fillTableData(excelData, rowIndex, colIndex)
|
||||||
const maxRow = rowIndex + excelData.length
|
|
||||||
const maxCol = colIndex + excelData[0].length
|
|
||||||
for (let i = rowIndex; i < maxRow; i++) {
|
|
||||||
for (let j = colIndex; j < maxCol; j++) {
|
|
||||||
const inputRef = document.querySelector(`#cell-${i}-${j}`) as HTMLInputElement
|
|
||||||
if (!inputRef) continue
|
|
||||||
inputRef.value = excelData[i - rowIndex][j - colIndex]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
else if (clipboardDataFirstItem.type === 'text/html') {
|
||||||
|
clipboardDataFirstItem.getAsString(html => {
|
||||||
|
const htmlData = pasteHTMLTableClipboardString(html)
|
||||||
|
if (htmlData) fillTableData(htmlData, rowIndex, colIndex)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 关闭图表数据编辑器
|
// 关闭图表数据编辑器
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onBeforeUnmount, ref, watch } from 'vue'
|
import { onBeforeUnmount, ref, watch } from 'vue'
|
||||||
import { pasteCustomClipboardString, pasteExcelClipboardString } from '@/utils/clipboard'
|
import { pasteCustomClipboardString, pasteExcelClipboardString, pasteHTMLTableClipboardString } from '@/utils/clipboard'
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
value?: string
|
value?: string
|
||||||
@ -54,7 +54,8 @@ const handleFocus = () => {
|
|||||||
|
|
||||||
const clipboardDataFirstItem = e.clipboardData.items[0]
|
const clipboardDataFirstItem = e.clipboardData.items[0]
|
||||||
|
|
||||||
if (clipboardDataFirstItem && clipboardDataFirstItem.kind === 'string' && clipboardDataFirstItem.type === 'text/plain') {
|
if (clipboardDataFirstItem && clipboardDataFirstItem.kind === 'string') {
|
||||||
|
if (clipboardDataFirstItem.type === 'text/plain') {
|
||||||
clipboardDataFirstItem.getAsString(text => {
|
clipboardDataFirstItem.getAsString(text => {
|
||||||
const clipboardData = pasteCustomClipboardString(text)
|
const clipboardData = pasteCustomClipboardString(text)
|
||||||
if (typeof clipboardData === 'object') return
|
if (typeof clipboardData === 'object') return
|
||||||
@ -69,6 +70,17 @@ const handleFocus = () => {
|
|||||||
document.execCommand('insertText', false, text)
|
document.execCommand('insertText', false, text)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
else if (clipboardDataFirstItem.type === 'text/html') {
|
||||||
|
clipboardDataFirstItem.getAsString(html => {
|
||||||
|
const htmlData = pasteHTMLTableClipboardString(html)
|
||||||
|
if (htmlData) {
|
||||||
|
emit('insertExcelData', htmlData)
|
||||||
|
if (textareaRef.value) textareaRef.value.innerHTML = htmlData[0][0]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user