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
@ -68,5 +68,31 @@ export const pasteExcelClipboardString = (text: string): string[][] | null => {
|
||||
if (colCount === -1) colCount = data[index].length
|
||||
else if (colCount !== data[index].length) return null
|
||||
}
|
||||
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 { KEYS } from '@/configs/hotkey'
|
||||
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 Popover from '@/components/Popover.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) => {
|
||||
e.preventDefault()
|
||||
@ -273,24 +285,22 @@ const handlePaste = (e: ClipboardEvent, rowIndex: number, colIndex: number) => {
|
||||
|
||||
const clipboardDataFirstItem = e.clipboardData.items[0]
|
||||
|
||||
if (clipboardDataFirstItem && clipboardDataFirstItem.kind === 'string' && clipboardDataFirstItem.type === 'text/plain') {
|
||||
clipboardDataFirstItem.getAsString(text => {
|
||||
const clipboardData = pasteCustomClipboardString(text)
|
||||
if (typeof clipboardData === 'object') return
|
||||
|
||||
const excelData = pasteExcelClipboardString(text)
|
||||
if (excelData) {
|
||||
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]
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
if (clipboardDataFirstItem && clipboardDataFirstItem.kind === 'string') {
|
||||
if (clipboardDataFirstItem.type === 'text/plain') {
|
||||
clipboardDataFirstItem.getAsString(text => {
|
||||
const clipboardData = pasteCustomClipboardString(text)
|
||||
if (typeof clipboardData === 'object') return
|
||||
|
||||
const excelData = pasteExcelClipboardString(text)
|
||||
if (excelData) fillTableData(excelData, rowIndex, 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>
|
||||
import { onBeforeUnmount, ref, watch } from 'vue'
|
||||
import { pasteCustomClipboardString, pasteExcelClipboardString } from '@/utils/clipboard'
|
||||
import { pasteCustomClipboardString, pasteExcelClipboardString, pasteHTMLTableClipboardString } from '@/utils/clipboard'
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
value?: string
|
||||
@ -54,20 +54,32 @@ const handleFocus = () => {
|
||||
|
||||
const clipboardDataFirstItem = e.clipboardData.items[0]
|
||||
|
||||
if (clipboardDataFirstItem && clipboardDataFirstItem.kind === 'string' && clipboardDataFirstItem.type === 'text/plain') {
|
||||
clipboardDataFirstItem.getAsString(text => {
|
||||
const clipboardData = pasteCustomClipboardString(text)
|
||||
if (typeof clipboardData === 'object') return
|
||||
|
||||
const excelData = pasteExcelClipboardString(text)
|
||||
if (excelData) {
|
||||
emit('insertExcelData', excelData)
|
||||
if (textareaRef.value) textareaRef.value.innerHTML = excelData[0][0]
|
||||
return
|
||||
}
|
||||
|
||||
document.execCommand('insertText', false, text)
|
||||
})
|
||||
if (clipboardDataFirstItem && clipboardDataFirstItem.kind === 'string') {
|
||||
if (clipboardDataFirstItem.type === 'text/plain') {
|
||||
clipboardDataFirstItem.getAsString(text => {
|
||||
const clipboardData = pasteCustomClipboardString(text)
|
||||
if (typeof clipboardData === 'object') return
|
||||
|
||||
const excelData = pasteExcelClipboardString(text)
|
||||
if (excelData) {
|
||||
emit('insertExcelData', excelData)
|
||||
if (textareaRef.value) textareaRef.value.innerHTML = excelData[0][0]
|
||||
return
|
||||
}
|
||||
|
||||
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