不是程序员也可以搞开发:一小时入门 Retool 低代码工具
学习编程已经成为近些年的热门话题之一。无论是 Apple、Google、AWS 等科技巨头积极响应 编程一小时 活动,还是 Z 世代的孩子早早地被父母送进少儿编程培训机构,都给人带来一种再不学习编程就会被时代抛弃的感觉。
我们都需要或者都想要成为程序员吗?答案应该是否定的。无论是自学编程的朋友,还是被送进培训机构的孩子们,他们的父母大概也不是希望孩子长大后就一定成为程序员,而是训练逻辑思维。程序员作为一份职业,依旧是少数人的选择,而编程作为一项技能,每个人都可以拥有。这就像是很多人都会自己炒菜做饭,但不全都是厨师一样。
我们可以运用逻辑思维,将重复繁杂的工作梳理得更清晰,而编程可以创造工具让流程变得更高效。但由于每个人的工作是个性化的,所以很难有完全通用工具。困难出现了,很多人都经历过学习编程从入门到放弃的过程。纵使某些编程语言入门相对简单(例如:Python),但从了解到最终实现能用的工具,中间涉及到的技术点纷繁复杂,小白还是很难短时间掌握。
于是市面上出现了许多低代码平台,让普通人也能较快地开发出自己想要的工具。Pietro Invernizzi 给出了他收集到的市面上常见的 低代码平台列表,将常用的低代码工具分为了 12 类,涉及网页开发、应用开发、自动化流程、表格工具等。当然国内做低代码产品的公司也很多,例如:腾讯云微搭、阿里云宜搭、明道云、飞书多维表格 等。
当然,低代码并不意味着完全零代码。根据低代码工具的属性和应用场景不同,对代码能力的要求也有区别。例如以 Airtable 和飞书多维表格这类以表格为主体,可以用来存放、统计、分析数据的平台,基本属于零代码。而 Bubble、Retool 等网页应用开发工具,则需要具备基本的编程思维和代码开发能力。
我试用过市面上大部分知名的低代码平台,个人最喜欢的是 Retool,也一直在工作中使用。这是一家位于旧金山,成立于 2017 年的创业公司,去年年底刚拿到 C 轮融资。相比之下,Retool 的组件和交互设计更加现代化,易用性也会更好一些。所以本文将使用 Retool 作为示例,手把手教会小白用户在一小时内开发一个和少数派相关的网页应用。
本文中,我们将尝试使用 Retool 开发一个能随机推荐少数派作者以及作者文章的 网页应用。通过实例练习,大家可以详细了解到 Retool 的常用功能并对低代码平台有更加深入的认识。
如上所示的网页应用具备两个功能:
首先我们需要 注册 Retool,过程就不再赘述了。登录之后,你需要设置一个自定义子域名。免费版的 Retool 可以永久使用全部开发功能,但过了 14 天试用期之后,将无法发布新的应用。已经发布的应用不受影响,且后续可以继续编辑并更新。
点击控制台右上角的新增按钮,创建一个空白的应用,页面会自动跳转到应用编辑器。
界面的正中是整个网页的预览区域,后续将在此区域完成应用界面设计和预览。左侧是应用数据结构区域,你可以在这里看到应用开发过程中的所有结构化数据,方便后续快速定位所需数据和字段。所有的数据都是 JSON 格式,这是最常用的数据交换格式之一。
界面下方是数据的获取和加工区域。你可以通过一些预设组件加载来自互联网的各类数据,例如:连接数据库、访问在线表格、请求 API 等。更重要的是,你可以在这里对获取到的数据进行再加工(Transformer),组合成自己所需的数据结构,并最终与功能组件完成数据交互。这一点将会在后续的开发过程中实际体验到。
界面右侧则是功能组件区域,Retool 提供了数十种常见的通用功能组件,你可以像搭积木一样,通过组合不同的组件去实现自己想要的功能。一款低代码工具提供的组件类型和功能越多,意味着其支持开发更加复杂多样的应用。
让我们直接开始吧。
一款网页应用界面上呈现的数据分为静态和动态两类。静态资源不会频繁更新,例如网站的 LOGO,菜单栏等。你可以直接拖拽相应的组件,并配置好静态资源即可。接下来,我们从界面右侧选中 Image 组件拖动到 Header 顶部菜单栏区域,放置一个少数派 LOGO。
请注意如图所示的 2 处配置,其中:
除了 LOGO 一类的静态资源,动态的部分往往会频繁更新,或者和部分功能一起完成数据交互。例如本次开发过程中的作者信息、作者文章等,这些数据大多直接来自于数据库,并通过功能组件实现对数据的新增、删除、修改和查询(简称:增删改查)。
回顾你平日里见过的大多数网页和应用,实际上都是这一套逻辑。例如少数派首页的样式是用 HTML、CSS、Javascript 等前端代码开发,而文章数据是通过 API 从后端数据库中实时获取。
低代码实际就是高度提炼这一套逻辑,通过提供大量的预设组件,减少自定义代码编写的工作量,最终实现前后端数据交互。
回到本次开发的网页应用,页面中的作者信息和文章数据都来自于少数派的数据库,我们没有权限直接访问。而少数派并也不提供开发者平台,所以我们无法使用其 API 数据接口(不建议大家通过技术方法使用少数派非公开 API)。
为了方便大家了解 Retool,文章提供了和少数派 API 数据结构一致的用户信息接口,示例地址为:https://jsonbase.huhuhang.workers.dev/sspai/api/v1/user/{slug}/info/get
,其中 {slug}
是用户名,可以使用 huhuhang
。
我们就可以将这个数据接口配置到 Retool,然后使用 Retool 里面的组件呈现数据即可。打开底部区域,新增一个数据查询:
userInfo
方便后续区分。https://jsonbase.huhuhang.workers.dev/sspai/api/v1/user/huhuhang/info/get
接下来,我们就可以在界面上呈现这些数据了,步骤如下:
上述组件的最终的摆放效果大致如下:
此时,你会发现拖动到界面上的组件并不会像上图一样展示正确的数据。我们需要从上一步的 userInfo
数据查询结果中读取相应的数据,然后配置到组件中。在这里需要介绍一下 Retool 中解析动态数据的语法,你可以使用 {{ }}
左右两个花括号来解析动态数据。
我们以头像为例,你可以在 URL 配置项中输入 {{userInfo.data.data.avatar}}
,就可以从刚刚 userInfo
的数据请求中,逐层解析拿到头像 avatar 的链接。Retool 支持自动补全,帮助快速选择到所需的数据,例如当你输入 {{userInfo.}}
后会自动预览下一级数据,这对不熟悉 JSON 数据结构的用户很有帮助。
但很快你就会发现少数派 API 中只存储了相对链接 2022/04/01/avatar/7f0214727c4c666a32b6a7a7ed9ab19a.png
,对比网站上的头像链接可以看出缺少了 https://cdn.sspai.com/
域名,于是最终的 URL 配置为 https://cdn.sspai.com/{{userInfo.data.data.avatar}}
,成功解析并组合出数据。
同理,你可以解析出用户名数据为 {{userInfo.data.data.nickname}}
。Retool 的 Text 组件支持 Markdown 语法,这里可以直接配置如下:
除了文本字段,Retool 中的 Tags 字段是通过列表 [ ]
来配置数据的。例如粉丝和关注数据,我们可以配置成:
[{{"粉丝 "+userInfo.data.data.followed_count.toLocaleString('en-US')}}, {{"关注 "+userInfo.data.data.following_count.toLocaleString('en-US')}}]
解释一下,Retool 中的 {{ }}
中支持直接使用 Javascript 语法处理数据。例如上方我们将解析得到的粉丝整数,加上 .toLocaleString('en-US')
处理成有逗号分隔符的英文数字书写方式。同时使用 +
将两个字符串合并在一起。
这一步相对于上一步,我们需要使用到简单的 Javascript 代码,这也就是为什么低代码并非零代码。当然,小白也无需担心和畏惧代码。你可以在搜索引擎中输入自己的需求 + Javascript 关键字来查找代码片段,从而实现自己想要的功能。
同理,如果你注意观察原始数据,少数派只提供了用户的创建时间字段 {{userInfo.data.data.created_at}}
。这里返回的并非我们想要的天数,而是 Unix 时间戳(秒)。我们同样需要通过 Javascript 代码将其处理成我们需要的天数。
[{{"成为少数派 "+Math.round((new Date().getTime()/1000-userInfo.data.data.created_at)/(3600*24)).toLocaleString('en-US')+" 天"}}]
解释一下这段代码:
new Date().getTime()/1000
获取当前时刻的 Unix 时间戳(秒)。userInfo.data.data.created_at
之后得到当前时刻距离创建时刻的秒数。3600*24
,得到当前时刻距离创建时刻的天数,为浮点数。Math.round
将浮点数转换为整数。.toLocaleString('en-US')
转换整数为逗号分隔展示。作者信息中,比较复杂的是作者勋章的展示。观察 API 返回的原始数据,可以看到勋章的数据主要集中在 user_badges
,user_plan_flags
,user_flags
,user_reward_badges
,user_old_badges
等字段中。
而反观用于展示勋章图片的 Avatar Group 组件配置项时,你发现其 Image URLs,也就是图片链接是需要用类似 Tags 的列表 []
来存储数据。
为了达到目的,我们这里引入一个 Retool 中的新概念 Transformer,即数据转换器。简单来讲,你可以在编辑器下方数据处理区域创建自定义数据转换器,通过编写 Javascript 代码,它可以将某个输入的原始数据按照你想要的样式处理之后返回。
Transformer 让你对数据有了主动权,例如在本次开发过程中,API 返回的数据格式是由少数派控制的,你不可能要求少数派的后端工程师将 API 数据结构改成你需要的样子。但是通过 Transformer 的二次加工,你可以将 API 返回的原始数据处理成任何结构。
接下来,我们创建一个 JavaScript transformer,并重命名为 badges
。
然后编写 Javascript 代码,将原始数据 {{ userInfo.data.data }}
遍历解析其中不同字段中的勋章图片链接,最后组合成列表返回。完整代码如下:
const data = {{ userInfo.data.data }}
badgeIcons = []
badgeNames = []
if (data.user_badges) {
data.user_badges.forEach(badge => {
badgeIcons.push(badge.icon)
badgeNames.push(badge.name)
})
}
if (data.user_plan_flags) {
data.user_plan_flags.forEach(flag => {
badgeIcons.push(flag.icon)
badgeNames.push(flag.name)
})
}
if (data.user_flags) {
data.user_flags.forEach(flag => {
badgeIcons.push(flag.icon)
badgeNames.push(flag.name)
})
}
if (data.user_reward_badges) {
data.user_reward_badges.forEach(badge => {
badgeIcons.push(badge.icon)
badgeNames.push(badge.name)
})
}
if (data.user_old_badges) {
data.user_old_badges.forEach(badge => {
badgeIcons.push(badge.icon)
badgeNames.push(badge.name)
})
}
return { badgeIcons, badgeNames }
我自己也并非前端工程师,仅略懂 Javascript 代码,上述代码可能会比较粗糙。😂
如上图所示的预览界面,最终返回的勋章图片列表 badgeIcons
,其中中包含了作者全部勋章的图片链接。此时回到 Avatar Group 组件配置项,我们读取 Transformer 中返回的数据 {{badges.value.badgeIcons}}
即可。
至此,作者信息的部分就全部处理完毕了。对比一下少数派官方页面的信息,基本一致。✌️
至此,我们实现了可以针对固定作者的信息展示。然而,我们希望能够更换展示指定作者的信息,或者随机展示作者。
我们先尝试达成第一个目标,即对指定用户名(slug
)的作者信息进行展示,而非固定展示某一位作者的信息。这里需要使用的 Retool 的链接参数功能,让我们可以通过 URL 参数传入不同作者的用户名,从而更换作者信息。
首先,从左侧栏顶部创建一个 TEMPORARY STATE 临时变量,选中后在右侧栏重命名其为 slug
,并设置一个默认值。完整操作步骤如下:
如上所示,可以从界面右上角的设置项中找到 URL Parameters 选项,新增参数 slug
,然后配置其值为 {{slug.value}}
,即使用上一步 TEMPORARY STATE 的默认值。
然后,我们重新配置之前的 userInfo
获取用户数据的接口,将其后面固定的用户名改为 {{urlparams.hash.slug}}
,即使用 URL 传入的参数。这样,就可以实现默认情况下使用 URL Parameters 传入 TEMPORARY STATE 的默认值,而又可以手动修改指定的 slug
参数。
刷新页面之后,你就可以看到编辑器 URL 和之前的区别,最末端出现了 slug
参数。尝试手动设置其为其他作者用户名,例如少数派编辑部的 slug=ee0vj778
,回车之后就可以看到指定作者的数据获取成功。
实现随机获取一个少数派作者的信息,理想情况是能够随机从数据库中选择一位作者,但是我们并没有权限操作。所以,你可以尝试从网页中找出一些和作者相关的数据源,例如我们找到 Matrix 社区 右侧推荐作者的板块。
同样,我们提供了此区域的示例 API 链接:https://jsonbase.huhuhang.workers.dev/sspai/api/v1/user/worth/follow/page/get
。
然后,创建一个新的数据请求,命名为 randomAuthor
。
接下来,我们需要进行一些配置。第一步是在 randomAuthor
执行成功时,触发 Set temporary state,随机从返回数据中抽出一位作者的 slug
,并赋值给之前创建的 TEMPORARY STATE。
{{randomAuthor.data.data[Math.floor(Math.random() * randomAuthor.data.data.length)].slug}}
解释一下这部分代码,randomAuthor.data.data.length
是返回作者数组的长度,然后 Math.floor(Math.random() * randomAuthor.data.data.length)
可以从长度上限中随机抽取一个整数。例如,当数据源返回了 5 位作者,则会从 [0, 4]
区间内随机返回一个整数。我们可以利用随机整数作为索引(索引从 0 开始),从原数组 randomAuthor.data.data
抽取一个作者值,并拿到其 slug
。详细配置如下:
接下来,我们在界面右上方拖动一个 Button 按钮组件。选择点击按钮时的触发动作为执行 randomAuthor
,配置如下图所示。这样,我们就可以实现在点击刷新按钮时,重新获取一个作者信息并展示出来。
至此,我们就成功通过 Retool 构建了一个能够展示默认指定作者,并支持随机获取少数派的推荐作者,并将其信息展示在页面上。同时,还支持通过 URL 参数指定展示某位作者的信息。
我们来实现第二个功能,随机展示作者的一篇文章。本文提供了和少数派作者文章 API 数据结构完全一致的示例 API 地址:https://jsonbase.huhuhang.workers.dev/api/v1/article/user/{slug}/page/get
。其中 slug
为作者的用户名。
实现随机获取文章的逻辑和上方随机获取作者差不多。我们可以从作者信息 API 中找到 released_article_count
字段,代表作者累计发布的文章数量。只要生成一个随机数,即可通过数组索引获取到指定位置的 1 篇文章就能达到目的。这样,我们就可以将文章的信息展示在页面上了。
接下来,拖动 1 个新的 Container 容器组件到编辑器中用作文章信息呈现区域,分别放置:
手动调整他们的大小和相对关系大致如下:
然后,我们添加一个新的数据请求 article
,地址为:https://jsonbase.huhuhang.workers.dev/api/v1/article/user/{{urlparams.hash.slug}}/page/get
,其中 {{urlparams.hash.slug}}
是使用 URL 传入的作者用户名。
该数据接口会返回作者的全部文章,我们通过随机索引获取其中的一篇文章即可。这里采用和上面随机作者不同的方式,直接在请求中开启 Transformer 设置,对数据进行转换,代码如下:
return {{article.rawData.data[Math.floor(Math.random() * (userInfo.data.data.released_article_count))]}}
其中,Math.floor(Math.random() * (userInfo.data.data.released_article_count))
是从作者发布的文章总数中获取随机值,得到相应位置的文章。
最后,设置右上角刷新按钮的触发器为执行 article
即可,就能实现手动随机切换文章了。至于文章布局中其他字段的解析这里就不再赘述了,大家可以结合后续完整示例应用配置查看。
至此本次示例的所有功能均已开发完成,我们可以点击界面右上角的 Share 按钮生成一个公开链接,供所有人访问和使用了。
此外,Retool 提供了版本管理的功能,方便控制版本和避免正在开发状态的应用被访问和使用。你可以从右上角的设置项中找到 Releases and history 选项,然后发布版本。
回顾本次案例,我们只涉及到对于现有数据 API 的查询、处理和呈现,并增加了随机作者和随机文章的小功能。其中的难点集中在找到 API 源,对数据的二次处理,以及 Retool 组件的选择和配置。
功能实现的过程实际上是对编程思维和编程逻辑的考验,你需要将功能进行提炼和简化成可以实现的方案,这就是低代码中最难的部分。这些是可以通过不断训练来完成的,当你制作的应用越来越多,对组件的应用更加熟练,就可以开发更多复杂的功能。
这里建议大家模仿本文的案例逻辑,先拿有现成数据源的站点练手,后续再尝试设计数据新增、修改、删除的功能。那么你可能会需要用到数据库,这里推荐大家同样使用低代码工具,如:飞书多维表格,Airtable 等。使用可视化界面快速创建所需的表结构之后,通过工具提供的现有 API 作为后端接口(不需要自己封装接口),前端则使用 Retool 等完成功能和界面的开发,从而快速构建一套基于低代码的前后端分离系统。
最后给出本次示例应用的完整的 JSON 配置,你可以通过 Retool 新建工程时选择导入 JSON,从而看到完整的配置项。
当你真正尝试使用低代码开发一个简单的案例之后,我相信你对低代码有了更深刻的理解。日常的工作中,往往都会存在一些高频且重复的事情。很多时候,我们都可以通过开发适合自己的工具来提升效率并减少重复工作带来的倦怠感。
而当我们下定决心学习一门编程语言之后,往往很难在短时间内构建一款真正可用的工具,这会让人非常失望。此时,低代码可以算作捷径,其不需要大量的基础代码编写、不需要考虑到代码的部署和服务器的维护、不需要耗费大量的金钱和时间。大部分情况下,我们甚至无需掌握丰富的前置知识,只需要秉着实用主义的精神,在搜索引擎的帮助下就可以快速实现自己的想法。
当然,目前低代码的普及还存在很多困难。首先是低代码并非零代码,对于业务人员而言,掌握基础的编程语言和具备基本的编程思维仍然存在门槛,而熟悉编程语言的人往往更喜欢直接写代码而非使用低代码。此外,低代码产品本身也很存在诸多问题亟待解决,部分工具复杂的配置让人感觉到还不如直接编写代码。
但终究我还是看好低代码未来的发展,一定存在更好的解决方案等待突破,真正从低代码到零代码,让业务人员快速上手。回顾编程发展史,从汇编语言到高级语言,从面向对象的出现,到如今提倡模块化和组件化,软件开发行业不也在向低代码过渡吗?我相信让更多普通人掌握简单的编程方法,解放专业程序员承担更具挑战性的工作一定是大势所趋。
> 下载 少数派 2.0 客户端、关注 少数派公众号,解锁全新阅读体验 📰
> 实用、好用的 正版软件,少数派为你呈现 🚀
© 本文著作权归作者所有,并授权少数派独家使用,未经少数派许可,不得转载使用。