Scratch3.0 二次开发——支持隐藏积木选择区域

2,537 阅读5分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第4天,点击查看活动详情

概述

Scratch3.0 二次开发系列,系列说明、Demo源码等请查看:《Scratch3.0 二次开发——开篇》

这次核心介绍如何修改 scratch-blocks 库 使其支持隐藏积木选择区域的功能

需求分析

官方 scratch

如上图,官方 scratch 积木选择区域(flyout)是没办法伸缩或者隐藏的,这样,如果我们把整个 PC 界面移植到平板上的话,屏幕相对较小的情况下,积木编辑区域就显得很小。故,原始需求:积木选择区域(flyout)实现隐藏/显示功能,从而拓展积木编辑区域的大小。

另外,对于常规情况下,积木选择区域(flyout)默认显示会比较方便一点,只有当有需要隐藏时再通过某个按钮触发隐藏。

还有,要控制好可删除区域,如下图:

前置准备

项目构建环境依赖

scratch-blocks 项目构建比较麻烦,向匹配的环境和额外需要的库请见《Scratch3.0 二次开发——开篇,环境》

启动本地服务

scratch-blocks 库中自带有测试用的页面。最好先安装 http-server,相对方便在本地启动一个 http 服务器。安装好后,在 scratch-blocks 项目的根目录下执行 http-server 就可以启动一个本地服务,直接访问 http://127.0.0.1:8080/tests/vertical_playground.html 就可以访问测试页面,如下图:

scratch-blocks 测试页面

npm link

改好代码后,在 scratch-blocks 项目的根目录下执行 npm link 命令,然后在 demo-scratch-gui 项目根目录下执行npm link scratch-blocks 命令就可以将 demo-scratch-gui 中安装的远程 scratch-blocks 库,换成是本地的。

详细可以自行百度一下 npm link 的用法 O(∩_∩)O哈哈~

实现细节

思路

flyout 的 隐藏/显示 功能,最直接的就是去到 scratch-blocks 项目的源码文件中找线索,看有没有现成的接口:

  • flyout_base.js
    • flyout 的基础类,其它类型的 flyout 都是继承自这个类
  • flyout_vertical.js
    • 垂直布局 flyout 的类,scratch 有垂直和水平布局两种积木编辑方式(用得比较多是垂直,后续也只在垂直布局的基础上修改。对于水平布局,有需要的朋友可以摸索摸索一下)
      • 垂直布局:
      • 水平布局:

有一说一,虽然官方 scratch 几乎是 0 文档,但系统里面的接口还是有预留了挺多的,有事没事多刷刷源码,需要用到时可能会有“灵光一闪”的微妙感觉~

flyout_base.js - hide 函数,可以满足我们这次需求。但是呢,不能直接上,实现过程还是有点坑,等在下娓娓道来~

一开始非常天真的以为发现了好东西——flyout_base.js - autoClose 属性。这个属性,默认值是 false,如果设置成 true,则在把积木从 flyout 区域拖到编辑区域时,flyout 会自动隐藏起来。

打算搭配 flyout_base.js - hide 函数flyout_base.js - autoClose 属性实现这次需求,但最终做出来后会出现以下几点坑:

  1. scratch-blocks 项目报错,初步判断,下面错误是指在加载时少了一些数组元素,导致没法正确读取内容
    • 基本可以定位到是因为使用了 autoClose 属性后,隐藏了 flyout 导致的问题
  2. 角色、背景两种类型的 target 切换时,flyout 没有正确显示。本来下图这种类型的积木只会在处于背景 target 时才会出现,当切换成角色 target 时就会换成运动类型的积木。结果使用了这套方案后,没法正确切换。
  3. flyout 中,可勾选类型的积木没法勾选

个人感觉,应该是 autoClose 属性在源码里面有坑还没解决,导致了一串连环 bug,最终放弃了这套方案,改成了下一小节中的方案

源代码

上文提到,autoClose 属性 有坑,但 hide 函数 是没问题的。接下来我们会基于 hide 函数展开

修改总览

文中没有贴完所有源码,有需要的朋友麻烦上 scratch-blocks github 库 自取,有很多关键性的注释也附在源码上面,记得看看中文类型的注释(英文的注释是官方的,中文的注释都是我自己加上去的)

实现这次需求修改的地方如下:

scratch-blocks 的 core/toolbox.js 文件中:

// 相关变量:
this.isHideFlyout_ = false;
this.triggerIcon_ = null;

// 相关函数;
init
createTrigger
unfoldTrigger
foldTrigger
getIsHideFlyout
setIsHideFlyout
triggerIsHideFlyout
populate_
getClientRect
setSelectedItem
setSelectedItemForPopulate

scratch-blocks 的 core/css.js 文件中,新增了 .blocklyToolboxTrigger.blocklyToolboxTriggerIcon 两个样式 class,用来处理触发按钮

另外还在 scratch-blocks 的 media 目录 下增加了两份资源文件:hide.svgshow.svg

创建隐藏/显示触发器

上文总览中提及到的:

this.isHideFlyout_ = false;
this.triggerIcon_ = null;

createTrigger
unfoldTrigger
foldTrigger
getIsHideFlyout
setIsHideFlyout
triggerIsHideFlyout

这些变量和函数都是用来创建并保存隐藏/显示触发器用的

初始化

上文总览中提及到的:init 函数,是在 scratch-blocks 的 core/toolbox.js 中对隐藏/显示触发器进行初始化,包括以下内容:

  • 创建并保存对象(调用“创建隐藏/显示触发器”中的函数)
  • 创建点击事件

边边角角

上文总览中提及到的:

populate_
getClientRect
setSelectedItem
setSelectedItemForPopulate

这几个函数都是用来处理边界情况,虽然是边边角角的情况,但对于整个实现来说至关重要,最好还是看看源码里面的中文注释 O(∩_∩)O哈哈~

至此,就完成了这一次的需求实现 ✿✿ヽ(°▽°)ノ✿