Snap! 中的 iframe 库
文章目录
前言
将另一个 HTML 页面嵌入到当前页面中 – iframe
我一直渴望拥有一个 Snap! iframe 库, 这个库最好足够通用, 它能够将各种各样的互联网资源通过 iframe 引入到 Snap! 里, 并与 Snap! 进行互操作。
这样一来我们就可以做许多有趣的事情:
- 以可编程的方式显示 markdown 文档
- 以可编程的方式播放 mp4 演示视频
- 以可编程的方式显示在线幻灯片
- 引入 3D world/game, 并使用 Snap! 对这些 3D 环境进行实时编程
- 将 MicroBlocks 平台嵌入 Snap! (之前的 MicroBlocks ide 库将成为这个通用 iframe 库的一个特例)
- …
潜在的用例非常多!
我在 CodeLab 群里分享相关演示视频的时候, @Patch 评论说:
给 Snap! 又开了一扇窗
我回复说
我也是这样看待 iframe 库,所以我刚给这个库添加的图标是 emoji 窗户: 🪟
我一直想要一个通用的 iframe 库,迟迟没有动手是因为不大喜欢也不大擅长前端工作,好在有了 ChatGPT! 这些工作变得非常轻松。 通过与 ChatGPT 协作, 我无需操心太多知识细节(这些是我过去不擅长的), 更多精力用于关注和表述想法, 不多时, 就得到了仅凭自己做不出来的东西。
对我而言, ChatGPT 的价值是双重的, 客观上, 它补足了我的知识短板, 更大的价值是主观层面的: 它极大减少了我对不熟悉领域的恐惧, 我之前倾向于回避这些工作。ChatGPT 通过使知识细节变得无关紧要, 让编程重新变得激动人心, 我们有更多精力关注自己的热情(passion)与项目(projects)的图景。
iframe 库
与之前的工作一样, 我们希望实现以下 2 个目标:
无需更新平台, 不需要开发者介入, 所有工作都在用户环境中完成(只是一个 Snap! 项目), 这意味着普通用户可以继续延伸这些能力。 (这是终端用户编程的一个例子)
可以充分利用 Snap! 的活性(liveness), 享受高效而愉快的开发体验。
所以整个 iframe 库完全在 Snap! IDE 中构建, “只是一个普通的 Snap! 项目”, 没有对平台进行任何修改。
我们将通过几个例子展示如何使用 iframe 库:
- 基本使用方式 (引入外部网站)
- 动态显示 markdown 文档
- 嵌入 MicroBlocks 项目
- 与 3D world 互操作(以 Spline 为例)
- 将消息从 iframe 页面发送到 Snap!
更多的操作细节, 推荐观看这个演示视频
基本使用方式
也可以打开多个页面, 每个页面可以通过它的 id 控制它:
动态显示 markdown 文档
Snap! 中的帮助文档
Snap! 官方的积木文档是以图片的形式制作的(右键某个积木, 点击 help...
):
相比于使用 markdown 编写和显示文档, 这种既不灵活(无法显示视频)也不清晰。
“支持使用 markdown 显示文档” 是我此次构建 iframe 的主要原因。
iframe 可以以多种方式显示 markdown 文档, 诸如使用常规方式编写 markdown 文档, 将其托管在网络上, 然后使用 iframe 打开文档链接它.
我采用了另一种更加 Snap! 的动态方案, 只托管一个通用的 markdown 渲染页面(默认空白), 如果你对它的工作原理感兴趣, 可以查看页面源代码, 使事情生效的代码只有 4 行!
|
|
通过 postMessage API , 可以在 iframe 页面中接收到 Snap! 页面发送过来的消息。
这个页面显示的 markdown 内容, 是由积木控制的! 这样一来我们就可以在积木环境中,实时控制文档页面的内容。
嵌入 MicroBlocks 项目
有些项目涉及到软硬件协作, 在 Snap! 中嵌入 MicroBlocks 项目, 就无需额外打开 MicroBlocks 页面刷入或查看硬件程序。
与 3D world 互操作(以 Spline 为例)
FAQ
可以拿 iframe 库做什么?
部署你自己的 web 应用, 使用 iframe 将其引入 Snap! , 然后你就可以为其提供一个高度可定制的图形化编程环境!
在过去, 这通常是一个完整的开发项目(有时是一个公司的商业项目), 现在,它只是一个用户级别的 Snap! 项目!
接下来做什么?
目前 Snap! 与 iframe 页面可以通过 postMessage 互相发送消息, 这些消息是异步非阻塞的。
- Snap! -> iframe
- Snap! 一侧: 使用
postMessage
积木给特定 iframe 页面发送消息 - iframe 一侧: 使用
window.addEventListener('message', (event) => {})
接收 Snap! 消息
- Snap! 一侧: 使用
- iframe -> Snap!
- Snap! 一侧: 使用
handle postMessage
积木接收 iframe 消息 - iframe 一侧: 使用
window.parent.postMessage(msg, "*")
发送字符串消息
- Snap! 一侧: 使用
有时候我们想要同步语义的消息, 诸如调用并等待结果
。
Dynatalk 致力于对象之间的交流, 尤其关心不同语言/环境之间的互操作。
我打算制作 dynatalk-over-postmessage: 将 dynatalk 构建在 postMessage 之上。 一旦完成, dynatalk 的所有能力在 iframe 库中使用。
更新: dynatalk-over-postmessage 已完成, Spline 库使用了它.
iframe 页面支持哪些权限?
目前的 iframe 页面支持以下权限: allow = "geolocation; microphone; camera; bluetooth; serial"
Snap! 中的 iframe 页面如何做到可缩放和可拖拽?
使用了 jQuery UI, 具体而言:
html
|
|
css:
|
|
js:
|
|
如何将其转化为标准的 Snap! 库?
处于教育目的, 我们使用 JavaScript function 来制作 iframe 库. 这样做,
- 好处是: “一切都只是一个普通 Snap! 项目”, 用户可以在 IDE 中理解所有事情
- 坏处是: 需要开启 “JavaScript 扩展"才能用
为了将基于 JavaScript function 的 iframe 库转化为开箱可用的内置积木库, 我们需要做一下工作:
- 将 iframe 库中所有的 JavaScript function 整理到一个 JavaScript 文件中, 并将 JavaScript 文件放在 Snap! 代码仓库里
- 将 iframe 库文件(以xml结尾) 当到 Snap! 代码仓库里
目前 iframe 已成为了 Snap! 中文版 内置库.
参考例子
可参考 microblocks 库(它引用了 ble 目录里的 JavaScript 文件), 是通过 autoloading JavaScript files 机制实现的.
如何控制 iframe 页面中的游戏?
通常的游戏设备都由鼠标/键盘控制, Snap! 无法直接触发鼠标/键盘事件.
一种解决方案是, 使用 MicroBlocks 的鼠标键盘库(使用rpi pico板子), 消息的流向是:
Snap! -> MicroBlocks 板子 -> 计算机
提醒: 在触发按键之前, 确保将鼠标聚焦在 iframe 页面(点击 iframe 页面)
参考
文章作者 种瓜
上次更新 2024-06-03