🍵 一杯代码冲泡的珍珠奶茶:Go 语言 Bubble Tea 初探 2024-09-142024-09-14 作者 C3P00 “在命令行里工作很酷,会让你感觉自己像黑客电影里的英雄。” 此言不虚!但是,面对单调乏味的文字瀑布,或者令人望而生畏的命令行参数、美元符号前缀,以及各种莫名其妙的错误信息,我们也难免会感到力不从心。 好在,终端世界里除了冰冷的命令行,还有生机勃勃的 TUI(终端用户界面)。TUI 就像一杯珍珠奶茶,在复古的外表下,蕴藏着现代化的体验。而在 Go 语言的世界里, Bubble Tea 库的出现,让制作 TUI 应用变得像泡一杯奶茶一样简单。 🤔 为什么选择 Bubble Tea? 想象一下,你是一位经验丰富的茶饮师,想要调制一杯独一无二的珍珠奶茶。这时,你会选择什么样的工具呢? Bubble Tea 就如同一个功能强大的工具箱,它提供了以下几个不可抗拒的优势: 熟悉的 Elm 架构: 如果你已经习惯了 React、Vue 或 Elm 等前端框架,那么 Bubble Tea 的 Elm 架构对你来说一定不会陌生。这种架构就像奶茶的配方,清晰易懂,让你轻松上手。 模块化的代码组织: Elm 架构不仅易于理解,而且非常适合构建模块化的 UI 代码。你可以从一个简单的应用开始,逐步添加功能,就像在奶茶中加入珍珠、椰果一样,让你的应用逐渐丰满起来。 简洁易懂的 Go 语言: Go 语言以其简洁一致的语法著称,这使得阅读和理解他人的代码变得轻而易举。就像品尝一杯精心调制的奶茶,你能清晰地感受到每一种成分的味道。 🚀 从 Hello World 开始 俗话说,万事开头难。让我们从一个简单的 “Hello World” 应用开始,体验一下 Bubble Tea 的魅力吧! 首先,创建一个名为 code-journal 的目录,并在终端中运行以下命令: go mod init go get github.com/charmbracelet/bubbletea 然后,创建一个名为 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) } } 接下来,创建另一个名为 simple_page.go 的文件,其中包含我们的第一个 UI,一个只显示一些文本的简单页面: 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 } 在终端中运行以下命令,编译并运行我们的应用: go build ./code-journal 你将会看到如下输出: ************************ * This app is under construction * ************************ Press Ctrl+C to exit 恭喜你!你已经成功运行了你的第一个 Bubble Tea 应用。 🔬 剖析代码 现在,让我们像品尝奶茶一样,细细品味一下这段代码。 🧋 Model:Bubble Tea 的核心 main 函数通过创建一个新的 simplePage 模型来启动程序。 p := tea.NewProgram( newSimplePage( "This app is under construction", ), ) 我们调用了 tea.NewProgram 函数,它的函数签名如下: func NewProgram(initialModel Model) *Program 然后调用该程序的 Start 方法来启动我们的应用程序。但是 initialModel 是什么呢? Model 是 Bubble Tea 的核心接口,它定义了三个方法: type Model interface { Init() Cmd Update(msg Msg) (Model, Cmd) View() string } Init() 方法在应用程序启动时被调用,并返回一个 tea.Cmd。Cmd 可以理解为 “幕后发生的事情”,例如加载数据或计时器。在本教程中,我们没有任何后台操作,因此 Init 方法只返回 nil。 func (s simplePage) Init() tea.Cmd { return nil } View() 方法是 Bubble Tea 中一个很酷的抽象,它将整个 UI 的显示都表示为一个字符串!在 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) } 在上面的代码中,我们将 simplePage 的文本放在一个由星号组成的盒子里,并在底部显示一条消息 “Press Ctrl+C to exit”。 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 } Update() 方法接收一个 tea.Msg 并返回一个新的 tea.Model,有时还会返回一个 tea.Cmd(例如,如果某个操作导致检索数据或计时器启动)。 tea.Msg 的类型签名如下: type Msg interface{} 所以它可以是任何类型,并携带你需要的数据。它有点像 JavaScript 中的浏览器事件;计时器事件不携带任何数据,点击事件会告诉你点击了什么,等等。 我们正在处理的消息类型是 tea.KeyMsg,它表示键盘输入。我们检查用户是否按下了 Ctrl+C. 如果是,则返回 ✅tea.Quit 命令,该命令属于 tea.Cmd 类型,并告诉 Bubble Tea 退出应用程序。 对于任何其他类型的输入,我们不做任何处理,只是按原样返回模型。但是,如果我们正在执行 UI 导航等操作,则会更改模型上的一些字段,然后返回它,从而导致 UI 更新。 ⏭️ 下一站:菜单组件 在下一篇文章中,我们将学习如何创建一个菜单组件,并让我们的应用程序更加生动有趣!敬请期待!
此言不虚!但是,面对单调乏味的文字瀑布,或者令人望而生畏的命令行参数、美元符号前缀,以及各种莫名其妙的错误信息,我们也难免会感到力不从心。
好在,终端世界里除了冰冷的命令行,还有生机勃勃的 TUI(终端用户界面)。TUI 就像一杯珍珠奶茶,在复古的外表下,蕴藏着现代化的体验。而在 Go 语言的世界里,
Bubble Tea
库的出现,让制作 TUI 应用变得像泡一杯奶茶一样简单。🤔 为什么选择 Bubble Tea?
想象一下,你是一位经验丰富的茶饮师,想要调制一杯独一无二的珍珠奶茶。这时,你会选择什么样的工具呢?
Bubble Tea
就如同一个功能强大的工具箱,它提供了以下几个不可抗拒的优势:Bubble Tea
的 Elm 架构对你来说一定不会陌生。这种架构就像奶茶的配方,清晰易懂,让你轻松上手。🚀 从 Hello World 开始
俗话说,万事开头难。让我们从一个简单的 “Hello World” 应用开始,体验一下
Bubble Tea
的魅力吧!首先,创建一个名为
code-journal
的目录,并在终端中运行以下命令:然后,创建一个名为
app.go
的文件,并添加以下代码:接下来,创建另一个名为
simple_page.go
的文件,其中包含我们的第一个 UI,一个只显示一些文本的简单页面:在终端中运行以下命令,编译并运行我们的应用:
你将会看到如下输出:
恭喜你!你已经成功运行了你的第一个
Bubble Tea
应用。🔬 剖析代码
现在,让我们像品尝奶茶一样,细细品味一下这段代码。
🧋
Model
:Bubble Tea 的核心main
函数通过创建一个新的simplePage
模型来启动程序。我们调用了
tea.NewProgram
函数,它的函数签名如下:然后调用该程序的
Start
方法来启动我们的应用程序。但是initialModel
是什么呢?Model
是Bubble Tea
的核心接口,它定义了三个方法:Init()
方法在应用程序启动时被调用,并返回一个tea.Cmd
。Cmd
可以理解为 “幕后发生的事情”,例如加载数据或计时器。在本教程中,我们没有任何后台操作,因此Init
方法只返回nil
。View()
方法是Bubble Tea
中一个很酷的抽象,它将整个 UI 的显示都表示为一个字符串!在View
方法中,你需要构建并返回这个字符串。在上面的代码中,我们将
simplePage
的文本放在一个由星号组成的盒子里,并在底部显示一条消息 “Press Ctrl+C to exit”。Update()
方法负责处理用户输入。Update()
方法接收一个tea.Msg
并返回一个新的tea.Model
,有时还会返回一个tea.Cmd
(例如,如果某个操作导致检索数据或计时器启动)。tea.Msg
的类型签名如下:所以它可以是任何类型,并携带你需要的数据。它有点像 JavaScript 中的浏览器事件;计时器事件不携带任何数据,点击事件会告诉你点击了什么,等等。
我们正在处理的消息类型是
tea.KeyMsg
,它表示键盘输入。我们检查用户是否按下了 Ctrl+C. 如果是,则返回 ✅tea.Quit
命令,该命令属于tea.Cmd
类型,并告诉Bubble Tea
退出应用程序。对于任何其他类型的输入,我们不做任何处理,只是按原样返回模型。但是,如果我们正在执行 UI 导航等操作,则会更改模型上的一些字段,然后返回它,从而导致 UI 更新。
⏭️ 下一站:菜单组件
在下一篇文章中,我们将学习如何创建一个菜单组件,并让我们的应用程序更加生动有趣!敬请期待!