Blockly元组积木开发

Blockly元组积木开发

今天出一期关于Blockly元组积木开发的教程,废话不多说,上代码

一:元组积木

元组积木借鉴mixly,python代码可以参考菜鸟教程www.runoob.com/python/pyth...

二:构建积木

1,涉及要修改得文件(blocks,tuple这个是要自己创建) 2,blocks文件引入tuple文件,并在export导出要积木

javascript 复制代码
tuple文件代码
/**
 * @license
 * Copyright 2012 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */

// Former goog.module ID: Blockly.libraryBlocks.tuple

import type {Block} from '../core/block.js';
import type {BlockSvg} from '../core/block_svg.js';
import type {Workspace} from '../core/workspace.js';
import type {Connection} from '../core/connection.js';
import {Msg} from '../core/msg.js';
import {Align} from '../core/inputs/align.js';
import {MutatorIcon} from '../core/icons/mutator_icon.js';
import {
  createBlockDefinitionsFromJsonArray,
  defineBlocks,
} from '../core/common.js';
import * as xmlUtils from '../core/utils/xml.js';

/**
 * A dictionary of the block definitions provided by this module.
 */
export const blocks = createBlockDefinitionsFromJsonArray([
  {
    type: "tuple_indexOf",
    helpUrl: "",
    tooltip: "",
    style: 'tuple_blocks',
    output: null,
    message0: "%{BKY_TUPLE_INDEXOF}",
    args0: [
      {
        type: "input_value",
        name: "VALUE",
        check: "Tuple",
      },
      { type: "input_value", name: "INDEX", check: "Number" },
    ],
  },
  {
    type: "tuple_slice",
    helpUrl: "",
    tooltip: "",
    style: "tuple_blocks",
    output: "Tuple",
    message0: "%{BKY_TUPLE_SLICE}",
    args0: [
      {
        type: "input_value",
        name: "VALUE",
        check: "Tuple",
      },
      { type: "input_value", name: "START", check: "Number" },
      { type: "input_value", name: "END", check: "Number" },
    ],
  },
  {
    type: "tuple_random_item",
    style: "tuple_blocks",
    helpUrl: "",
    tooltip: "",
    output: null,
    message0: "%{BKY_TUPLE_RANDOM_ITEM}",
    args0: [
      {
        type: "input_value",
        name: "VALUE",
        check: "Tuple",
      },
    ],
  },
  {
    type: "tuple_length",
    style: "tuple_blocks",
    helpUrl: "",
    tooltip: "",
    output: "Number",
    message0: "%{BKY_TUPLE_LENGTH}",
    args0: [
      {
        type: "input_value",
        name: "VALUE",
        check: "Tuple",
      },
    ],
  },
  {
    type: "tuple_max_value",
    style: "tuple_blocks",
    helpUrl: "",
    tooltip: "",
    output: null,
    message0: "%{BKY_TUPLE_MAX_VALUE}",
    args0: [
      {
        type: "input_value",
        name: "VALUE",
        check: "Tuple",
      },
      {
        type: "field_dropdown",
        name: "TYPE",
        options: [
          ["最大值", "max"],
          ["最小值", "min"],
          ["总和", "sum"],
        ],
      },
    ],
  },
  {
    type: "tuple_serach_value",
    style: "tuple_blocks",
    helpUrl: "",
    tooltip: "",
    output: "Number",
    message0: "%{BKY_TUPLE_SERACH_VALUE}",
    args0: [
      {
        type: "input_value",
        name: "VALUE",
        check: "Tuple",
      },
      {
        type: "input_value",
        name: "SEARCH",
      },
      {
        type: "field_dropdown",
        name: "TYPE",
        options: [
          ["位置", "index"],
          ["个数", "count"],
        ],
      },
    ],
  },
  {
    type: "tuple_delete",
    style: "tuple_blocks",
    helpUrl: "",
    tooltip: "",
    previousStatement: null,
    nextStatement: null,
    message0: "%{BKY_TUPLE_DELETE}",
    args0: [
      {
        type: "input_value",
        name: "VALUE",
        check: "Tuple",
      },
    ],
  },
  {
    type: "tuple_concat",
    style: "tuple_blocks",
    helpUrl: "",
    tooltip: "",
    output: "Tuple",
    inputsInline: true,
    message0: "%{BKY_TUPLE_CONCAT}",
    args0: [
      {
        type: "input_value",
        name: "VALUE1",
        check: "Tuple",
      },
      {
        type: "input_value",
        name: "VALUE2",
        check: "Tuple",
      },
    ],
  },
  {
    type: "tuple_to_tuple",
    style: "tuple_blocks",
    helpUrl: "",
    tooltip: "",
    output: "Tuple",
    message0: "%{BKY_TUPLE_TO_TUPLE}",
    args0: [
      {
        type: "input_value",
        name: "VALUE"
      },
    ],
  },
]);

/**
 * Type of a 'tuple_create_with' block.
 */
export type CreateWithBlock = Block & TupleCreateWithMixin;
interface TupleCreateWithMixin extends TupleCreateWithMixinType {
  itemCount_: number;
};
type TupleCreateWithMixinType = typeof TUPLE_CREATE_WITH;
const TUPLE_CREATE_WITH = {
  /**
   * Block for creating a tuple with any number of elements of any type.
   */
  init: function(this: CreateWithBlock) {
    this.setHelpUrl('');
    this.setStyle('tuple_blocks');
    this.itemCount_ = 3;
    this.updateShape_();
    this.setOutput(true, 'Tuple');
    this.setMutator(
      new MutatorIcon(['tuple_create_with_item'], this as unknown as BlockSvg)
    )
    this.setTooltip('');
  },
  /**
   * Create XML to represent tuple inputs.
   * Backwards compatible serialization implementation.
   */
  mutationToDom: function(this: CreateWithBlock): Element {
    const container = xmlUtils.createElement('mutation');
    container.setAttribute('items', String(this.itemCount_));
    return container;
  },
  /**
   * Parse XML to restore the tuple inputs.
   * Backwards compatible serialization implementation.
   *
   * @param xmlElement XML storage element.
   */
  domToMutation: function(this: CreateWithBlock, xmlElement: Element) {
    const items = xmlElement.getAttribute('items');
    if (!items) throw new TypeError('element did not have items');
    this.itemCount_ = parseInt(items, 10)
    this.updateShape_();
  },
  /**
   * Returns the state of this block as a JSON serializable object.
   *
   * @returns The state of this block, ie the item count.
   */
  saveExtraState: function (this: CreateWithBlock): {itemCount: number} {
    return {
      'itemCount': this.itemCount_,
    };
  },
  /**
   * Applies the given state to this block.
   *
   * @param state The state to apply to this block, ie the item count.
   */
  loadExtraState: function (this: CreateWithBlock, state: AnyDuringMigration) {
    this.itemCount_ = state['itemCount'];
    this.updateShape_();
  },
  /**
   * Populate the mutator's dialog with this block's components.
   * 
   * @param workspace Mutator's workspace.
   * @returns Root block in mutator.
   */
  decompose: function(
    this: CreateWithBlock,
    workspace: Workspace,
  ): ContainerBlock {
    const containerBlock = workspace.newBlock(
      'tuple_create_with_container'
    ) as ContainerBlock;
    (containerBlock as BlockSvg).initSvg();
    let connection = containerBlock.getInput('STACK')!.connection;
    for (let i = 0; i < this.itemCount_; i++) {
      const itemBlock = workspace.newBlock(
        'tuple_create_with_item'
      ) as ItemBlock;
      (itemBlock as BlockSvg).initSvg();
      if (!itemBlock.previousConnection) {
        throw new Error('itemBlock has no previousConnection')
      }
      connection!.connect(itemBlock.previousConnection)
      connection = itemBlock.nextConnection;
    }
    return containerBlock;
  },
  /**
   * Reconfigure this block based on the mutator dialog's components.
   * 
   * @param containerBlock Root block in mutator.
   */
  compose: function(this: CreateWithBlock, containerBlock: Block) {
    let itemBlock: ItemBlock | null = containerBlock.getInputTargetBlock(
      'STACK'
    ) as ItemBlock;
    // Count number of inputs.
    const connections: Connection[] = [];
    while (itemBlock) {
      if (itemBlock.isInsertionMarker()) {
        itemBlock = itemBlock.getNextBlock() as ItemBlock | null;
        continue;
      }
      connections.push(itemBlock.valueConnection_ as Connection);
      itemBlock = itemBlock.getNextBlock() as ItemBlock | null;
    }
    // Disconnect any children that don't belong.
    for (let i = 0; i < this.itemCount_; i++) {
      const connection = this.getInput('ADD' + i)!.connection!.targetConnection;
      if (connection && !connections.includes(connection)) {
        connection.disconnect();
      }
    }
    this.itemCount_ = connections.length;
    this.updateShape_();
    // Reconnect any child blocks.
    for (let i = 0; i < this.itemCount_; i++) {
      connections[i]?.reconnect(this, 'ADD' + i)
    }
  },
  /**
   * Store pointers to any connected child blocks.
   *
   * @param containerBlock Root block in mutator.
   */
  saveConnections: function(this: CreateWithBlock, containerBlock: Block) {
    let itemBlock: ItemBlock | null = containerBlock.getInputTargetBlock(
      'STACK',
    ) as ItemBlock;
    let i = 0;
    while(itemBlock) {
      if (itemBlock.isInsertionMarker()) {
        itemBlock = itemBlock.getNextBlock() as ItemBlock | null;
        continue;
      }
      const input = this.getInput('ADD' + i);
      itemBlock.valueConnection_ = input?.connection!.targetConnection as Connection;
      itemBlock = itemBlock.getNextBlock() as ItemBlock | null;
      i++;
    }
  },
  /**
   * Modify this block to have the correct number of inputs.
   */
  updateShape_: function(this: CreateWithBlock) {
    if (this.itemCount_ && this.getInput('EMPTY')) {
      this.removeInput('EMPTY');
    } else if (!this.itemCount_ && ! this.getInput('EMPTY')) {
      this.appendDummyInput('EMPTY')
        .appendField(
          Msg['TUPLE_CREATE_EMPTY_TITLE']
        );
    }
    // Add new inputs.
    for (let i = 0; i < this.itemCount_; i++) {
      if (!this.getInput('ADD' + i)) {
        const input = this.appendValueInput('ADD' + i).setAlign(Align.RIGHT);
        if (i === 0) {
          input.appendField(Msg['TUPLE_CREATE_WITH_INPUT_WITH'])
        }
      }
    }
    // Remove deleted inputs.
    for (let i = this.itemCount_; this.getInput('ADD' + i); i++) {
      this.removeInput('ADD' + i);
    }
  }
};
blocks['tuple_create_with'] = TUPLE_CREATE_WITH;

/** type for a 'tuple_creat_with_item' block. */
type ItemBlock = Block & ItemMutator
interface ItemMutator extends ItemMutatorType {
  valueConnection_?: Connection;
}
type ItemMutatorType = typeof TUPLE_CREATE_WITH_ITEM
const TUPLE_CREATE_WITH_ITEM = {
  /**
   * Mutator block for adding items.
   */
  init: function(this: ItemBlock) {
    this.setStyle('tuple_blocks');
    this.appendDummyInput()
      .appendField(Msg['ELEMENT']);
    this.setPreviousStatement(true);
    this.setNextStatement(true);
    this.setTooltip('');
    this.contextMenu = false;
  }
}
blocks['tuple_create_with_item'] = TUPLE_CREATE_WITH_ITEM;

/** Type for a 'tuple_create_with_container' block. */
type ContainerBlock = Block & ContainerMutator
interface ContainerMutator extends ContainerMutatorType {}
type ContainerMutatorType = typeof TUPLE_CREATE_WITH_CONTAINER
const TUPLE_CREATE_WITH_CONTAINER = {
  /**
   * Mutator block from tuple container.
   */
  init: function(this: ContainerBlock) {
    this.setStyle('tuple_blocks');
    this.appendDummyInput()
      .appendField(Msg['TUPLE_CREATE_WITH_CONTAINER']);
    this.appendStatementInput('STACK');
    this.setTooltip('');
    this.contextMenu = false;
  }
}
blocks['tuple_create_with_container'] = TUPLE_CREATE_WITH_CONTAINER;

defineBlocks(blocks);

至此元组积木已经完成,看一下效果图

三:构建python

1,涉及要修改得文件(python,tuple这个是要自己创建) 2,python文件引入tuple文件,并在export导出python代码

javascript 复制代码
tuple文件
/**
 * @license
 * Copyright 2012 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */

/**
 * @file Generating Python for tuple blocks.
 */

// Former goog.module ID: Blockly.Python.tuple
import type {Block} from '../../core/block.js';
import type {CreateWithBlock} from '../../blocks/tuple.js';
import type {PythonGenerator} from './python_generator.js';
import {Order} from './python_generator.js';

export function tuple_create_with(
  block: Block,
  generator: PythonGenerator,
): [string, Order] {
  // Create a tuple with any number of elements of any type.
  const createWithBlock = block as CreateWithBlock;
  const elements = new Array(createWithBlock.itemCount_);
  for (let i = 0; i < createWithBlock.itemCount_; i++) {
    elements[i] = generator.valueToCode(block, 'ADD' + i, Order.NONE) || 'None';
  }
  let code = ''
  if (elements.length === 1) {
    code = '(' + elements.join(', ') + ',)';
  } else {
    code = '(' + elements.join(', ') + ')';
  }
  return [code, Order.FUNCTION_CALL];
}

export function tuple_indexOf(block: Block, generator: PythonGenerator) : [string, Order] {    
  let VALUE = generator.valueToCode(block, 'VALUE', Order.NONE) || '0';
  let INDEX = generator.valueToCode(block, 'INDEX', Order.NONE) || '0';

  let code = `${VALUE}[${INDEX}]`
  return [code, Order.ATOMIC]
}

export function tuple_slice(block: Block, generator: PythonGenerator) : [string, Order] {
  let VALUE = generator.valueToCode(block, 'VALUE', Order.NONE) || '0';
  let START = generator.valueToCode(block, 'START', Order.NONE) || '0';
  let END = generator.valueToCode(block, 'END', Order.NONE) || '0';

  let code = `${VALUE}[${START} : ${END}]`
  return [code, Order.MEMBER]
}

export function tuple_random_item(block: Block, generator: PythonGenerator) : [string, Order] {
  (generator as AnyDuringMigration).definitions_['import_random'] = 'import random'
  let VALUE = generator.valueToCode(block, 'VALUE', Order.NONE) || '0';

  let code = `random.choice(${VALUE})`
  return [code, Order.ATOMIC]
}

export function tuple_length(block: Block, generator: PythonGenerator) : [string, Order] {
  let VALUE = generator.valueToCode(block, 'VALUE', Order.NONE) || '0';

  let code = `len(${VALUE})`
  return [code, Order.ATOMIC]
}

export function tuple_max_value(block: Block, generator: PythonGenerator) : [string, Order] {
  let VALUE = generator.valueToCode(block, 'VALUE', Order.NONE) || '0';
  let TYPE = block.getFieldValue('TYPE')

  let code = `${TYPE}(${VALUE})`
  return [code, Order.ATOMIC]
}

export function tuple_serach_value(block: Block, generator: PythonGenerator) : [string, Order] {
  let VALUE = generator.valueToCode(block, 'VALUE', Order.NONE) || '0';
  let SEARCH = generator.valueToCode(block, 'SEARCH', Order.NONE) || '0';
  let TYPE = block.getFieldValue('TYPE')

  let code = `${VALUE}.${TYPE}(${SEARCH})`
  return [code, Order.ATOMIC]
}

export function tuple_delete(block: Block, generator: PythonGenerator)  {
  let VALUE = generator.valueToCode(block, 'VALUE', Order.NONE) || '0';

  let code = `del ${VALUE}\n`
  return code
}

export function tuple_concat(block: Block, generator: PythonGenerator) : [string, Order] {
  let VALUE1 = generator.valueToCode(block, 'VALUE1', Order.NONE) || '0';
  let VALUE2 = generator.valueToCode(block, 'VALUE2', Order.NONE) || '0';

  let code = `${VALUE1} + ${VALUE2}`
  return [code, Order.ATOMIC]
}

export function tuple_to_tuple(block: Block, generator: PythonGenerator) : [string, Order] {
  let VALUE = generator.valueToCode(block, 'VALUE', Order.NONE) || '0';

  let code = `tuple(${VALUE})`
  return [code, Order.ATOMIC]
}

至此元组python已经完成,看一下效果图 总结:由于我的blockly项目是typescript的,有些开发人员项目和我并不相同,特别是引入的一些库文件有所不同,在用的时候要留一下,避免陷入太深,具体代码更具自己的项目改动一下就可以使用

相关推荐
笨笨狗吞噬者3 小时前
【uniapp】小程序体积优化,JSON文件压缩
前端·微信小程序·uni-app
西洼工作室3 小时前
浏览器事件循环与内存管理可视化
前端·javascript·css·css3
xier1234564 小时前
高性能和高灵活度的react表格组件
前端
你打不到我呢4 小时前
nestjs入门:上手数据库与prisma
前端
多啦C梦a4 小时前
React 实战:从 setInterval 到 useInterval,一次搞懂定时器 Hook(还能暂停!)
前端·javascript·react.js
闲不住的李先森4 小时前
乐观更新
前端·react.js·设计模式
笔尖的记忆4 小时前
【前端架构和框架】react组件化&数据流
前端·面试
zhangzelin8884 小时前
TypeScript入门指南:JavaScript的类型化超集
前端·javascript·其他·typescript
lichenyang4534 小时前
流式聊天界面实现解析:从零到一构建实时对话体验
前端