Просмотр исходного кода

feat(PictureEditor): 添加键盘导航功能支持对象移动

- 实现了键盘事件监听器,支持方向键移动选中对象
- 添加了 Shift 键组合,按住时移动距离为 10px,否则为 1px
- 支持单个对象和多选对象的键盘移动操作
- 实现了键盘导航的初始化和销毁逻辑
- 确保画布容器可以获取焦点以接收键盘事件
- 添加了事件阻止默认行为和事件传播处理
panqiuyao 15 часов назад
Родитель
Сommit
ee91741eae

+ 99 - 0
frontend/src/views/components/PictureEditor/mixin/actions/index.js

@@ -154,6 +154,10 @@ export default  {
         this.toEraseInLayer();
 
       })
+
+      // 添加键盘事件监听,用于移动选中的对象
+      this.initKeyboardNavigation()
+
       //设置默认笔画
       setTimeout(() => {
         this.fcanvas.freeDrawingBrush.width = this.drawWidth
@@ -657,6 +661,101 @@ export default  {
       }
     },
 
+    // 初始化键盘导航,用于移动选中的对象
+    initKeyboardNavigation() {
+      if (!this.fcanvas) return
+
+      const canvasWrapper = this.fcanvas.wrapperEl
+      if (!canvasWrapper) return
+
+      // 移除之前可能存在的监听器
+      canvasWrapper.removeEventListener('keydown', this.handleKeyDown)
+
+      // 添加键盘事件监听
+      this.handleKeyDown = (e) => {
+        this.handleKeyboardNavigation(e)
+      }
+      canvasWrapper.addEventListener('keydown', this.handleKeyDown)
+
+      // 确保画布容器可以获取焦点
+      canvasWrapper.tabIndex = 0
+      canvasWrapper.focus()
+    },
+
+    // 处理键盘导航
+    handleKeyboardNavigation(e) {
+      const activeObject = this.fcanvas.getActiveObject()
+      if (!activeObject) return
+
+      // 检查是否按下了方向键
+      const keyMap = {
+        ArrowUp: 'up',
+        ArrowDown: 'down',
+        ArrowLeft: 'left',
+        ArrowRight: 'right'
+      }
+
+      const direction = keyMap[e.key]
+      if (!direction) return
+
+      e.preventDefault()
+      e.stopPropagation()
+
+      // 计算移动距离,可以根据需要调整
+      const moveDistance = e.shiftKey ? 10 : 1 // 按住 Shift 键时移动 10px,否则移动 1px
+
+      let deltaX = 0
+      let deltaY = 0
+
+      switch (direction) {
+        case 'up':
+          deltaY = -moveDistance
+          break
+        case 'down':
+          deltaY = moveDistance
+          break
+        case 'left':
+          deltaX = -moveDistance
+          break
+        case 'right':
+          deltaX = moveDistance
+          break
+      }
+
+      // 如果是 ActiveSelection(多选),移动所有选中的对象
+      if (activeObject.type === 'activeSelection') {
+        activeObject.forEachObject((obj) => {
+          obj.set({
+            left: obj.left + deltaX,
+            top: obj.top + deltaY
+          })
+        })
+      } else {
+        // 单个对象移动
+        activeObject.set({
+          left: activeObject.left + deltaX,
+          top: activeObject.top + deltaY
+        })
+      }
+
+      // 更新画布
+      this.fcanvas.renderAll()
+
+      // 更新画布状态(用于撤销功能)
+      this.updateCanvasState()
+    },
+
+    // 清理键盘导航事件监听器
+    destroyKeyboardNavigation() {
+      if (!this.fcanvas) return
+
+      const canvasWrapper = this.fcanvas.wrapperEl
+      if (canvasWrapper && this.handleKeyDown) {
+        canvasWrapper.removeEventListener('keydown', this.handleKeyDown)
+        this.handleKeyDown = null
+      }
+    }
+
 
   }
 

+ 1 - 0
frontend/src/views/components/marketingEdit/index.vue

@@ -56,6 +56,7 @@ export default {
   beforeDestroy() {
     this.saveCanvasSnapshot()
     this.destroyCanvasInstance()
+    this.destroyKeyboardNavigation()
   },
   data() {
     return {