[blockly] blockly块的变形器

145 阅读1分钟

前言

因为之前我在网上找blockly变形器的相关的内容的时候,资料少的又少,现在我也来补充一点

版本

使用的blackly版本为12.1.0,如果为过于老的版本可能不适用

效果展示

7月3日.gif

可以根据我们的需要来进行切换样式

实现解释

通过在代码块的样式中添加setMutator为打开变形器的开关,打开后

this.setMutator(new Blockly.icons.MutatorIcon(['custom_if_elseif', 'custom_if_else'], this));

与之配合的是下面两个函数: decompose 用户点击变形器按钮时 展示当前结构供用户编辑 compose 用户完成编辑关闭窗口 根据编辑内容修改 block 结构

 decompose: function (workspace) {
 		// 创建一个新的workspac,并且在这个workspace上面添加一个新块,名为custom_if_container
        const containerBlock = workspace.newBlock('custom_if_container');
        containerBlock.initSvg();

        let connection = containerBlock.getInput('STACK').connection;

		// 根据之前变形的结构,补充所存在的custom_if_elseif块和custom_if_else块
        for (let i = 1; i <= this.elseifCount_; i++) {
            const elseifBlock = workspace.newBlock('custom_if_elseif');
            elseifBlock.initSvg();
            connection.connect(elseifBlock.previousConnection);
            connection = elseifBlock.nextConnection;
        }
        if (this.elseCount_) {
            const elseBlock = workspace.newBlock('custom_if_else');
            elseBlock.initSvg();
            connection.connect(elseBlock.previousConnection);
        }

        return containerBlock;
    },

	// 每次放置新的块的时候进行变形的操作
    compose: function (containerBlock) {
        // 移除所有 elseif 和 else
        for (let i = 1; this.getInput(`IF${i}`); i++) {
            this.removeInput(`IF${i}`);
            this.removeInput(`DO${i}`);
        }
        if (this.getInput('ELSE')) {
            this.removeInput('ELSE');
        }

		// 用于记录这个块中存在的custom_if_elseif块和custom_if_else块的数量
        this.elseifCount_ = 0;
        this.elseCount_ = 0;

        // 重新插入
        let clauseBlock = containerBlock.getInputTargetBlock('STACK');
        let i = 1;
        // 根据取到的clauseBlock ,也就是打开变形器的这个工作区上面放置的块,进行添加并且记录数量
        while (clauseBlock) {
            if (clauseBlock.type === 'custom_if_elseif') {
                this.appendValueInput(`IF${i}`)
                    .setCheck("Boolean")
                    .appendField("否则如果");
                this.appendStatementInput(`DO${i}`)
                    .appendField("那么");
                i++;
                this.elseifCount_++;
            } else if (clauseBlock.type === 'custom_if_else') {
                this.appendStatementInput('ELSE')
                    .appendField("否则");
                this.elseCount_++;
            }
            clauseBlock = clauseBlock.nextConnection && clauseBlock.nextConnection.targetBlock();
        }
    }
};

完整代码

Blockly.Blocks['custom_if'] = {
    init: function () {
        this.setMutator(new Blockly.icons.MutatorIcon(['custom_if_elseif', 'custom_if_else'], this));
        this.appendValueInput("IF0")
            .setCheck("Boolean")
            .appendField("如果");
        this.appendStatementInput("DO0")
            .appendField("那么");

        this.elseifCount_ = 0;
        this.elseCount_ = 0;

        this.setPreviousStatement(true, null);
        this.setNextStatement(true, null);
        this.setColour("#1E90FF");
    },

    decompose: function (workspace) {
        const containerBlock = workspace.newBlock('custom_if_container');
        containerBlock.initSvg();

        let connection = containerBlock.getInput('STACK').connection;

        for (let i = 1; i <= this.elseifCount_; i++) {
            const elseifBlock = workspace.newBlock('custom_if_elseif');
            elseifBlock.initSvg();
            connection.connect(elseifBlock.previousConnection);
            connection = elseifBlock.nextConnection;
        }

        if (this.elseCount_) {
            const elseBlock = workspace.newBlock('custom_if_else');
            elseBlock.initSvg();
            connection.connect(elseBlock.previousConnection);
        }

        return containerBlock;
    },

    compose: function (containerBlock) {
        // 移除所有 elseif 和 else
        for (let i = 1; this.getInput(`IF${i}`); i++) {
            this.removeInput(`IF${i}`);
            this.removeInput(`DO${i}`);
        }
        if (this.getInput('ELSE')) {
            this.removeInput('ELSE');
        }

        this.elseifCount_ = 0;
        this.elseCount_ = 0;

        // 重新插入
        let clauseBlock = containerBlock.getInputTargetBlock('STACK');
        let i = 1;
        while (clauseBlock) {
            if (clauseBlock.type === 'custom_if_elseif') {
                this.appendValueInput(`IF${i}`)
                    .setCheck("Boolean")
                    .appendField("否则如果");
                this.appendStatementInput(`DO${i}`)
                    .appendField("那么");
                i++;
                this.elseifCount_++;
            } else if (clauseBlock.type === 'custom_if_else') {
                this.appendStatementInput('ELSE')
                    .appendField("否则");
                this.elseCount_++;
            }
            clauseBlock = clauseBlock.nextConnection && clauseBlock.nextConnection.targetBlock();
        }
    }
};
Blockly.Blocks['custom_if_container'] = {
    init: function () {
        this.appendDummyInput().appendField("条件分支");
        this.appendStatementInput("STACK");
        this.setColour(210);
        this.setTooltip("");
        this.contextMenu = false;
    }
};

Blockly.Blocks['custom_if_elseif'] = {
    init: function () {
        this.appendDummyInput().appendField("添加 否则如果");
        this.setPreviousStatement(true, null);
        this.setNextStatement(true, null);
        this.setColour(210);
        this.setTooltip("");
        this.contextMenu = false;
    }
};

Blockly.Blocks['custom_if_else'] = {
    init: function () {
        this.appendDummyInput().appendField("添加 否则");
        this.setPreviousStatement(true, null);
        this.setColour(210);
        this.setTooltip("");
        this.contextMenu = false;
    }
};
javascriptGenerator.forBlock['custom_if'] = function (block, generator) {
    let code = '';
    let n = 0;

    const condition = generator.valueToCode(block, 'IF0', Order.NONE) || 'false';
    const branch = generator.statementToCode(block, 'DO0');
    code += `if (${condition}) {${branch}}`;

    for (n = 1; n <= block.elseifCount_; n++) {
        const condition = generator.valueToCode(block, 'IF' + n, Order.NONE) || 'false';
        const branch = generator.statementToCode(block, 'DO' + n);
        code += ` else if (${condition}) {${branch}}`;
    }

    if (block.elseCount_) {
        const branch = generator.statementToCode(block, 'ELSE');
        code += ` else {${branch}}`;
    }



    return code + '';
};