可编辑表格组件开发

This commit is contained in:
pipipi-pikachu 2021-01-23 10:08:37 +08:00
parent 7be29a5fc2
commit 38504b096a
4 changed files with 90 additions and 67 deletions

View File

@ -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,
} }
}, },

View File

@ -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%;

View File

@ -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

View File

@ -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