pipipi-pikachu 5 سال پیش
والد
کامیت
ca36cbac52

+ 0 - 1
src/assets/styles/prosemirror.scss

@@ -2,7 +2,6 @@
   outline: 0;
   border: 0;
   font-size: 20px;
-  line-height: 1.5;
   word-break: break-word;
   font-family: '微软雅黑';
 

+ 1 - 0
src/views/Editor/Canvas/Operate/ImageElementOperate.vue

@@ -53,6 +53,7 @@ import ImageClipHandler from './ImageClipHandler.vue'
 
 export default defineComponent({
   name: 'image-element-operate',
+  inheritAttrs: false,
   components: {
     RotateHandler,
     ResizeHandler,

+ 1 - 0
src/views/Editor/Canvas/Operate/LineElementOperate.vue

@@ -25,6 +25,7 @@ import ResizeHandler from './ResizeHandler.vue'
 
 export default defineComponent({
   name: 'text-element-operate',
+  inheritAttrs: false,
   components: {
     ResizeHandler,
   },

+ 1 - 0
src/views/Editor/Canvas/Operate/ShapeElementOperate.vue

@@ -40,6 +40,7 @@ import BorderLine from './BorderLine.vue'
 
 export default defineComponent({
   name: 'text-element-operate',
+  inheritAttrs: false,
   components: {
     RotateHandler,
     ResizeHandler,

+ 1 - 0
src/views/Editor/Canvas/Operate/TextElementOperate.vue

@@ -40,6 +40,7 @@ import BorderLine from './BorderLine.vue'
 
 export default defineComponent({
   name: 'text-element-operate',
+  inheritAttrs: false,
   components: {
     RotateHandler,
     ResizeHandler,

+ 20 - 3
src/views/Editor/Toolbar/ElementStylePanel/TextStylePanel.vue

@@ -81,14 +81,14 @@
 
     <div class="row">
       <div style="flex: 2;">行间距:</div>
-      <Select style="flex: 3;" :value="lineHeight">
+      <Select style="flex: 3;" :value="lineHeight" @change="value => updateLineHeight(value)">
         <template #suffixIcon><ColumnHeightOutlined /></template>
         <SelectOption v-for="item in lineHeightOptions" :key="item" :value="item">{{item}}</SelectOption>
       </Select>
     </div>
     <div class="row">
       <div style="flex: 2;">字间距:</div>
-      <Select style="flex: 3;" :value="wordSpace">
+      <Select style="flex: 3;" :value="wordSpace" @change="value => updateWordSpace(value)">
         <template #suffixIcon><ColumnWidthOutlined /></template>
         <SelectOption v-for="item in wordSpaceOptions" :key="item" :value="item">{{item}}</SelectOption>
       </Select>
@@ -111,10 +111,11 @@
 <script lang="ts">
 import { computed, defineComponent, onUnmounted, Ref, ref, watch } from 'vue'
 import { useStore } from 'vuex'
-import { State } from '@/store'
+import { MutationTypes, State } from '@/store'
 import { PPTTextElement } from '@/types/slides'
 import emitter, { EmitterEvents } from '@/utils/emitter'
 import { TextAttrs } from '@/prosemirror/utils'
+import useHistorySnapshot from '@/hooks/useHistorySnapshot'
 
 import ElementOpacity from '../common/ElementOpacity.vue'
 import ElementOutline from '../common/ElementOutline.vue'
@@ -215,6 +216,20 @@ export default defineComponent({
       emitter.off(EmitterEvents.UPDATE_TEXT_STATE, attr => updateRichTextAttrs(attr))
     })
 
+    const { addHistorySnapshot } = useHistorySnapshot()
+
+    const updateLineHeight = (value: number) => {
+      const props = { lineHeight: value }
+      store.commit(MutationTypes.UPDATE_ELEMENT, { id: handleElement.value.id, props })
+      addHistorySnapshot()
+    }
+
+    const updateWordSpace = (value: number) => {
+      const props = { wordSpace: value }
+      store.commit(MutationTypes.UPDATE_ELEMENT, { id: handleElement.value.id, props })
+      addHistorySnapshot()
+    }
+
     return {
       fill,
       lineHeight,
@@ -224,6 +239,8 @@ export default defineComponent({
       fontSizeOptions,
       lineHeightOptions,
       wordSpaceOptions,
+      updateLineHeight,
+      updateWordSpace,
     }
   },
 })

+ 19 - 2
src/views/Editor/Toolbar/common/ElementOpacity.vue

@@ -2,7 +2,14 @@
   <div class="element-opacity">
     <div class="row">
       <div style="flex: 2;">不透明度:</div>
-      <Slider :min="0" :max="1" :step="0.1" :value="opacity" style="flex: 3;" />
+      <Slider
+        :min="0"
+        :max="1"
+        :step="0.1"
+        :value="opacity"
+        style="flex: 3;"
+        @change="value => updateOpacity(value)" 
+      />
     </div>
   </div>
 </template>
@@ -10,8 +17,9 @@
 <script lang="ts">
 import { computed, defineComponent, Ref, ref, watch } from 'vue'
 import { useStore } from 'vuex'
-import { State } from '@/store'
+import { MutationTypes, State } from '@/store'
 import { PPTElement } from '@/types/slides'
+import useHistorySnapshot from '@/hooks/useHistorySnapshot'
 
 import { Slider } from 'ant-design-vue'
 
@@ -31,8 +39,17 @@ export default defineComponent({
       opacity.value = 'opacity' in handleElement.value && handleElement.value.opacity || 1
     }, { deep: true, immediate: true })
 
+    const { addHistorySnapshot } = useHistorySnapshot()
+
+    const updateOpacity = (value: number) => {
+      const props = { opacity: value }
+      store.commit(MutationTypes.UPDATE_ELEMENT, { id: handleElement.value.id, props })
+      addHistorySnapshot()
+    }
+
     return {
       opacity,
+      updateOpacity,
     }
   },
 })

+ 34 - 12
src/views/Editor/Toolbar/common/ElementOutline.vue

@@ -3,13 +3,20 @@
     <div class="row">
       <div style="flex: 2;">启用边框:</div>
       <div class="switch-wrapper" style="flex: 3;">
-        <Switch :checked="hasOutline" @change="checked => toggleOutline(checked)" />
+        <Switch 
+          :checked="hasOutline" 
+          @change="checked => toggleOutline(checked)" 
+        />
       </div>
     </div>
     <template v-if="hasOutline">
       <div class="row">
         <div style="flex: 2;">边框样式:</div>
-        <Select style="flex: 3;" :value="outline.style">
+        <Select 
+          style="flex: 3;" 
+          :value="outline.style" 
+          @change="value => updateOutline({ style: value })"
+        >
           <SelectOption value="solid">实线边框</SelectOption>
           <SelectOption value="dashed">虚线边框</SelectOption>
         </Select>
@@ -18,7 +25,10 @@
         <div style="flex: 2;">边框颜色:</div>
         <Popover trigger="click">
           <template #content>
-            <ColorPicker v-model="outline.color" />
+            <ColorPicker
+              :modelValue="outline.color"
+              @update:modelValue="value => updateOutline({ color: value })"
+            />
           </template>
           <Button class="color-btn" style="flex: 3;">
             <div class="color-block" :style="{ backgroundColor: outline.color }"></div>
@@ -28,7 +38,11 @@
       </div>
       <div class="row">
         <div style="flex: 2;">边框粗细:</div>
-        <InputNumber :value="outline.width" style="flex: 3;" />
+        <InputNumber 
+          :value="outline.width" 
+          @change="value => updateOutline({ width: value })" 
+          style="flex: 3;" 
+        />
       </div>
     </template>
   </div>
@@ -37,8 +51,9 @@
 <script lang="ts">
 import { computed, defineComponent, Ref, ref, watch } from 'vue'
 import { useStore } from 'vuex'
-import { State } from '@/store'
+import { MutationTypes, State } from '@/store'
 import { PPTElement, PPTElementOutline } from '@/types/slides'
+import useHistorySnapshot from '@/hooks/useHistorySnapshot'
 
 import ColorPicker from '@/components/ColorPicker/index.vue'
 import { Select, Button, Popover, InputNumber, Switch } from 'ant-design-vue'
@@ -69,21 +84,28 @@ export default defineComponent({
       hasOutline.value = !!outline.value
     }, { deep: true, immediate: true })
 
+    const { addHistorySnapshot } = useHistorySnapshot()
+
+    const updateOutline = (outlineProps: Partial<PPTElementOutline>) => {
+      const props = { outline: { ...outline.value, ...outlineProps } }
+      store.commit(MutationTypes.UPDATE_ELEMENT, { id: handleElement.value.id, props })
+      addHistorySnapshot()
+    }
+
     const toggleOutline = (checked: boolean) => {
-      if(!checked) {
-        outline.value = undefined
-        hasOutline.value = false
-      }
-      else {
-        outline.value = { width: 2, color: '#000', style: 'solid' }
-        hasOutline.value = true
+      let props: { outline?: PPTElementOutline } = { outline: undefined }
+      if(checked) {
+        props = { outline: { width: 2, color: '#000', style: 'solid' } }
       }
+      store.commit(MutationTypes.UPDATE_ELEMENT, { id: handleElement.value.id, props })
+      addHistorySnapshot()
     }
 
     return {
       outline,
       hasOutline,
       toggleOutline,
+      updateOutline,
     }
   },
 })

+ 44 - 12
src/views/Editor/Toolbar/common/ElementShadow.vue

@@ -9,21 +9,45 @@
     <template v-if="hasShadow">
       <div class="row">
         <div style="flex: 2;">水平阴影:</div>
-        <Slider :min="1" :max="10" :step="1" :value="shadow.h" style="flex: 3;" />
+        <Slider 
+          :min="1" 
+          :max="10" 
+          :step="1" 
+          :value="shadow.h" 
+          @change="value => updateShadow({ h: value })" 
+          style="flex: 3;" 
+        />
       </div>
       <div class="row">
         <div style="flex: 2;">垂直阴影:</div>
-        <Slider :min="1" :max="10" :step="1" :value="shadow.v" style="flex: 3;" />
+        <Slider
+          :min="1"
+          :max="10"
+          :step="1"
+          :value="shadow.v"
+          @change="value => updateShadow({ v: value })" 
+          style="flex: 3;"
+        />
       </div>
       <div class="row">
         <div style="flex: 2;">模糊距离:</div>
-        <Slider :min="1" :max="20" :step="1" :value="shadow.blur" style="flex: 3;" />
+        <Slider
+          :min="1"
+          :max="20"
+          :step="1"
+          :value="shadow.blur"
+          @change="value => updateShadow({ blur: value })" 
+          style="flex: 3;"
+        />
       </div>
       <div class="row">
         <div style="flex: 2;">阴影颜色:</div>
         <Popover trigger="click">
           <template #content>
-            <ColorPicker v-model="shadow.color" />
+            <ColorPicker
+              :modelValue="shadow.color"
+              @update:modelValue="value => updateShadow({ color: value })"
+            />
           </template>
           <Button class="color-btn" style="flex: 3;">
             <div class="color-block"></div>
@@ -38,8 +62,9 @@
 <script lang="ts">
 import { computed, defineComponent, Ref, ref, watch } from 'vue'
 import { useStore } from 'vuex'
-import { State } from '@/store'
+import { MutationTypes, State } from '@/store'
 import { PPTElement, PPTElementShadow } from '@/types/slides'
+import useHistorySnapshot from '@/hooks/useHistorySnapshot'
 
 import ColorPicker from '@/components/ColorPicker/index.vue'
 import { Slider, Button, Popover, Switch } from 'ant-design-vue'
@@ -68,21 +93,28 @@ export default defineComponent({
       hasShadow.value = !!shadow.value
     }, { deep: true, immediate: true })
 
+    const { addHistorySnapshot } = useHistorySnapshot()
+
+    const updateShadow = (shadowProps: Partial<PPTElementShadow>) => {
+      const props = { shadow: { ...shadow.value, ...shadowProps } }
+      store.commit(MutationTypes.UPDATE_ELEMENT, { id: handleElement.value.id, props })
+      addHistorySnapshot()
+    }
+
     const toggleShadow = (checked: boolean) => {
-      if(!checked) {
-        shadow.value = undefined
-        hasShadow.value = false
-      }
-      else {
-        shadow.value = { h: 1, v: 1, blur: 2, color: '#000' }
-        hasShadow.value = true
+      let props: { shadow?: PPTElementShadow } = { shadow: undefined }
+      if(checked) {
+        props = { shadow: { h: 1, v: 1, blur: 2, color: '#000' } }
       }
+      store.commit(MutationTypes.UPDATE_ELEMENT, { id: handleElement.value.id, props })
+      addHistorySnapshot()
     }
 
     return {
       shadow,
       hasShadow,
       toggleShadow,
+      updateShadow,
     }
   },
 })

+ 10 - 6
src/views/components/element/hooks/useElementShadow.ts

@@ -1,12 +1,16 @@
-import { Ref } from 'vue'
+import { ref, Ref, watchEffect } from 'vue'
 import { PPTElementShadow } from '@/types/slides'
 
 export default (shadow: Ref<PPTElementShadow | undefined>) => {
-  let shadowStyle = ''
-  if(shadow.value) {
-    const { h, v, blur, color } = shadow.value
-    shadowStyle = `${h}px ${v}px ${blur}px ${color}`
-  }
+  const shadowStyle = ref('')
+
+  watchEffect(() => {
+    if(shadow.value) {
+      const { h, v, blur, color } = shadow.value
+      shadowStyle.value = `${h}px ${v}px ${blur}px ${color}`
+    }
+    else shadowStyle.value = ''
+  })
 
   return {
     shadowStyle,