Browse Source

perf: 代码优化&注释

pipipi-pikachu 5 years atrás
parent
commit
132c2a0afa

+ 11 - 11
src/views/Editor/useHotkey.ts

@@ -4,17 +4,17 @@ import { ElementOrderCommand, ElementOrderCommands } from '@/types/edit'
 import { PPTElement } from '@/types/slides'
 import { KEYS } from '@/configs/hotkey'
 
-import useSlideHandler from '@/hooks/useSlideHandler'
-import useLockElement from '@/hooks/useLockElement'
-import useDeleteElement from '@/hooks/useDeleteElement'
-import useCombineElement from '@/hooks/useCombineElement'
-import useCopyAndPasteElement from '@/hooks/useCopyAndPasteElement'
-import useSelectAllElement from '@/hooks/useSelectAllElement'
-import useMoveElement from '@/hooks/useMoveElement'
-import useOrderElement from '@/hooks/useOrderElement'
-import useHistorySnapshot from '@/hooks/useHistorySnapshot'
-import useScreening from '@/hooks/useScreening'
-import useScaleCanvas from '@/hooks/useScaleCanvas'
+import useSlideHandler from './useSlideHandler'
+import useLockElement from './useLockElement'
+import useDeleteElement from './useDeleteElement'
+import useCombineElement from './useCombineElement'
+import useCopyAndPasteElement from './useCopyAndPasteElement'
+import useSelectAllElement from './useSelectAllElement'
+import useMoveElement from './useMoveElement'
+import useOrderElement from './useOrderElement'
+import useHistorySnapshot from './useHistorySnapshot'
+import useScreening from './useScreening'
+import useScaleCanvas from './useScaleCanvas'
 
 export default () => {
   const store = useStore()

+ 10 - 3
src/views/Editor/usePasteEvent.ts

@@ -1,8 +1,8 @@
 import { computed, onMounted, onUnmounted } from 'vue'
 import { useStore } from '@/store'
 import { getImageDataURL } from '@/utils/image'
-import usePasteTextClipboardData from '@/hooks/usePasteTextClipboardData'
-import useCreateElement from '@/hooks/useCreateElement'
+import usePasteTextClipboardData from './usePasteTextClipboardData'
+import useCreateElement from './useCreateElement'
 
 export default () => {
   const store = useStore()
@@ -13,10 +13,15 @@ export default () => {
   const { pasteTextClipboardData } = usePasteTextClipboardData()
   const { createImageElement } = useCreateElement()
 
+  // 粘贴图片到幻灯片元素
   const pasteImageFile = (imageFile: File) => {
     getImageDataURL(imageFile).then(dataURL => createImageElement(dataURL))
   }
 
+  /**
+   * 粘贴事件监听
+   * @param e ClipboardEvent
+   */
   const pasteListener = (e: ClipboardEvent) => {
     if (!editorAreaFocus.value && !thumbnailsFocus.value) return
     if (disableHotkeys.value) return
@@ -28,6 +33,7 @@ export default () => {
 
     if (!clipboardDataFirstItem) return
 
+    // 如果剪贴板内有图片,优先尝试读取图片
     for (const item of clipboardDataItems) {
       if (item.kind === 'file' && item.type.indexOf('image') !== -1) {
         const imageFile = item.getAsFile()
@@ -35,7 +41,8 @@ export default () => {
         return
       }
     }
-
+    
+    // 如果剪贴板内没有图片,但有文字内容,尝试解析文字内容
     if (clipboardDataFirstItem.kind === 'string' && clipboardDataFirstItem.type === 'text/plain') {
       clipboardDataFirstItem.getAsString(text => pasteTextClipboardData(text))
     }

+ 5 - 0
src/views/Editor/CanvasTool/index.vue

@@ -113,12 +113,15 @@ export default defineComponent({
     const chartPoolVisible = ref(false)
     const tableGeneratorVisible = ref(false)
 
+    // 绘制文字范围
     const drawText = () => {
       store.commit(MutationTypes.SET_CREATING_ELEMENT, {
         type: 'text',
         data: null,
       })
     }
+
+    // 绘制形状范围
     const drawShape = (shape: ShapePoolItem) => {
       store.commit(MutationTypes.SET_CREATING_ELEMENT, {
         type: 'shape',
@@ -126,6 +129,8 @@ export default defineComponent({
       })
       shapePoolVisible.value = false
     }
+
+    // 绘制线条路径
     const drawLine = (line: LinePoolItem) => {
       store.commit(MutationTypes.SET_CREATING_ELEMENT, {
         type: 'line',

+ 3 - 0
src/views/Editor/Thumbnails/index.vue

@@ -63,6 +63,7 @@ export default defineComponent({
       cutSlide,
     } = useSlideHandler()
 
+    // 切换页面
     const changSlideIndex = (index: number) => {
       store.commit(MutationTypes.SET_ACTIVE_ELEMENT_ID_LIST, [])
 
@@ -72,11 +73,13 @@ export default defineComponent({
 
     const thumbnailsFocus = computed(() => store.state.thumbnailsFocus)
 
+    // 设置缩略图工具栏聚焦状态(只有聚焦状态下,该部分的快捷键才能生效)
     const setThumbnailsFocus = (focus: boolean) => {
       if (thumbnailsFocus.value === focus) return
       store.commit(MutationTypes.SET_THUMBNAILS_FOCUS, focus)
     }
 
+    // 拖拽调整顺序后进行数据的同步
     const handleDragEnd = (eventData: { newIndex: number; oldIndex: number }) => {
       const { newIndex, oldIndex } = eventData
       if (oldIndex === newIndex) return

+ 3 - 3
src/views/Editor/index.vue

@@ -15,8 +15,8 @@
 <script lang="ts">
 import { defineComponent } from 'vue'
 
-import useHotkey from './useHotkey'
-import usePasteEvent from './usePasteEvent'
+import useGlobalHotkey from '@/hooks/useGlobalHotkey'
+import usePasteEvent from '@/hooks/usePasteEvent'
 
 import EditorHeader from './EditorHeader/index.vue'
 import Canvas from './Canvas/index.vue'
@@ -34,7 +34,7 @@ export default defineComponent({
     Toolbar,
   },
   setup() {
-    useHotkey()
+    useGlobalHotkey()
     usePasteEvent()
   },
 })

+ 1 - 0
src/views/Screen/ScreenElement.vue

@@ -60,6 +60,7 @@ export default defineComponent({
     const theme = computed(() => store.state.theme)
     const currentSlide = computed<Slide>(() => store.getters.currentSlide)
 
+    // 判断元素是否需要等待执行入场动画:等待执行的元素需要先隐藏
     const needWaitAnimation = computed(() => {
       const animations = currentSlide.value.animations || []
       const elementIndexInAnimation = animations.findIndex(animation => animation.elId === props.elementInfo.id)

+ 6 - 1
src/views/Screen/WritingBoardTool.vue

@@ -47,28 +47,33 @@ export default defineComponent({
     const writingBoardColor = ref('#e2534d')
     const writingBoardModel = ref('pen')
 
+    // 切换到画笔状态
     const changePen = () => {
       if (!writingBoardVisible.value) writingBoardVisible.value = true
       writingBoardModel.value = 'pen'
       emit('close')
     }
 
+    // 切换到橡皮状态
     const changeEraser = () => {
       writingBoardModel.value = 'eraser'
       emit('close')
     }
 
+    // 清除画布上的墨迹
     const clearCanvas = () => {
       writingBoardRef.value.clearCanvas()
       emit('close')
     }
 
+    // 修改画笔颜色,如果当前不处于画笔状态则先切换到画笔状态
     const changeColor = (color: string) => {
       if (writingBoardModel.value !== 'pen') writingBoardModel.value = 'pen'
       writingBoardColor.value = color
       emit('close')
     }
-
+    
+    // 关闭写字板
     const closeWritingBoard = () => {
       writingBoardVisible.value = false
       emit('close')

+ 25 - 8
src/views/Screen/index.vue

@@ -92,6 +92,7 @@ export default defineComponent({
 
     const writingBoardToolVisible = ref(false)
 
+    // 计算和更新幻灯片内容的尺寸(按比例自适应屏幕)
     const setSlideContentSize = () => {
       const winWidth = document.body.clientWidth
       const winHeight = document.body.clientHeight
@@ -113,6 +114,8 @@ export default defineComponent({
       slideHeight.value = height
     }
 
+    // 窗口尺寸变化监听:窗口发生变化时更新幻灯片的大小
+    // 如果退出了全屏,需要返回到编辑模式
     const { exitScreening } = useScreening()
 
     const windowResizeListener = () => {
@@ -120,9 +123,18 @@ export default defineComponent({
       if (!isFullscreen()) exitScreening()
     }
 
-    const animationIndex = ref(0)
+    onMounted(() => {
+      window.addEventListener('resize', windowResizeListener)
+    })
+    onUnmounted(() => {
+      window.removeEventListener('resize', windowResizeListener)
+    })
+
+    // 当前页的元素动画列表和当前执行到的位置
     const animations = computed(() => currentSlide.value.animations || [])
+    const animationIndex = ref(0)
 
+    // 执行元素的入场动画
     const runAnimation = () => {
       const prefix = 'animate__'
       const animation = animations.value[animationIndex.value]
@@ -140,6 +152,9 @@ export default defineComponent({
       }
     }
 
+    // 向上/向下播放
+    // 遇到元素动画时,优先执行动画播放,无动画则执行翻页
+    // 向上播放遇到动画时,仅撤销到动画执行前的状态,不需要反向播放动画
     const execPrev = () => {
       if (animations.value.length && animationIndex.value > 0) {
         animationIndex.value -= 1
@@ -160,6 +175,13 @@ export default defineComponent({
       }
     }
 
+    // 鼠标滚动翻页
+    const mousewheelListener = throttle(function(e: WheelEvent) {
+      if (e.deltaY < 0) execPrev()
+      else if (e.deltaY > 0) execNext()
+    }, 500, { leading: true, trailing: false })
+
+    // 快捷键翻页
     const keydownListener = (e: KeyboardEvent) => {
       const key = e.key.toUpperCase()
       if (key === KEYS.UP || key === KEYS.LEFT) execPrev()
@@ -171,20 +193,14 @@ export default defineComponent({
       ) execNext()
     }
 
-    const mousewheelListener = throttle(function(e: WheelEvent) {
-      if (e.deltaY < 0) execPrev()
-      else if (e.deltaY > 0) execNext()
-    }, 500, { leading: true, trailing: false })
-
     onMounted(() => {
-      window.addEventListener('resize', windowResizeListener)
       document.addEventListener('keydown', keydownListener)
     })
     onUnmounted(() => {
-      window.removeEventListener('resize', windowResizeListener)
       document.removeEventListener('keydown', keydownListener)
     })
 
+    // 切换到上一张/上一张幻灯片(无视元素的入场动画)
     const turnPrevSlide = () => {
       store.commit(MutationTypes.UPDATE_SLIDE_INDEX, slideIndex.value - 1)
       animationIndex.value = 0
@@ -194,6 +210,7 @@ export default defineComponent({
       animationIndex.value = 0
     }
 
+    // 切换幻灯片到指定的页面
     const turnSlideToIndex = (index: number) => {
       slideThumbnailModelVisible.value = false
       store.commit(MutationTypes.UPDATE_SLIDE_INDEX, index)

+ 9 - 62
src/views/components/element/TableElement/EditableTable.vue

@@ -71,12 +71,14 @@
 <script lang="ts">
 import { computed, defineComponent, nextTick, onMounted, onUnmounted, PropType, ref, watch } from 'vue'
 import debounce from 'lodash/debounce'
-import tinycolor from 'tinycolor2'
 import { useStore } from '@/store'
-import { PPTElementOutline, TableCell, TableCellStyle, TableTheme } from '@/types/slides'
+import { PPTElementOutline, TableCell, TableTheme } from '@/types/slides'
 import { ContextmenuItem } from '@/components/Contextmenu/types'
 import { KEYS } from '@/configs/hotkey'
 import { createRandomCode } from '@/utils/common'
+import { getTextStyle } from './utils'
+import useHideCells from './useHideCells'
+import useSubThemeColor from './useSubThemeColor'
 
 import CustomTextarea from './CustomTextarea.vue'
 
@@ -127,19 +129,9 @@ export default defineComponent({
       },
     })
 
-    // 通过表格的主题色计算辅助颜色
-    const subThemeColor = ref(['', ''])
-    watch(() => props.theme, () => {
-      if (props.theme) {
-        const rgba = tinycolor(props.theme.color).toRgb()
-        const subRgba1 = { r: rgba.r, g: rgba.g, b: rgba.b, a: rgba.a * 0.3 }
-        const subRgba2 = { r: rgba.r, g: rgba.g, b: rgba.b, a: rgba.a * 0.1 }
-        subThemeColor.value = [
-          `rgba(${[subRgba1.r, subRgba1.g, subRgba1.b, subRgba1.a].join(',')})`,
-          `rgba(${[subRgba2.r, subRgba2.g, subRgba2.b, subRgba2.a].join(',')})`,
-        ]
-      }
-    }, { immediate: true })
+    // 主题辅助色
+    const theme = computed(() => props.theme)
+    const { subThemeColor } = useSubThemeColor(theme)
 
     // 计算表格每一列的列宽和总宽度
     const colSizeList = ref<number[]>([])
@@ -173,26 +165,8 @@ export default defineComponent({
     })
 
     // 无效的单元格位置(被合并的单元格位置)集合
-    const hideCells = computed(() => {
-      const hideCells = []
-      
-      for (let i = 0; i < tableCells.value.length; i++) {
-        const rowCells = tableCells.value[i]
-
-        for (let j = 0; j < rowCells.length; j++) {
-          const cell = rowCells[j]
-          
-          if (cell.colspan > 1 || cell.rowspan > 1) {
-            for (let row = i; row < i + cell.rowspan; row++) {
-              for (let col = row === i ? j + 1 : j; col < j + cell.colspan; col++) {
-                hideCells.push(`${row}_${col}`)
-              }
-            }
-          }
-        }
-      }
-      return hideCells
-    })
+    const cells = computed(() => props.data)
+    const { hideCells } = useHideCells(cells)
 
     // 当前选中的单元格集合
     const selectedCells = computed(() => {
@@ -526,33 +500,6 @@ export default defineComponent({
       document.removeEventListener('keydown', keydownListener)
     })
 
-    // 计算单元格文本样式
-    const getTextStyle = (style?: TableCellStyle) => {
-      if (!style) return {}
-      const {
-        bold,
-        em,
-        underline,
-        strikethrough,
-        color,
-        backcolor,
-        fontsize,
-        fontname,
-        align,
-      } = style
-      
-      return {
-        fontWeight: bold ? 'bold' : 'normal',
-        fontStyle: em ? 'italic' : 'normal',
-        textDecoration: `${underline ? 'underline' : ''} ${strikethrough ? 'line-through' : ''}`,
-        color: color || '#000',
-        backgroundColor: backcolor || '',
-        fontSize: fontsize || '14px',
-        fontFamily: fontname || '微软雅黑',
-        textAlign: align || 'left',
-      }
-    }
-
     // 单元格文字输入时更新表格数据
     const handleInput = debounce(function() {
       emit('change', tableCells.value)

+ 8 - 60
src/views/components/element/TableElement/StaticTable.vue

@@ -45,8 +45,10 @@
 
 <script lang="ts">
 import { computed, defineComponent, PropType, ref, watch } from 'vue'
-import tinycolor from 'tinycolor2'
-import { PPTElementOutline, TableCell, TableCellStyle, TableTheme } from '@/types/slides'
+import { PPTElementOutline, TableCell, TableTheme } from '@/types/slides'
+import { getTextStyle } from './utils'
+import useHideCells from './useHideCells'
+import useSubThemeColor from './useSubThemeColor'
 
 export default defineComponent({
   name: 'static-table',
@@ -86,65 +88,11 @@ export default defineComponent({
       colSizeList.value = props.colWidths.map(item => item * props.width)
     }, { immediate: true })
 
-    const hideCells = computed(() => {
-      const hideCells = []
-      
-      for (let i = 0; i < props.data.length; i++) {
-        const rowCells = props.data[i]
+    const cells = computed(() => props.data)
+    const { hideCells } = useHideCells(cells)
 
-        for (let j = 0; j < rowCells.length; j++) {
-          const cell = rowCells[j]
-          
-          if (cell.colspan > 1 || cell.rowspan > 1) {
-            for (let row = i; row < i + cell.rowspan; row++) {
-              for (let col = row === i ? j + 1 : j; col < j + cell.colspan; col++) {
-                hideCells.push(`${row}_${col}`)
-              }
-            }
-          }
-        }
-      }
-      return hideCells
-    })
-
-    const subThemeColor = ref(['', ''])
-    watch(() => props.theme, () => {
-      if (props.theme) {
-        const rgba = tinycolor(props.theme.color).toRgb()
-        const subRgba1 = { r: rgba.r, g: rgba.g, b: rgba.b, a: rgba.a * 0.3 }
-        const subRgba2 = { r: rgba.r, g: rgba.g, b: rgba.b, a: rgba.a * 0.1 }
-        subThemeColor.value = [
-          `rgba(${[subRgba1.r, subRgba1.g, subRgba1.b, subRgba1.a].join(',')})`,
-          `rgba(${[subRgba2.r, subRgba2.g, subRgba2.b, subRgba2.a].join(',')})`,
-        ]
-      }
-    }, { immediate: true })
-
-    const getTextStyle = (style?: TableCellStyle) => {
-      if (!style) return {}
-      const {
-        bold,
-        em,
-        underline,
-        strikethrough,
-        color,
-        backcolor,
-        fontsize,
-        fontname,
-        align,
-      } = style
-      
-      return {
-        fontWeight: bold ? 'bold' : 'normal',
-        fontStyle: em ? 'italic' : 'normal',
-        textDecoration: `${underline ? 'underline' : ''} ${strikethrough ? 'line-through' : ''}`,
-        color: color || '#000',
-        backgroundColor: backcolor || '',
-        fontSize: fontsize || '14px',
-        fontFamily: fontname || '微软雅黑',
-        textAlign: align || 'left',
-      }
-    }
+    const theme = computed(() => props.theme)
+    const { subThemeColor } = useSubThemeColor(theme)
 
     return {
       colSizeList,

+ 31 - 0
src/views/components/element/TableElement/useHideCells.ts

@@ -0,0 +1,31 @@
+import { computed, Ref } from 'vue'
+import { TableCell } from '@/types/slides'
+
+// 计算无效的单元格位置(被合并的单元格位置)集合
+
+export default (cells: Ref<TableCell[][]>) => {
+  const hideCells = computed(() => {
+    const hideCells = []
+    
+    for (let i = 0; i < cells.value.length; i++) {
+      const rowCells = cells.value[i]
+
+      for (let j = 0; j < rowCells.length; j++) {
+        const cell = rowCells[j]
+        
+        if (cell.colspan > 1 || cell.rowspan > 1) {
+          for (let row = i; row < i + cell.rowspan; row++) {
+            for (let col = row === i ? j + 1 : j; col < j + cell.colspan; col++) {
+              hideCells.push(`${row}_${col}`)
+            }
+          }
+        }
+      }
+    }
+    return hideCells
+  })
+
+  return {
+    hideCells,
+  }
+}

+ 24 - 0
src/views/components/element/TableElement/useSubThemeColor.ts

@@ -0,0 +1,24 @@
+import { ref, Ref, watch } from 'vue'
+import tinycolor from 'tinycolor2'
+import { TableTheme } from '@/types/slides'
+
+// 通过表格的主题色计算辅助颜色
+
+export default (theme: Ref<TableTheme | undefined>) => {
+  const subThemeColor = ref(['', ''])
+  watch(() => theme.value, () => {
+    if (theme.value) {
+      const rgba = tinycolor(theme.value.color).toRgb()
+      const subRgba1 = { r: rgba.r, g: rgba.g, b: rgba.b, a: rgba.a * 0.3 }
+      const subRgba2 = { r: rgba.r, g: rgba.g, b: rgba.b, a: rgba.a * 0.1 }
+      subThemeColor.value = [
+        `rgba(${[subRgba1.r, subRgba1.g, subRgba1.b, subRgba1.a].join(',')})`,
+        `rgba(${[subRgba2.r, subRgba2.g, subRgba2.b, subRgba2.a].join(',')})`,
+      ]
+    }
+  }, { immediate: true })
+
+  return {
+    subThemeColor,
+  }
+}

+ 31 - 0
src/views/components/element/TableElement/utils.ts

@@ -0,0 +1,31 @@
+import { TableCellStyle } from '@/types/slides'
+
+/**
+ * 计算单元格文本样式
+ * @param style 单元格文本样式原数据
+ */
+export const getTextStyle = (style?: TableCellStyle) => {
+  if (!style) return {}
+  const {
+    bold,
+    em,
+    underline,
+    strikethrough,
+    color,
+    backcolor,
+    fontsize,
+    fontname,
+    align,
+  } = style
+  
+  return {
+    fontWeight: bold ? 'bold' : 'normal',
+    fontStyle: em ? 'italic' : 'normal',
+    textDecoration: `${underline ? 'underline' : ''} ${strikethrough ? 'line-through' : ''}`,
+    color: color || '#000',
+    backgroundColor: backcolor || '',
+    fontSize: fontsize || '14px',
+    fontFamily: fontname || '微软雅黑',
+    textAlign: align || 'left',
+  }
+}