diff --git a/src/configs/hotkey.ts b/src/configs/hotkey.ts index 7115091b..d6d51d5e 100644 --- a/src/configs/hotkey.ts +++ b/src/configs/hotkey.ts @@ -35,6 +35,7 @@ export const HOTKEY_DOC = [ { label: '撤销', value: 'Ctrl + Z' }, { label: '恢复', value: 'Ctrl + Y' }, { label: '删除', value: 'Delete / Backspace' }, + { label: '多选', value: '按住 Ctrl 或 Shift' }, ], }, { @@ -67,7 +68,6 @@ export const HOTKEY_DOC = [ { label: '取消组合', value: 'Ctrl + Shift + G' }, { label: '置顶层', value: 'Alt + F' }, { label: '置底层', value: 'Alt + B' }, - { label: '多选', value: '按住 Ctrl 或 Shift' }, { label: '锁定宽高比例', value: '按住 Ctrl 或 Shift' }, { label: '创建水平 / 垂直线条', value: '按住 Ctrl 或 Shift' }, { label: '确认图片裁剪', value: 'Enter' }, diff --git a/src/hooks/usePasteTextClipboardData.ts b/src/hooks/usePasteTextClipboardData.ts index 4ff66d11..8d7100a4 100644 --- a/src/hooks/usePasteTextClipboardData.ts +++ b/src/hooks/usePasteTextClipboardData.ts @@ -55,11 +55,12 @@ export default () => { * 粘贴页面 * @param slide 页面数据 */ - const pasteSlide = (slide: Slide) => { - store.commit(MutationTypes.ADD_SLIDE, { + const pasteSlides = (slides: Slide[]) => { + const newSlides = slides.map(slide => ({ ...slide, id: createRandomCode(8), - }) + })) + store.commit(MutationTypes.ADD_SLIDE, newSlides) addHistorySnapshot() } @@ -98,7 +99,7 @@ export default () => { const { type, data } = clipboardData if (type === 'elements' && !onlySlide) pasteElement(data) - else if (type === 'slide' && !onlyElements) pasteSlide(data) + else if (type === 'slides' && !onlyElements) pasteSlides(data) } // 普通文本 diff --git a/src/hooks/useSlideHandler.ts b/src/hooks/useSlideHandler.ts index 739e3bf1..b95c06c0 100644 --- a/src/hooks/useSlideHandler.ts +++ b/src/hooks/useSlideHandler.ts @@ -13,12 +13,26 @@ export default () => { const store = useStore() const slideIndex = computed(() => store.state.slideIndex) const theme = computed(() => store.state.theme) - const slidesLength = computed(() => store.state.slides.length) + const slides = computed(() => store.state.slides) const currentSlide = computed(() => store.getters.currentSlide) + const selectedSlidesIndex = computed(() => [...store.state.selectedSlidesIndex, slideIndex.value]) + const selectedSlides = computed(() => slides.value.filter((item, index) => selectedSlidesIndex.value.includes(index))) + const selectedSlidesId = computed(() => selectedSlides.value.map(item => item.id)) + const { pasteTextClipboardData } = usePasteTextClipboardData() const { addHistorySnapshot } = useHistorySnapshot() + // 重置幻灯片 + const resetSlides = () => { + store.commit(MutationTypes.UPDATE_SLIDE_INDEX, 0) + store.commit(MutationTypes.SET_ACTIVE_ELEMENT_ID_LIST, []) + store.commit(MutationTypes.SET_SLIDES, [{ + id: createRandomCode(), + elements: [], + }]) + } + /** * 移动页面焦点 * @param command 移动页面焦点命令:上移、下移 @@ -28,7 +42,7 @@ export default () => { if (command === KEYS.UP && slideIndex.value > 0) { targetIndex = slideIndex.value - 1 } - else if (command === KEYS.DOWN && slideIndex.value < slidesLength.value - 1) { + else if (command === KEYS.DOWN && slideIndex.value < slides.value.length - 1) { targetIndex = slideIndex.value + 1 } store.commit(MutationTypes.UPDATE_SLIDE_INDEX, targetIndex) @@ -37,8 +51,8 @@ export default () => { // 将当前页面数据加密后复制到剪贴板 const copySlide = () => { const text = encrypt(JSON.stringify({ - type: 'slide', - data: currentSlide.value, + type: 'slides', + data: selectedSlides.value, })) copyText(text).then(() => { @@ -76,21 +90,26 @@ export default () => { addHistorySnapshot() } - // 删除当前页 - const deleteSlide = () => { - if (slidesLength.value === 1) return message.warning('无法继续删除') - - store.commit(MutationTypes.DELETE_SLIDE, currentSlide.value.id) + // 删除当前页,若将删除全部页面,则执行重置幻灯片操作 + const deleteSlide = (targetSlidesId = selectedSlidesId.value) => { + if (slides.value.length === targetSlidesId.length) resetSlides() + else store.commit(MutationTypes.DELETE_SLIDE, targetSlidesId) + + store.commit(MutationTypes.UPDATE_SELECTED_SLIDES_INDEX, []) + addHistorySnapshot() } // 将当前页复制后删除(剪切) + // 由于复制操作会导致多选状态消失,所以需要提前将需要删除的页面ID进行缓存 const cutSlide = () => { + const targetSlidesId = [...selectedSlidesId.value] copySlide() - deleteSlide() + deleteSlide(targetSlidesId) } return { + resetSlides, updateSlideIndex, copySlide, pasteSlide, diff --git a/src/store/mutations.ts b/src/store/mutations.ts index c451854a..e1fd524d 100644 --- a/src/store/mutations.ts +++ b/src/store/mutations.ts @@ -82,9 +82,10 @@ export const mutations: MutationTree = { state.slides = slides }, - [MutationTypes.ADD_SLIDE](state, slide: Slide) { + [MutationTypes.ADD_SLIDE](state, slide: Slide | Slide[]) { + const slides = Array.isArray(slide) ? slide : [slide] const addIndex = state.slideIndex + 1 - state.slides.splice(addIndex, 0, slide) + state.slides.splice(addIndex, 0, ...slides) state.slideIndex = addIndex }, @@ -93,13 +94,21 @@ export const mutations: MutationTree = { state.slides[slideIndex] = { ...state.slides[slideIndex], ...props } }, - [MutationTypes.DELETE_SLIDE](state, slideId: string) { - const deleteIndex = state.slides.findIndex(item => item.id === slideId) + [MutationTypes.DELETE_SLIDE](state, slideId: string | string[]) { + const slidesId = Array.isArray(slideId) ? slideId : [slideId] - if (deleteIndex === state.slides.length - 1) { - state.slideIndex = deleteIndex - 1 + const deleteSlidesIndex = [] + for (let i = 0; i < slidesId.length; i++) { + const index = state.slides.findIndex(item => item.id === slidesId[i]) + deleteSlidesIndex.push(index) } - state.slides.splice(deleteIndex, 1) + let newIndex = Math.min(...deleteSlidesIndex) + + const maxIndex = state.slides.length - slidesId.length - 1 + if (newIndex > maxIndex) newIndex = maxIndex + + state.slideIndex = newIndex + state.slides = state.slides.filter(item => !slidesId.includes(item.id)) }, [MutationTypes.UPDATE_SLIDE_INDEX](state, index: number) { diff --git a/src/views/Editor/EditorHeader/index.vue b/src/views/Editor/EditorHeader/index.vue index 203444ed..ffd31e40 100644 --- a/src/views/Editor/EditorHeader/index.vue +++ b/src/views/Editor/EditorHeader/index.vue @@ -65,7 +65,6 @@