命令行中的加载动画,spinner 的艺术

5,854 阅读2分钟

Tip: GIF 需要点击才会动

当你在做命令行工具的时候,有时会涉及到一些网络请求。在请求的时候如果不反馈点信息给用户给让人很没有「安全感」,换句正式的话说就是用户体验不好。

这正是加载动画存在的理由之一,不仅仅是在终端中,你在网络上随处可见各式各样的加载动画。

在终端中,情况有些不一样,你不能用 CSS 不能用图片,加载动画的效果是靠一些特殊字符来实现,动画的原理不就是让连续的静态画面动起来吗。

原理

CLI spinner 的原理很简单,你需要的是:

  • 一组特殊字符,当它们连贯地动起来的时候能看起来像上面这些动画。

  • 一个定时器,每一个字符看做一帧,定时按顺序切换每帧就能实现「动画效果」。

似乎还有些纰漏,不过可以先试试再找问题:

显而易见,我们应该在同样的位置输出字符,而不是 console.log 这样每次输出都会换行。

我们知道用 \r 可以让终端把光标移到行首,这样再配合 process.stdout.write 输出内容的时候就会是相同的位置了。

最后还有个 edge case 就是,当你的字符只有一个还好说,每次输出新的内容都能覆盖掉,但是如果新的字符串长度大于旧的字符串就会出现这种情况:

终端只会覆盖有新字符的位置,因此过长的部分就永远不会变了。这个时候你需要在输出内容之前清除整行的内容:

process.stdout.clearLine()

这样一个能用的 spinner 就诞生了,多亏前人的实践,现在有了很多有趣的可以

用作 spinner 的字符

,你可以试试不同的效果。

模块推荐

把这个例子封装一个就成了

io-spin

,它额外的功能就是 .stop 停止动画和 .update 更新要显示的文字。顺带说一下 .stop 也很简单,只是清除当前这一行的字符再清理掉之前用来循环的这个 interval 就行了。

另一个更为人性化的模块是

Ora

,它提供了简单的「状态」管理,你可以在某个操作之后设置 spinner 的状态(成功或是失败),这样有更好的显示效果:

当然,这些东西你完全可以亲手动手实现或者改进。有兴趣的话可以来帮助改进

io-spin

呢!