ソースを参照

1、blockly操作图标

liyanbo 6 ヶ月 前
コミット
f7a107d43e
1 ファイル変更110 行追加119 行削除
  1. 110 119
      src/views/Blockly.vue

+ 110 - 119
src/views/Blockly.vue

@@ -1313,143 +1313,134 @@ onMounted(async () => {
   // 注册Python代码生成器
   registerPythonGenerators();
 
-  // 在初始化工作区后添加以下代码来恢复初始加载功能并修复拖拽问题
-  // 初始化工作区
-  state.workspace = Blockly.inject("blocklyDiv", {
-    toolbox: document.getElementById("toolbox"),
-    grid: { spacing: 20, length: 3, colour: "#ccc", snap: true },
-    trashcan: true,
-  });
-
-  // 恢复并优化初始加载组件逻辑 - 与当前Blockly版本兼容的修复版
+  // 初始化工作区 - 简化且标准化的实现
   try {
-    // 使用字符串拼接定义初始XML内容
+    // 使用标准方式初始化Blockly工作区,参考BlocklyEditor_2.vue的配置
+    const blocklyDiv = document.getElementById('blocklyDiv');
+    const toolbox = document.getElementById('toolbox');
+
+    state.workspace = Blockly.inject(blocklyDiv, {
+      toolbox: toolbox,
+      collapse: true,
+      comments: true,
+      disable: false, // 设为false以允许编辑
+      maxBlocks: Infinity,
+      trashcan: true,
+      horizontalLayout: false,
+      toolboxPosition: 'start',
+      css: true,
+      media: 'https://unpkg.com/blockly/media/',
+      rtl: false,
+      scrollbars: true,
+      sounds: false, // 禁用声音以提高性能
+      oneBasedIndex: true,
+      grid: {
+        spacing: 20,
+        length: 3,
+        colour: "#ccc",
+        snap: true
+      },
+      zoom: {
+        controls: true,
+        wheel: true,
+        startScale: 1.0,
+        maxScale: 3,
+        minScale: 0.3,
+        scaleSpeed: 1.2
+      }
+    });
+
+    // 使用当前Blockly版本支持的标准方法加载初始内容
     const initialXml = "<xml xmlns=\"https://developers.google.com/blockly/xml\">\n" +
-        "  <variables>\n" +
-        "    <variable id=\"kAVG*zJLw/q)l/(/eIMM\">inputText</variable>\n" +
-        "    <variable id=\"[7F(niLz{.fvWvY.VT/N\">lampConfig</variable>\n" +
-        "  </variables>\n" +
-        "  <block type=\"variables_set\" id=\"XIsa=sV/8ImVP5P3:ol4\" x=\"90\" y=\"90\">\n" +
-        "    <field name=\"VAR\" id=\"kAVG*zJLw/q)l/(/eIMM\">inputText</field>\n" +
-        "    <value name=\"VALUE\">\n" +
-        "      <block type=\"ai_voice_input\" id=\"Ql).^+/uT(P~$aMg2OEA\">\n" +
-        "        <field name=\"LANGUAGE\">zh-CN</field>\n" +
-        "        <value name=\"PROMPT\">\n" +
-        "          <block type=\"text\" id=\"kXjnnUncUu7p$a[zz)da\">\n" +
-        "            <field name=\"TEXT\">请说话:</field>\n" +
-        "          </block>\n" +
-        "        </value>\n" +
-        "      </block>\n" +
-        "    </value>\n" +
-        "    <next>\n" +
-        "      <block type=\"variables_set\" id=\"AP0CO$VPeM0*PS*CKT,V\">\n" +
-        "        <field name=\"VAR\" id=\"[7F(niLz{.fvWvY.VT/N\">lampConfig</field>\n" +
+        "      <variables>\n" +
+        "        <variable id=\"kAVG*zJLw/q)l/(/eIMM\">inputText</variable>\n" +
+        "        <variable id=\"[7F(niLz{.fvWvY.VT/N\">lampConfig</variable>\n" +
+        "      </variables>\n" +
+        "      <block type=\"variables_set\" id=\"XIsa=sV/8ImVP5P3:ol4\" x=\"90\" y=\"90\">\n" +
+        "        <field name=\"VAR\" id=\"kAVG*zJLw/q)l/(/eIMM\">inputText</field>\n" +
         "        <value name=\"VALUE\">\n" +
-        "          <block type=\"ai_text_to_text\" id=\"XYG.cN_=CX5:Vd_)wdZ7\" x=\"190\" y=\"250\">\n" +
-                "    <value name=\"PROMPT\">\n" +
-                "      <block type=\"variables_get\" id=\"(3Sd)lTX],5xho{p_=s!\">\n" +
-                "        <field name=\"VAR\" id=\"8(,gJ5{2y*8olrD{^G.P\">inputText</field>\n" +
-                "      </block>\n" +
-                "    </value>\n" +
-                "    <value name=\"提示词\">\n" +
-                "      <block type=\"text\" id=\"ubD*WPRnwBC|BxGraKX3\">\n" +
-                "        <field name=\"TEXT\">请只回复我指定格式:白,100,热闹</field>\n" +
-                "      </block>\n" +
-                "    </value>\n" +
-                "  </block>\n" +
+        "          <block type=\"ai_voice_input\" id=\"Ql).^+/uT(P~$aMg2OEA\">\n" +
+        "            <field name=\"LANGUAGE\">zh-CN</field>\n" +
+        "            <value name=\"PROMPT\">\n" +
+        "              <block type=\"text\" id=\"kXjnnUncUu7p$a[zz)da\">\n" +
+        "                <field name=\"TEXT\">请说话:</field>\n" +
+        "              </block>\n" +
+        "            </value>\n" +
+        "          </block>\n" +
         "        </value>\n" +
         "        <next>\n" +
-        "          <block type=\"ai_smart_lamp_single_param\" id=\"ZTAwt~MMm(t5w:$$Azt`\">\n" +
-        "            <value name=\"PARAMS\">\n" +
-        "              <block type=\"variables_get\" id=\"X):w|X4hYE~ru1r9`W8f\">\n" +
-        "                <field name=\"VAR\" id=\"[7F(niLz{.fvWvY.VT/N\">lampConfig</field>\n" +
+        "          <block type=\"variables_set\" id=\"AP0CO$VPeM0*PS*CKT,V\">\n" +
+        "            <field name=\"VAR\" id=\"[7F(niLz{.fvWvY.VT/N\">lampConfig</field>\n" +
+        "            <value name=\"VALUE\">\n" +
+        "              <block type=\"ai_text_to_text\" id=\"XYG.cN_=CX5:Vd_)wdZ7\" x=\"190\" y=\"250\">\n" +
+        "                <value name=\"PROMPT\">\n" +
+        "                  <block type=\"variables_get\" id=\"(3Sd)lTX],5xho{p_=s!\">\n" +
+        "                    <field name=\"VAR\" id=\"8(,gJ5{2y*8olrD{^G.P\">inputText</field>\n" +
+        "                  </block>\n" +
+        "                </value>\n" +
+        "                <value name=\"提示词\">\n" +
+        "                  <block type=\"text\" id=\"ubD*WPRnwBC|BxGraKX3\">\n" +
+        "                    <field name=\"TEXT\">请只回复我指定格式:白,100,热闹</field>\n" +
+        "                  </block>\n" +
+        "                </value>\n" +
         "              </block>\n" +
         "            </value>\n" +
-        "          </block>\n" +
-        "        </next>\n" +
-        "      </block>\n" +
-        "    </next>\n" +
+        "            <next>\n" +
+        "              <block type=\"ai_smart_lamp_single_param\" id=\"ZTAwt~MMm(t5w:$$Azt`\">\n" +
+        "    <value name=\"PARAMS\">\n" +
+        "        <block type=\"variables_get\" id=\"X):w|X4hYE~ru1r9`W8f\">\n" +
+        "        <field name=\"VAR\" id=\"[7F(niLz{.fvWvY.VT/N\">lampConfig</field>\n" +
         "  </block>\n" +
-        "</xml>";
-    // 使用安全的方式解析XML
-    const xml = Blockly.utils.xml.textToDom(initialXml);
-
-    // 清空工作区确保没有遗留节点
-    state.workspace.clear();
-
-    // 使用当前Blockly版本支持的标准方法加载XML
-    Blockly.Xml.domToWorkspace(xml, state.workspace);
-
-    // 使用setTimeout确保DOM完全加载和节点注册完成
-    setTimeout(() => {
-      // 确保所有块都可移动和可删除
-      const allBlocks = state.workspace.getAllBlocks();
-      allBlocks.forEach(block => {
-        // 重置拖拽状态
-        block.draggable_ = true;
-
-        // 强制设置可移动和可删除属性
-        block.setMovable(true);
-        block.setDeletable(true);
-
-        // 关键修复:确保SVG节点正确注册到工作区
-        if (block.svgGroup_ && block.svgGroup_.parentNode) {
-          // 重新附加到DOM以触发正确的注册
-          const parent = block.svgGroup_.parentNode;
-          parent.removeChild(block.svgGroup_);
-          parent.appendChild(block.svgGroup_);
-
-          // 强制重新渲染块
-          block.render();
-        }
-      });
+        "  </value>\n" +
+        "  </block>\n" +
+        "  </next>\n" +
+        "  </block>\n" +
+        "  </next>\n" +
+        "  </block>\n" +
+        "  </xml>";
 
-      // 修复FocusManager问题:采用兼容方式
-      const canvas = state.workspace.getCanvas();
-      if (canvas && canvas.dispatchEvent) {
-        // 模拟鼠标移动事件,触发Blockly内部重新扫描DOM
-        const tempEvent = new MouseEvent('mousemove', {
-          bubbles: true,
-          cancelable: true,
-          view: window
-        });
-        canvas.dispatchEvent(tempEvent);
-      }
 
-      // 强制重新渲染整个工作区
-      state.workspace.render();
-
-      // 为初始块添加自定义的拖拽处理器
-      const initialBlocks = state.workspace.getAllBlocks();
-      initialBlocks.forEach(block => {
-        // 为初始块添加错误处理包装器
-        if (block.onMouseDown) {
-          const originalMouseDown = block.onMouseDown;
-          block.onMouseDown = function(e) {
-            try {
-              // 调用原始的鼠标按下处理函数
-              originalMouseDown.call(this, e);
-            } catch (error) {
-              console.warn('处理块鼠标事件失败:', error);
-              // 防止错误传播,影响其他块
-              if (e && e.stopPropagation) {
-                e.stopPropagation();
-              }
-            }
-          };
+    // const initialXml = "<xml xmlns=\"https://developers.google.com/blockly/xml\">\n" +
+    //     "  </xml>";
+
+    try {
+      // 尝试使用现代API加载工作区
+      const parsedXml = Blockly.utils.xml.textToDom(initialXml);
+      Blockly.Xml.domToWorkspace(parsedXml, state.workspace);
+      console.log('XML加载成功');
+    } catch (xmlError) {
+      console.warn('XML加载失败,尝试清空工作区:', xmlError);
+      // 如果XML加载失败,清空工作区
+      state.workspace.clear();
+    }
+
+    // 添加拖拽修复
+    if (state.workspace) {
+      // 确保所有块都可以正确拖拽
+      state.workspace.addChangeListener((event) => {
+        if (event.type === Blockly.Events.BLOCK_CREATE) {
+          // 对于新创建的块,确保它们是可拖拽的
+          const block = state.workspace.getBlockById(event.blockId);
+          if (block && block.editable) {
+            // 确保块是可编辑的
+            block.setEditable(true);
+          }
         }
       });
+    }
 
-      // 初始化完成后手动生成一次代码
-      generateCode("javascript");
+    // 初始化完成后手动生成一次代码
+    generateCode("javascript");
 
-    }, 1000); // 增加延迟时间确保DOM完全就绪
   } catch (error) {
-    console.error('加载初始组件失败:', error);
+    console.error('初始化Blockly工作区失败:', error);
+    ElMessage.error('Blockly初始化失败,请刷新页面重试');
   }
 
   // 添加工作区变化监听器
-  state.workspace.addChangeListener(() => generateCode("javascript"));
+  if (state.workspace) {
+    state.workspace.addChangeListener(() => generateCode("javascript"));
+  }
 });
 
 // 组件卸载时清除所有资源