mirror of
https://github.com/pipipi-pikachu/PPTist.git
synced 2025-04-15 02:20:00 +08:00
可编辑表格组件开发
This commit is contained in:
parent
7be29a5fc2
commit
38504b096a
39
src/App.vue
39
src/App.vue
@ -3,14 +3,18 @@
|
|||||||
<Screen v-else />
|
<Screen v-else />
|
||||||
|
|
||||||
<div class="test">
|
<div class="test">
|
||||||
<EditableTable />
|
<EditableTable
|
||||||
|
:data="tableCells"
|
||||||
|
@change="data => updateTableCells(data)"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { computed, defineComponent, onMounted } from 'vue'
|
import { computed, defineComponent, onMounted, ref } from 'vue'
|
||||||
import { useStore } from 'vuex'
|
import { useStore } from 'vuex'
|
||||||
import { MutationTypes, ActionTypes, State } from '@/store'
|
import { MutationTypes, ActionTypes, State } from '@/store'
|
||||||
|
import { TableCell } from './types/slides'
|
||||||
|
|
||||||
import Editor from './views/Editor/index.vue'
|
import Editor from './views/Editor/index.vue'
|
||||||
import Screen from './views/Screen/index.vue'
|
import Screen from './views/Screen/index.vue'
|
||||||
@ -27,12 +31,43 @@ export default defineComponent({
|
|||||||
const store = useStore<State>()
|
const store = useStore<State>()
|
||||||
const screening = computed(() => store.state.screening)
|
const screening = computed(() => store.state.screening)
|
||||||
|
|
||||||
|
const tableCells = ref<TableCell[][]>([
|
||||||
|
[
|
||||||
|
{ id: '1', colspan: 1, rowspan: 1, text: '' },
|
||||||
|
{ id: '2', colspan: 1, rowspan: 1, text: '' },
|
||||||
|
{ id: '3', colspan: 1, rowspan: 1, text: '' },
|
||||||
|
{ id: '4', colspan: 1, rowspan: 1, text: '' },
|
||||||
|
{ id: '5', colspan: 1, rowspan: 1, text: '' },
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{ id: '6', colspan: 1, rowspan: 1, text: '' },
|
||||||
|
{ id: '7', colspan: 1, rowspan: 1, text: '' },
|
||||||
|
{ id: '8', colspan: 1, rowspan: 1, text: '' },
|
||||||
|
{ id: '9', colspan: 1, rowspan: 1, text: '' },
|
||||||
|
{ id: '10', colspan: 1, rowspan: 1, text: '' },
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{ id: '11', colspan: 1, rowspan: 1, text: '' },
|
||||||
|
{ id: '12', colspan: 1, rowspan: 1, text: '' },
|
||||||
|
{ id: '13', colspan: 1, rowspan: 1, text: '' },
|
||||||
|
{ id: '14', colspan: 1, rowspan: 1, text: '' },
|
||||||
|
{ id: '15', colspan: 1, rowspan: 1, text: '' },
|
||||||
|
],
|
||||||
|
])
|
||||||
|
|
||||||
|
const updateTableCells = (data: TableCell[][]) => {
|
||||||
|
console.log(data)
|
||||||
|
tableCells.value = data
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
store.commit(MutationTypes.SET_AVAILABLE_FONTS)
|
store.commit(MutationTypes.SET_AVAILABLE_FONTS)
|
||||||
store.dispatch(ActionTypes.INIT_SNAPSHOT_DATABASE)
|
store.dispatch(ActionTypes.INIT_SNAPSHOT_DATABASE)
|
||||||
})
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
tableCells,
|
||||||
|
updateTableCells,
|
||||||
screening,
|
screening,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -44,6 +44,7 @@
|
|||||||
:class="{ 'active': activedCell === `${rowIndex}_${colIndex}` }"
|
:class="{ 'active': activedCell === `${rowIndex}_${colIndex}` }"
|
||||||
:contenteditable="activedCell === `${rowIndex}_${colIndex}` ? 'plaintext-only' : false"
|
:contenteditable="activedCell === `${rowIndex}_${colIndex}` ? 'plaintext-only' : false"
|
||||||
v-model="cell.text"
|
v-model="cell.text"
|
||||||
|
@update:modelValue="handleInput()"
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@ -54,28 +55,14 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { computed, defineComponent, nextTick, onMounted, onUnmounted, PropType, ref } from 'vue'
|
import { computed, defineComponent, nextTick, onMounted, onUnmounted, PropType, ref } from 'vue'
|
||||||
|
import debounce from 'lodash/debounce'
|
||||||
import { ContextmenuItem } from './Contextmenu/types'
|
import { ContextmenuItem } from './Contextmenu/types'
|
||||||
|
import { TableCell } from '@/types/slides'
|
||||||
import { KEYS } from '@/configs/hotkey'
|
import { KEYS } from '@/configs/hotkey'
|
||||||
import { createRandomCode } from '@/utils/common'
|
import { createRandomCode } from '@/utils/common'
|
||||||
|
|
||||||
import EditableDiv from './EditableDiv.vue'
|
import EditableDiv from './EditableDiv.vue'
|
||||||
|
|
||||||
interface TableCells {
|
|
||||||
id: string;
|
|
||||||
colspan: number;
|
|
||||||
rowspan: number;
|
|
||||||
text: string;
|
|
||||||
style?: {
|
|
||||||
color?: string;
|
|
||||||
bgColor?: string;
|
|
||||||
fontSize?: number;
|
|
||||||
fontName?: string;
|
|
||||||
bold?: boolean;
|
|
||||||
italic?: boolean;
|
|
||||||
align?: string;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'editable-table',
|
name: 'editable-table',
|
||||||
components: {
|
components: {
|
||||||
@ -83,33 +70,32 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
data: {
|
data: {
|
||||||
type: Array as PropType<TableCells[][]>,
|
type: Array as PropType<TableCell[][]>,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
outlineWidth: {
|
||||||
|
type: Number,
|
||||||
|
default: 1,
|
||||||
|
},
|
||||||
|
outlineColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#41464b',
|
||||||
|
},
|
||||||
|
outlineStyle: {
|
||||||
|
type: String,
|
||||||
|
default: 'solid',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
setup() {
|
setup(props, { emit }) {
|
||||||
const tableCells = ref<TableCells[][]>([
|
const tableCells = computed<TableCell[][]>({
|
||||||
[
|
get() {
|
||||||
{ id: '1', colspan: 1, rowspan: 1, text: '' },
|
return props.data
|
||||||
{ id: '2', colspan: 1, rowspan: 1, text: '' },
|
},
|
||||||
{ id: '3', colspan: 1, rowspan: 1, text: '' },
|
set(newData) {
|
||||||
{ id: '4', colspan: 1, rowspan: 1, text: '' },
|
emit('change', newData)
|
||||||
{ id: '5', colspan: 1, rowspan: 1, text: '' },
|
},
|
||||||
],
|
})
|
||||||
[
|
|
||||||
{ id: '6', colspan: 1, rowspan: 1, text: '' },
|
|
||||||
{ id: '7', colspan: 1, rowspan: 1, text: '' },
|
|
||||||
{ id: '8', colspan: 1, rowspan: 1, text: '' },
|
|
||||||
{ id: '9', colspan: 1, rowspan: 1, text: '' },
|
|
||||||
{ id: '10', colspan: 1, rowspan: 1, text: '' },
|
|
||||||
],
|
|
||||||
[
|
|
||||||
{ id: '11', colspan: 1, rowspan: 1, text: '' },
|
|
||||||
{ id: '12', colspan: 1, rowspan: 1, text: '' },
|
|
||||||
{ id: '13', colspan: 1, rowspan: 1, text: '' },
|
|
||||||
{ id: '14', colspan: 1, rowspan: 1, text: '' },
|
|
||||||
{ id: '15', colspan: 1, rowspan: 1, text: '' },
|
|
||||||
],
|
|
||||||
])
|
|
||||||
const colWidths = ref([160, 160, 160, 160, 160])
|
const colWidths = ref([160, 160, 160, 160, 160])
|
||||||
const isStartSelect = ref(false)
|
const isStartSelect = ref(false)
|
||||||
const startCell = ref<number[]>([])
|
const startCell = ref<number[]>([])
|
||||||
@ -246,7 +232,7 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const deleteRow = (rowIndex: number) => {
|
const deleteRow = (rowIndex: number) => {
|
||||||
const _tableCells: TableCells[][] = JSON.parse(JSON.stringify(tableCells.value))
|
const _tableCells: TableCell[][] = JSON.parse(JSON.stringify(tableCells.value))
|
||||||
|
|
||||||
const targetCells = tableCells.value[rowIndex]
|
const targetCells = tableCells.value[rowIndex]
|
||||||
const hideCellsPos = []
|
const hideCellsPos = []
|
||||||
@ -268,7 +254,7 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const deleteCol = (colIndex: number) => {
|
const deleteCol = (colIndex: number) => {
|
||||||
const _tableCells: TableCells[][] = JSON.parse(JSON.stringify(tableCells.value))
|
const _tableCells: TableCell[][] = JSON.parse(JSON.stringify(tableCells.value))
|
||||||
|
|
||||||
const hideCellsPos = []
|
const hideCellsPos = []
|
||||||
for(let i = 0; i < tableCells.value.length; i++) {
|
for(let i = 0; i < tableCells.value.length; i++) {
|
||||||
@ -292,7 +278,7 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const insertRow = (selectedIndex: number, rowIndex: number) => {
|
const insertRow = (selectedIndex: number, rowIndex: number) => {
|
||||||
const rowCells: TableCells[] = []
|
const rowCells: TableCell[] = []
|
||||||
for(let i = 0; i < tableCells.value[0].length; i++) {
|
for(let i = 0; i < tableCells.value[0].length; i++) {
|
||||||
rowCells.push({
|
rowCells.push({
|
||||||
colspan: 1,
|
colspan: 1,
|
||||||
@ -328,7 +314,7 @@ export default defineComponent({
|
|||||||
const maxX = Math.max(startX, endX)
|
const maxX = Math.max(startX, endX)
|
||||||
const maxY = Math.max(startY, endY)
|
const maxY = Math.max(startY, endY)
|
||||||
|
|
||||||
const _tableCells: TableCells[][] = JSON.parse(JSON.stringify(tableCells.value))
|
const _tableCells: TableCell[][] = JSON.parse(JSON.stringify(tableCells.value))
|
||||||
|
|
||||||
_tableCells[minX][minY].rowspan = maxX - minX + 1
|
_tableCells[minX][minY].rowspan = maxX - minX + 1
|
||||||
_tableCells[minX][minY].colspan = maxY - minY + 1
|
_tableCells[minX][minY].colspan = maxY - minY + 1
|
||||||
@ -338,7 +324,7 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const splitCells = (rowIndex: number, colIndex: number) => {
|
const splitCells = (rowIndex: number, colIndex: number) => {
|
||||||
const _tableCells: TableCells[][] = JSON.parse(JSON.stringify(tableCells.value))
|
const _tableCells: TableCell[][] = JSON.parse(JSON.stringify(tableCells.value))
|
||||||
_tableCells[rowIndex][colIndex].rowspan = 1
|
_tableCells[rowIndex][colIndex].rowspan = 1
|
||||||
_tableCells[rowIndex][colIndex].colspan = 1
|
_tableCells[rowIndex][colIndex].colspan = 1
|
||||||
|
|
||||||
@ -371,7 +357,7 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const clearSelectedCellText = () => {
|
const clearSelectedCellText = () => {
|
||||||
const _tableCells: TableCells[][] = JSON.parse(JSON.stringify(tableCells.value))
|
const _tableCells: TableCell[][] = JSON.parse(JSON.stringify(tableCells.value))
|
||||||
|
|
||||||
for(let i = 0; i < _tableCells.length; i++) {
|
for(let i = 0; i < _tableCells.length; i++) {
|
||||||
for(let j = 0; j < _tableCells[i].length; j++) {
|
for(let j = 0; j < _tableCells[i].length; j++) {
|
||||||
@ -515,6 +501,9 @@ export default defineComponent({
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleInput = debounce(function() {
|
||||||
|
emit('change', tableCells.value)
|
||||||
|
}, 300, { trailing: true })
|
||||||
|
|
||||||
return {
|
return {
|
||||||
width,
|
width,
|
||||||
@ -531,6 +520,7 @@ export default defineComponent({
|
|||||||
selectRow,
|
selectRow,
|
||||||
handleMousedownColHandler,
|
handleMousedownColHandler,
|
||||||
contextmenus,
|
contextmenus,
|
||||||
|
handleInput,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@ -559,17 +549,6 @@ table {
|
|||||||
border: 1px solid #d9d9d9;
|
border: 1px solid #d9d9d9;
|
||||||
cursor: default;
|
cursor: default;
|
||||||
|
|
||||||
&.active::after {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
bottom: 0;
|
|
||||||
right: 0;
|
|
||||||
border: 1px solid rgba($color: $themeColor, $alpha: .5);
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.selected::after {
|
&.selected::after {
|
||||||
content: '';
|
content: '';
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
@ -3,7 +3,7 @@ import { MutationTypes } from '@/store'
|
|||||||
import { createRandomCode } from '@/utils/common'
|
import { createRandomCode } from '@/utils/common'
|
||||||
import { getImageSize } from '@/utils/image'
|
import { getImageSize } from '@/utils/image'
|
||||||
import { VIEWPORT_SIZE, VIEWPORT_ASPECT_RATIO } from '@/configs/canvas'
|
import { VIEWPORT_SIZE, VIEWPORT_ASPECT_RATIO } from '@/configs/canvas'
|
||||||
import { ChartType, PPTElement, TableElementCell } from '@/types/slides'
|
import { ChartType, PPTElement, TableCell } from '@/types/slides'
|
||||||
import { ShapePoolItem } from '@/configs/shapes'
|
import { ShapePoolItem } from '@/configs/shapes'
|
||||||
import { LinePoolItem } from '@/configs/lines'
|
import { LinePoolItem } from '@/configs/lines'
|
||||||
import {
|
import {
|
||||||
@ -77,8 +77,8 @@ export default () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const createTableElement = (rowCount: number, colCount: number) => {
|
const createTableElement = (rowCount: number, colCount: number) => {
|
||||||
const row: TableElementCell[] = new Array(colCount).fill({ colspan: 1, rowspan: 1, content: '' })
|
const row: TableCell[] = new Array(colCount).fill({ colspan: 1, rowspan: 1, content: '' })
|
||||||
const data: TableElementCell[][] = new Array(rowCount).fill(row)
|
const data: TableCell[][] = new Array(rowCount).fill(row)
|
||||||
|
|
||||||
const DEFAULT_CELL_WIDTH = 80
|
const DEFAULT_CELL_WIDTH = 80
|
||||||
const DEFAULT_CELL_HEIGHT = 35
|
const DEFAULT_CELL_HEIGHT = 35
|
||||||
|
@ -136,11 +136,20 @@ export interface PPTChartElement {
|
|||||||
gridColor?: string;
|
gridColor?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TableElementCell {
|
export interface TableCell {
|
||||||
|
id: string;
|
||||||
colspan: number;
|
colspan: number;
|
||||||
rowspan: number;
|
rowspan: number;
|
||||||
content: string;
|
text: string;
|
||||||
bgColor: string;
|
style?: {
|
||||||
|
color?: string;
|
||||||
|
bgColor?: string;
|
||||||
|
fontSize?: number;
|
||||||
|
fontName?: string;
|
||||||
|
bold?: boolean;
|
||||||
|
italic?: boolean;
|
||||||
|
align?: string;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
export interface PPTTableElement {
|
export interface PPTTableElement {
|
||||||
type: 'table';
|
type: 'table';
|
||||||
@ -152,7 +161,7 @@ export interface PPTTableElement {
|
|||||||
width: number;
|
width: number;
|
||||||
height: number;
|
height: number;
|
||||||
colWidths: number[];
|
colWidths: number[];
|
||||||
data: TableElementCell[][];
|
data: TableCell[][];
|
||||||
}
|
}
|
||||||
|
|
||||||
export type PPTElement = PPTTextElement | PPTImageElement | PPTShapeElement | PPTLineElement | PPTChartElement | PPTTableElement
|
export type PPTElement = PPTTextElement | PPTImageElement | PPTShapeElement | PPTLineElement | PPTChartElement | PPTTableElement
|
||||||
|
Loading…
x
Reference in New Issue
Block a user