mirror of
https://github.com/pipipi-pikachu/PPTist.git
synced 2025-04-15 02:20:00 +08:00
perf: 代码优化&注释
This commit is contained in:
parent
d4a8d41394
commit
132c2a0afa
@ -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()
|
@ -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))
|
||||||
}
|
}
|
@ -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',
|
||||||
|
@ -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
|
||||||
|
@ -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()
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -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)
|
||||||
|
@ -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')
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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,
|
||||||
|
31
src/views/components/element/TableElement/useHideCells.ts
Normal file
31
src/views/components/element/TableElement/useHideCells.ts
Normal 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,
|
||||||
|
}
|
||||||
|
}
|
@ -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
src/views/components/element/TableElement/utils.ts
Normal file
31
src/views/components/element/TableElement/utils.ts
Normal 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',
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user