perf: 代码优化&注释

This commit is contained in:
pipipi-pikachu 2021-02-12 15:04:04 +08:00
parent d4a8d41394
commit 132c2a0afa
13 changed files with 168 additions and 149 deletions

View File

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

View File

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

View File

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

View File

@ -63,6 +63,7 @@ export default defineComponent({
cutSlide, cutSlide,
} = useSlideHandler() } = useSlideHandler()
//
const changSlideIndex = (index: number) => { const changSlideIndex = (index: number) => {
store.commit(MutationTypes.SET_ACTIVE_ELEMENT_ID_LIST, []) store.commit(MutationTypes.SET_ACTIVE_ELEMENT_ID_LIST, [])
@ -72,11 +73,13 @@ export default defineComponent({
const thumbnailsFocus = computed(() => store.state.thumbnailsFocus) const thumbnailsFocus = computed(() => store.state.thumbnailsFocus)
//
const setThumbnailsFocus = (focus: boolean) => { const setThumbnailsFocus = (focus: boolean) => {
if (thumbnailsFocus.value === focus) return if (thumbnailsFocus.value === focus) return
store.commit(MutationTypes.SET_THUMBNAILS_FOCUS, focus) store.commit(MutationTypes.SET_THUMBNAILS_FOCUS, focus)
} }
//
const handleDragEnd = (eventData: { newIndex: number; oldIndex: number }) => { const handleDragEnd = (eventData: { newIndex: number; oldIndex: number }) => {
const { newIndex, oldIndex } = eventData const { newIndex, oldIndex } = eventData
if (oldIndex === newIndex) return if (oldIndex === newIndex) return

View File

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

View File

@ -60,6 +60,7 @@ export default defineComponent({
const theme = computed(() => store.state.theme) const theme = computed(() => store.state.theme)
const currentSlide = computed<Slide>(() => store.getters.currentSlide) const currentSlide = computed<Slide>(() => store.getters.currentSlide)
//
const needWaitAnimation = computed(() => { const needWaitAnimation = computed(() => {
const animations = currentSlide.value.animations || [] const animations = currentSlide.value.animations || []
const elementIndexInAnimation = animations.findIndex(animation => animation.elId === props.elementInfo.id) const elementIndexInAnimation = animations.findIndex(animation => animation.elId === props.elementInfo.id)

View File

@ -47,28 +47,33 @@ export default defineComponent({
const writingBoardColor = ref('#e2534d') const writingBoardColor = ref('#e2534d')
const writingBoardModel = ref('pen') const writingBoardModel = ref('pen')
//
const changePen = () => { const changePen = () => {
if (!writingBoardVisible.value) writingBoardVisible.value = true if (!writingBoardVisible.value) writingBoardVisible.value = true
writingBoardModel.value = 'pen' writingBoardModel.value = 'pen'
emit('close') emit('close')
} }
//
const changeEraser = () => { const changeEraser = () => {
writingBoardModel.value = 'eraser' writingBoardModel.value = 'eraser'
emit('close') emit('close')
} }
//
const clearCanvas = () => { const clearCanvas = () => {
writingBoardRef.value.clearCanvas() writingBoardRef.value.clearCanvas()
emit('close') emit('close')
} }
//
const changeColor = (color: string) => { const changeColor = (color: string) => {
if (writingBoardModel.value !== 'pen') writingBoardModel.value = 'pen' if (writingBoardModel.value !== 'pen') writingBoardModel.value = 'pen'
writingBoardColor.value = color writingBoardColor.value = color
emit('close') emit('close')
} }
//
const closeWritingBoard = () => { const closeWritingBoard = () => {
writingBoardVisible.value = false writingBoardVisible.value = false
emit('close') emit('close')

View File

@ -92,6 +92,7 @@ export default defineComponent({
const writingBoardToolVisible = ref(false) const writingBoardToolVisible = ref(false)
//
const setSlideContentSize = () => { const setSlideContentSize = () => {
const winWidth = document.body.clientWidth const winWidth = document.body.clientWidth
const winHeight = document.body.clientHeight const winHeight = document.body.clientHeight
@ -113,6 +114,8 @@ export default defineComponent({
slideHeight.value = height slideHeight.value = height
} }
//
// 退
const { exitScreening } = useScreening() const { exitScreening } = useScreening()
const windowResizeListener = () => { const windowResizeListener = () => {
@ -120,9 +123,18 @@ export default defineComponent({
if (!isFullscreen()) exitScreening() if (!isFullscreen()) exitScreening()
} }
const animationIndex = ref(0) onMounted(() => {
const animations = computed(() => currentSlide.value.animations || []) window.addEventListener('resize', windowResizeListener)
})
onUnmounted(() => {
window.removeEventListener('resize', windowResizeListener)
})
//
const animations = computed(() => currentSlide.value.animations || [])
const animationIndex = ref(0)
//
const runAnimation = () => { const runAnimation = () => {
const prefix = 'animate__' const prefix = 'animate__'
const animation = animations.value[animationIndex.value] const animation = animations.value[animationIndex.value]
@ -140,6 +152,9 @@ export default defineComponent({
} }
} }
// /
//
//
const execPrev = () => { const execPrev = () => {
if (animations.value.length && animationIndex.value > 0) { if (animations.value.length && animationIndex.value > 0) {
animationIndex.value -= 1 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 keydownListener = (e: KeyboardEvent) => {
const key = e.key.toUpperCase() const key = e.key.toUpperCase()
if (key === KEYS.UP || key === KEYS.LEFT) execPrev() if (key === KEYS.UP || key === KEYS.LEFT) execPrev()
@ -171,20 +193,14 @@ export default defineComponent({
) execNext() ) execNext()
} }
const mousewheelListener = throttle(function(e: WheelEvent) {
if (e.deltaY < 0) execPrev()
else if (e.deltaY > 0) execNext()
}, 500, { leading: true, trailing: false })
onMounted(() => { onMounted(() => {
window.addEventListener('resize', windowResizeListener)
document.addEventListener('keydown', keydownListener) document.addEventListener('keydown', keydownListener)
}) })
onUnmounted(() => { onUnmounted(() => {
window.removeEventListener('resize', windowResizeListener)
document.removeEventListener('keydown', keydownListener) document.removeEventListener('keydown', keydownListener)
}) })
// /
const turnPrevSlide = () => { const turnPrevSlide = () => {
store.commit(MutationTypes.UPDATE_SLIDE_INDEX, slideIndex.value - 1) store.commit(MutationTypes.UPDATE_SLIDE_INDEX, slideIndex.value - 1)
animationIndex.value = 0 animationIndex.value = 0
@ -194,6 +210,7 @@ export default defineComponent({
animationIndex.value = 0 animationIndex.value = 0
} }
//
const turnSlideToIndex = (index: number) => { const turnSlideToIndex = (index: number) => {
slideThumbnailModelVisible.value = false slideThumbnailModelVisible.value = false
store.commit(MutationTypes.UPDATE_SLIDE_INDEX, index) store.commit(MutationTypes.UPDATE_SLIDE_INDEX, index)

View File

@ -71,12 +71,14 @@
<script lang="ts"> <script lang="ts">
import { computed, defineComponent, nextTick, onMounted, onUnmounted, PropType, ref, watch } from 'vue' import { computed, defineComponent, nextTick, onMounted, onUnmounted, PropType, ref, watch } from 'vue'
import debounce from 'lodash/debounce' import debounce from 'lodash/debounce'
import tinycolor from 'tinycolor2'
import { useStore } from '@/store' 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 { ContextmenuItem } from '@/components/Contextmenu/types'
import { KEYS } from '@/configs/hotkey' import { KEYS } from '@/configs/hotkey'
import { createRandomCode } from '@/utils/common' import { createRandomCode } from '@/utils/common'
import { getTextStyle } from './utils'
import useHideCells from './useHideCells'
import useSubThemeColor from './useSubThemeColor'
import CustomTextarea from './CustomTextarea.vue' import CustomTextarea from './CustomTextarea.vue'
@ -127,19 +129,9 @@ export default defineComponent({
}, },
}) })
// //
const subThemeColor = ref(['', '']) const theme = computed(() => props.theme)
watch(() => props.theme, () => { const { subThemeColor } = useSubThemeColor(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 colSizeList = ref<number[]>([]) const colSizeList = ref<number[]>([])
@ -173,26 +165,8 @@ export default defineComponent({
}) })
// //
const hideCells = computed(() => { const cells = computed(() => props.data)
const hideCells = [] const { hideCells } = useHideCells(cells)
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 selectedCells = computed(() => { const selectedCells = computed(() => {
@ -526,33 +500,6 @@ export default defineComponent({
document.removeEventListener('keydown', keydownListener) 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() { const handleInput = debounce(function() {
emit('change', tableCells.value) emit('change', tableCells.value)

View File

@ -45,8 +45,10 @@
<script lang="ts"> <script lang="ts">
import { computed, defineComponent, PropType, ref, watch } from 'vue' import { computed, defineComponent, PropType, ref, watch } from 'vue'
import tinycolor from 'tinycolor2' import { PPTElementOutline, TableCell, TableTheme } from '@/types/slides'
import { PPTElementOutline, TableCell, TableCellStyle, TableTheme } from '@/types/slides' import { getTextStyle } from './utils'
import useHideCells from './useHideCells'
import useSubThemeColor from './useSubThemeColor'
export default defineComponent({ export default defineComponent({
name: 'static-table', name: 'static-table',
@ -86,65 +88,11 @@ export default defineComponent({
colSizeList.value = props.colWidths.map(item => item * props.width) colSizeList.value = props.colWidths.map(item => item * props.width)
}, { immediate: true }) }, { immediate: true })
const hideCells = computed(() => { const cells = computed(() => props.data)
const hideCells = [] const { hideCells } = useHideCells(cells)
for (let i = 0; i < props.data.length; i++) {
const rowCells = props.data[i]
for (let j = 0; j < rowCells.length; j++) { const theme = computed(() => props.theme)
const cell = rowCells[j] const { subThemeColor } = useSubThemeColor(theme)
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',
}
}
return { return {
colSizeList, colSizeList,

View File

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

View File

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

View File

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