فهرست منبع

可编辑表格组件开发

pipipi-pikachu 5 سال پیش
والد
کامیت
38504b096a
4فایلهای تغییر یافته به همراه90 افزوده شده و 67 حذف شده
  1. 37 2
      src/App.vue
  2. 37 58
      src/components/EditableTable.vue
  3. 3 3
      src/hooks/useCreateElement.ts
  4. 13 4
      src/types/slides.ts

+ 37 - 2
src/App.vue

@@ -3,14 +3,18 @@
   <Screen v-else />
 
   <div class="test">
-    <EditableTable />
+    <EditableTable 
+      :data="tableCells"
+      @change="data => updateTableCells(data)"
+    />
   </div>
 </template>
 
 <script lang="ts">
-import { computed, defineComponent, onMounted } from 'vue'
+import { computed, defineComponent, onMounted, ref } from 'vue'
 import { useStore } from 'vuex'
 import { MutationTypes, ActionTypes, State } from '@/store'
+import { TableCell } from './types/slides'
 
 import Editor from './views/Editor/index.vue'
 import Screen from './views/Screen/index.vue'
@@ -27,12 +31,43 @@ export default defineComponent({
     const store = useStore<State>()
     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(() => {
       store.commit(MutationTypes.SET_AVAILABLE_FONTS)
       store.dispatch(ActionTypes.INIT_SNAPSHOT_DATABASE)
     })
 
     return {
+      tableCells,
+      updateTableCells,
       screening,
     }
   },

+ 37 - 58
src/components/EditableTable.vue

@@ -44,6 +44,7 @@
               :class="{ 'active': activedCell === `${rowIndex}_${colIndex}` }"
               :contenteditable="activedCell === `${rowIndex}_${colIndex}` ? 'plaintext-only' : false"
               v-model="cell.text"
+              @update:modelValue="handleInput()"
             />
           </td>
         </tr>
@@ -54,28 +55,14 @@
 
 <script lang="ts">
 import { computed, defineComponent, nextTick, onMounted, onUnmounted, PropType, ref } from 'vue'
+import debounce from 'lodash/debounce'
 import { ContextmenuItem } from './Contextmenu/types'
+import { TableCell } from '@/types/slides'
 import { KEYS } from '@/configs/hotkey'
 import { createRandomCode } from '@/utils/common'
 
 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({
   name: 'editable-table',
   components: {
@@ -83,33 +70,32 @@ export default defineComponent({
   },
   props: {
     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() {
-    const tableCells = ref<TableCells[][]>([
-      [
-        { 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: '' },
-      ],
-    ])
+  setup(props, { emit }) {
+    const tableCells = computed<TableCell[][]>({
+      get() {
+        return props.data
+      },
+      set(newData) {
+        emit('change', newData)
+      },
+    })
+    
     const colWidths = ref([160, 160, 160, 160, 160])
     const isStartSelect = ref(false)
     const startCell = ref<number[]>([])
@@ -246,7 +232,7 @@ export default defineComponent({
     }
 
     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 hideCellsPos = []
@@ -268,7 +254,7 @@ export default defineComponent({
     }
 
     const deleteCol = (colIndex: number) => {
-      const _tableCells: TableCells[][] = JSON.parse(JSON.stringify(tableCells.value))
+      const _tableCells: TableCell[][] = JSON.parse(JSON.stringify(tableCells.value))
 
       const hideCellsPos = []
       for(let i = 0; i < tableCells.value.length; i++) {
@@ -292,7 +278,7 @@ export default defineComponent({
     }
     
     const insertRow = (selectedIndex: number, rowIndex: number) => {
-      const rowCells: TableCells[] = []
+      const rowCells: TableCell[] = []
       for(let i = 0; i < tableCells.value[0].length; i++) {
         rowCells.push({
           colspan: 1,
@@ -328,7 +314,7 @@ export default defineComponent({
       const maxX = Math.max(startX, endX)
       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].colspan = maxY - minY + 1
@@ -338,7 +324,7 @@ export default defineComponent({
     }
 
     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].colspan = 1
 
@@ -371,7 +357,7 @@ export default defineComponent({
     }
 
     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 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 {
       width,
@@ -531,6 +520,7 @@ export default defineComponent({
       selectRow,
       handleMousedownColHandler,
       contextmenus,
+      handleInput,
     }
   },
 })
@@ -559,17 +549,6 @@ table {
     border: 1px solid #d9d9d9;
     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 {
       content: '';
       width: 100%;

+ 3 - 3
src/hooks/useCreateElement.ts

@@ -3,7 +3,7 @@ import { MutationTypes } from '@/store'
 import { createRandomCode } from '@/utils/common'
 import { getImageSize } from '@/utils/image'
 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 { LinePoolItem } from '@/configs/lines'
 import {
@@ -77,8 +77,8 @@ export default () => {
   }
   
   const createTableElement = (rowCount: number, colCount: number) => {
-    const row: TableElementCell[] = new Array(colCount).fill({ colspan: 1, rowspan: 1, content: '' })
-    const data: TableElementCell[][] = new Array(rowCount).fill(row)
+    const row: TableCell[] = new Array(colCount).fill({ colspan: 1, rowspan: 1, content: '' })
+    const data: TableCell[][] = new Array(rowCount).fill(row)
   
     const DEFAULT_CELL_WIDTH = 80
     const DEFAULT_CELL_HEIGHT = 35

+ 13 - 4
src/types/slides.ts

@@ -136,11 +136,20 @@ export interface PPTChartElement {
   gridColor?: string;
 }
 
-export interface TableElementCell {
+export interface TableCell {
+  id: string;
   colspan: number;
   rowspan: number;
-  content: string;
-  bgColor: string;
+  text: string;
+  style?: {
+    color?: string;
+    bgColor?: string;
+    fontSize?: number;
+    fontName?: string;
+    bold?: boolean;
+    italic?: boolean;
+    align?: string;
+  };
 }
 export interface PPTTableElement {
   type: 'table';
@@ -152,7 +161,7 @@ export interface PPTTableElement {
   width: number;
   height: number;
   colWidths: number[];
-  data: TableElementCell[][];
+  data: TableCell[][];
 }
 
 export type PPTElement = PPTTextElement | PPTImageElement | PPTShapeElement | PPTLineElement | PPTChartElement | PPTTableElement