发布于 2026-01-06 1 阅读
0

Go 中的珍珠奶茶入门

Go 中的珍珠奶茶入门

在命令行里操作很酷,能让你感觉自己像黑客电影里的英雄。但它也可能让人觉得老派,单调的文本像雪崩一样铺天盖地;或者让人望而生畏,各种命令行参数、美元符号前缀,以及各种可能在毫无预警的情况下破坏系统的方法,都让人感到不知所措。

但命令行并非使用终端的唯一方式,还有终端用户界面 ( TUI) ,它能让你的程序使用起来更加友好。我非常喜欢 TUI,因为它既有新意又保留了传统特色。最近,Go 语言中的Bubble Tea库以及Charm Bracelet 的所有其他工具都因其简化了 TUI 的创建过程而备受关注。

目前为止,我发现珍珠奶茶最突出的优点有:

  • 它采用与浏览器 UI 框架共享的Elm 架构,因此如果您已经使用过 React、Vue 或 Elm,会感觉很熟悉。
  • Elm架构不仅对现代前端开发人员来说耳熟能详,而且它也是组织UI代码的绝佳方式,因此有利于以易于管理的方式构建应用程序,并逐步扩展其逻辑。
  • 由于是用 Go 语言编写的,其一致的语法有利于通过阅读他人的代码来学习。

在本系列教程中,我将从零开始构建一个基础的 TUI 应用,用于记录你每天学习的代码内容,尤其适合参加 #100Devs 或 #100DaysOfCode 等项目的人。撰写本文时,该应用尚未完成,因此每篇教程都将着重讲解特定的概念。大致的教程路线图如下:

  • 🐣 编写一个简单的 Hello World 应用,看看它的架构是如何运作的
  • 📝 我们正在打造第一个真正的珍珠奶茶组件——菜单
  • ✨ 使用类似 CSS 的Lipgloss库,通过一些样式设计,让我们的菜单看起来更酷炫。
  • 🚇 为我们的应用添加路由功能,以便显示不同的页面
  • 🫧 使用其他人制作的珍珠奶茶组件,并使用Bubbles
  • 📝 将签到信息保存到 JSON 文件

所以,准备好你的终端机和一根珍珠奶茶专用吸管,因为事不宜迟,让我们一起畅享珍珠奶茶吧!

🚧 编写我们的第一个基础应用程序

首先,我们将用 Bubble Tea 创建一个“hello world”应用程序,您可以通过按 Ctrl+C 退出,该应用程序还将向我们介绍 Bubble Tea 应用程序的各个部分。

首先,在名为“code-journal”的新目录中运行:



go mod init
go get github.com/charmbracelet/bubbletea


Enter fullscreen mode Exit fullscreen mode

然后,创建一个名为 `<filename>` 的文件app.go,并添加以下代码:



package main

import (
    tea "github.com/charmbracelet/bubbletea"
)

func main() {
    p := tea.NewProgram(
        newSimplePage("This app is under construction"),
    )
    if err := p.Start(); err != nil {
        panic(err)
    }
}


Enter fullscreen mode Exit fullscreen mode

接下来,我们创建另一个文件,simple_page.go其中包含我们的第一个用户界面,这是一个只显示一些文本的简单页面:


 go
package main

import (
    "fmt"
    "strings"

    tea "github.com/charmbracelet/bubbletea"
)

// MODEL DATA

type simplePage struct { text string }

func newSimplePage(text string) simplePage {
    return simplePage{text: text}
}

func (s simplePage) Init() tea.Cmd { return nil }

// VIEW

func (s simplePage) View() string {
    textLen := len(s.text)
    topAndBottomBar := strings.Repeat("*", textLen + 4)
    return fmt.Sprintf(
        "%s\n* %s *\n%s\n\nPress Ctrl+C to exit",
        topAndBottomBar, s.text, topAndBottomBar,
    )
}

// UPDATE

func (s simplePage) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
    switch msg.(type) {
    case tea.KeyMsg:
        switch msg.(tea.KeyMsg).String() {
        case "ctrl+c":
            return s, tea.Quit
        }
    }
    return s, nil
}


Enter fullscreen mode Exit fullscreen mode

在分析代码之前,我们先运行一下看看它的作用。在终端中运行:



go build
./code-journal


Enter fullscreen mode Exit fullscreen mode

你应该会看到类似这样的内容:

终端显示文本

太棒了!你的第一个奶茶应用已经运行起来了。现在让我们仔细看看代码。

🧋 模型是珍珠奶茶的主要界面

主函数通过使用该模型创建一个新程序来启动程序simplePage



func main() {
    p := tea.NewProgram(
        newSimplePage("This app is under construction"),
    )
    if err := p.Start(); err != nil {
        panic(err)
    }
}


Enter fullscreen mode Exit fullscreen mode

我们称之为tea.NewProgram,其签名是:



func NewProgram(initialModel Model) *Program


Enter fullscreen mode Exit fullscreen mode

然后调用该程序的 Start 方法即可启动我们的应用程序。但是,这是什么意思呢initialModel

Model这是珍珠奶茶的主要界面。它有三种方法:



type Model interface {
    Init() Cmd
    Update(msg Msg) (Model, Cmd)
    View() string
}


Enter fullscreen mode Exit fullscreen mode

Init方法在应用程序启动时调用,并返回一个对象tea.Cmd。对象Cmd大致包含“幕后发生的事情”,例如数据加载或时间流逝。但在本教程中,我们没有任何后台操作,因此我们的init方法仅返回一个对象nil



func (s simplePage) Init() tea.Cmd { return nil }


Enter fullscreen mode Exit fullscreen mode

接下来,我们来看View方法。Bubble Tea 的一个很棒的抽象概念是,你的整个用户界面显示都是一个字符串!View这里就是你创建这个字符串的地方。



func (s simplePage) View() string {
    textLen := len(s.text)
    topAndBottomBar := strings.Repeat("*", textLen + 4)
    return fmt.Sprintf(
        "%s\n* %s *\n%s\n\nPress Ctrl+C to exit",
        topAndBottomBar, s.text, topAndBottomBar,
    )
}


Enter fullscreen mode Exit fullscreen mode

因此,我们将文本放在simplePage一个由星号组成的框中,并在底部添加一条消息:“按 Ctrl+C 退出”。

但是,如果我们的应用程序无法处理用户输入,我们就无法退出,所以这就是我们的Update方法发挥作用的地方。



func (s simplePage) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
    switch msg.(type) {
    case tea.KeyMsg:
        switch msg.(tea.KeyMsg).String() {
        case "ctrl+c":
            return s, tea.Quit
        }
    }
    return s, nil
}


Enter fullscreen mode Exit fullscreen mode

Update方法接收一个参数tea.Msg,并返回一个新的tea.Model参数,有时还会返回一个值tea.Cmd(例如,如果某个操作导致检索到一些数据或计时器响起)。

Atea.Msg的类型签名是



type Msg interface {}


Enter fullscreen mode Exit fullscreen mode

所以它可以是任何类型的事件,并且可以携带任意数量的数据。如果你做过前端开发,它有点像 JavaScript 中的浏览器事件;例如,定时器事件不携带任何数据,点击事件会告诉你点击了什么,等等。

我们正在处理的消息类型是tea.KeyMsg,它代表键盘输入。我们正在检查用户是否按下了 Ctrl+C,如果是,则返回该tea.Quit命令,该命令类型为,tea.Cmd并指示 Bubble Tea 退出应用程序。

对于其他类型的输入,我们什么也不做,直接返回模型原样。但如果我们需要进行一些操作,比如用户界面导航,我们会修改模型中的一些字段,然后再返回,从而更新用户界面。接下来,我们将在下一个教程中创建一个菜单组件,届时就会用到这些内容!

文章来源:https://dev.to/andyhaskell/intro-to-bubble-tea-in-go-21lg