{T}

Blessed 技术文档

基本介绍

blessed 是基于 Node.js 的、功能强大且高级的终端界面创建库(Cursed-like library)。它的核心定位是让开发者能够利用 JavaScript,像构建网页应用一样,轻松地在命令行终端中创建复杂、美观、交互丰富的图形用户界面(TUI)

blessed 通过抽象底层的终端控制序列(如 terminfotermcap),提供一套面向对象的 API,开发者可以通过声明式的方式定义和组织各种 UI 组件,而无需关心具体的终端类型和控制代码

bash
pnpm install blessed

主要应用场景

blessed 的应用场景非常广泛,几乎涵盖了所有需要在终端中提供丰富交互体验的场合:

  • 命令行工具(CLI):为传统的命令行工具增加图形化配置界面、进度显示、实时日志查看等功能,提升用户体验
  • 仪表盘(Dashboards):创建实时监控系统的数据仪表盘,例如服务器状态监控、应用性能指标(APM)、加密货币行情看板等
  • 交互式终端应用:开发功能完整的终端应用程序,如文件管理器、代码编辑器、聊天客户端、任务管理器等
  • 游戏开发:制作复古风格的终端游戏

与其他类似库的对比

blessed 经常被拿来与 ncurses(及其 Node.js 包装)等传统 TUI 库进行比较

特性blessedncurses
抽象层次高层抽象。提供了面向对象的组件模型,更接近现代 GUI 框架底层库。提供更基础的窗口和字符控制功能,API 相对原始
开发效率。声明式 API 和丰富的内置组件可以快速构建复杂界面较低。需要手动管理窗口、屏幕刷新和事件循环,开发周期较长
布局系统现代化。支持类似 CSS 的布局和样式配置,支持百分比、相对定位等基础。通常需要手动计算坐标和尺寸
事件模型强大。内置了完善的事件系统,支持鼠标、键盘、窗口事件基础。事件处理相对简单,需要开发者自行实现复杂的事件逻辑
社区生态活跃。拥有丰富的第三方插件和组件,如 blessed-contrib非常成熟。作为事实上的标准,拥有庞大的用户基础和长期的技术积累
性能良好。针对 Node.js 环境进行了优化,但对于极端性能场景可能不如 C/C++ 库极高。作为 C 语言库,性能非常出色

总而言之,blessed 以牺牲部分底层控制和极致性能为代价,换来了极高的开发效率和更现代化的开发体验,特别适合需要快速迭代和构建复杂界面的 Node.js 项目

技术特性

支持的终端 UI 组件类型

blessed 内置丰富的 UI 组件(官方称为 ElementNode),基本可以满足绝大部分 TUI 应用的需求。所有组件都继承自基类 ElementNode

基础容器

  • Element: 所有可见组件的基类,提供基础的样式和布局能力
  • Box: 一个简单的矩形容器,可用于布局和内容承载,类似 HTML 中的 <div>
  • Screen: 根节点,代表整个终端屏幕,是所有其他组件的顶级容器

文本与内容

  • Text: 显示纯文本内容
  • Line: 绘制水平或垂直的线条
  • BigText: 使用 ASCII 字符绘制大字体文本
  • Log: 可滚动的日志输出组件,适合显示实时日志
  • Markdown: 解析并渲染 Markdown 格式的文本

交互式组件

  • List: 可选择的列表,支持键盘导航
  • Listbar: 水平菜单栏,类似传统 GUI 应用的顶部菜单
  • File-Manager: 一个简单的文件浏览器组件
  • Form: 表单容器,用于管理输入型组件
  • Input, Textbox, Textarea: 不同形式的文本输入框
  • Button: 可点击的按钮
  • Checkbox: 复选框
  • RadioSet & RadioButton: 单选按钮组
  • Prompt: 弹出一个提示框,等待用户输入
  • Question: 弹出一个确认对话框(Yes/No)

数据可视化

  • ProgressBar: 进度条
  • Table: 渲染表格数据
  • ListTable: 结合了 ListTable 的功能,即可选择的表格

其他

  • Terminal: 在 blessed 界面中嵌入一个真实的终端会话
  • Image: 显示图片(通过 Sixel 图形格式或 iTerm2 的内联图像协议)

事件处理机制

blessed 拥有一个强大的、类似 DOM 的事件系统。每个组件都是一个事件发射器(EventEmitter),可以监听和响应各种事件

键盘事件: screen 对象和可聚焦的组件(如 InputList)可以监听键盘事件

  • keypress: 任何按键被按下时触发
  • key [name]: 特定按键被按下时触发,例如 key enter
  • once('keypress', ...): 监听一次按键事件

鼠标事件: 需要在创建 screen 时设置 sendFocus: truesmartCSR: true 来启用鼠标支持

  • mousedown, mouseup, mousemove: 鼠标按键按下、抬起和移动
  • wheeldown, wheelup: 鼠标滚轮事件
  • click: 组件被点击时触发
  • focus, blur: 组件获得或失去焦点时触发

组件生命周期与状态事件:

  • attach, detach: 组件被添加或移除出渲染树。
  • show, hide: 组件可见性改变。
  • move, resize: 组件位置或尺寸改变。
  • prerender, render: 组件渲染前后触发。

事件可以进行冒泡。如果在子组件上触发了一个事件,但没有被处理,它会向上传递到父组件,直到 screen 对象。可以通过 event.stopPropagation() 来阻止事件冒泡。

布局系统与样式配置方式

blessed 的布局和样式系统非常灵活,其设计思想借鉴了 CSS

尺寸与定位:

  • 绝对定位: top, left, right, bottom 可以是数字(字符数)或百分比字符串('50%'
  • 尺寸: width, height 同样支持数字和百分比
  • 相对定位: 可以将 top, left 等设置为相对于父容器中心的值,例如 left: 'center'
  • 偏移量: 支持在百分比或中心对齐的基础上进行微调,例如 top: '50%-5'

样式配置 (style 对象):

  • 颜色: fg (前景色), bg (背景色)。可以是颜色名称('red')、十六进制值('#ff0000')或 256 色索引
  • 文本属性: bold, underline, blink, inverse (反色)
  • 边框 (border 对象):
    • type: 'line' (默认) 或 'bg' (使用背景色填充)
    • ch: 用于绘制边框的字符,默认为 (空格)
    • fg, bg: 边框颜色。
  • 状态样式: style 对象中可以包含 hover (鼠标悬停), focus (获得焦点), selected (列表项被选中) 等伪类的样式
javascript
const box = blessed.box({
  parent: screen,
  top: "center",
  left: "center",
  width: "80%",
  height: "90%",
  border: {
    type: "line",
    fg: "cyan"
  },
  style: {
    fg: "white",
    bg: "blue",
    hover: {
      bg: "green"
    }
  }
})

跨平台兼容性说明

blessed 致力于提供良好的跨平台兼容性,能在绝大多数现代终端模拟器上运行,包括:

  • Linux: xtermgnome-terminalkonsoleterminator
  • macOS: Terminal.appiTerm2
  • Windows: cmd.exePowerShellWindows Terminal。在 Windows 上,blessed 会尝试使用 windows-curses 作为后端,以提供更好的兼容性

尽管 blessed 做了很多兼容性工作,但某些高级特性(如图片显示、24 位真彩色)仍然依赖于特定终端的支持

  • 颜色支持: blessed 会自动检测终端支持的颜色数量(2、8、16、256、16777216),并尽可能优雅降级
  • 字符集: 建议使用 UTF-8 编码的终端,以确保特殊字符和宽字符(如中文)能正确显示

在开发时,如果遇到平台相关的显示问题,通常需要检查终端本身的配置(如字体、编码、TERM 环境变量等)

核心 API 文档

blessed 的 API 设计是面向对象的,理解其核心类和方法是高效开发的关键

关键类与方法说明

blessed.screen(options)

screenblessed 应用的根节点和心脏。它继承自 Box,并负责管理全局状态、事件循环和屏幕渲染

  • 构造函数: blessed.screen(options)

    • options (Object): 配置对象。
      • smartCSR (Boolean): true (默认) 启用智能光标渲染优化,可以大幅提升性能。
      • sendFocus (Boolean): true (默认) 使能 focusblur 事件,是鼠标支持所必需的。
      • autoPadding (Boolean): true (默认) 自动为带边框的元素计算内边距。
      • dockBorders (Boolean): true (默认) 边框停靠在元素边缘。
      • fullUnicode (Boolean): true (默认) 开启完整的 Unicode 支持,正确处理宽字符。
      • terminal (String): 指定终端类型,覆盖 process.env.TERM
  • 关键方法:

    • screen.render(): 手动触发一次全屏重绘。blessed 会自动批量处理更新,但有时需要手动调用。
    • screen.destroy(): 销毁 screen 和所有子元素,恢复终端到原始状态。
    • screen.key(keys, listener): 注册全局快捷键。例如 screen.key(['q', 'C-c'], () => process.exit(0));
    • screen.append(element): 将一个元素添加到 screen 中。
    • screen.remove(element): 从 screen 中移除一个元素。

blessed.node(options) (基类)

Node 是所有组件的顶层基类,主要负责组件树的层级关系(父子、兄弟节点)

  • 核心属性:

    • parent: 父节点
    • children: 子节点数组
    • type: 组件类型字符串(如 'box'
  • 核心方法:

    • append(element): 添加一个子节点
    • prepend(element): 在子节点列表的开头添加一个节点
    • remove(element): 移除一个子节点
    • insert(element, index): 在指定索引处插入一个子节点
    • emit(event, ...args): 触发一个事件
    • on(event, listener): 监听一个事件

blessed.element(options) (基类)

Element 继承自 Node,是所有可见组件的基类。它添加了位置、尺寸、样式和内容等视觉相关的属性和方法

  • 核心属性:

    • options (Object): 包含所有配置,如 top, left, width, height, style, border, content
    • width, height, top, left: 最终计算出的尺寸和位置
    • content (String): 组件显示的文本内容
  • 核心方法:

    • show(): 显示组件
    • hide(): 隐藏组件
    • toggle(): 切换可见性
    • focus(): 使组件获得焦点
    • setContent(text): 设置组件的文本内容
    • setFront(): 将组件置于其兄弟节点的顶层
    • setBack(): 将组件置于其兄弟节点的底层

blessed.box(options)

Box 是最常用的基础容器组件,继承自 Element。它本身没有太多特殊功能,主要用于布局和作为其他组件的容器

常用配置参数详解

以下是一些在创建组件时最常用的配置参数:

  • parent (Node): 必需。指定该组件的父节点,通常是 screen 或另一个容器组件
  • top, left, right, bottom (Number | String): 控制位置。可以是数字(行/列),或字符串('center''50%''50%-2'
  • width, height (Number | String): 控制尺寸。规则同上
  • content (String): 要显示的文本内容。可以使用 blessed 的标签语法进行样式设置,例如 'Hello {bold}world{/bold}!'
  • label (String | Object): 在边框上显示的标签。如果是对象,可以设置 { text: 'Label', side: 'left' }
  • border (Object | String): 边框样式。如果是字符串,则指定 type。对象可以包含 type, ch, fg, bg
  • style (Object): 样式对象,包含 fg, bg, bold, underline, hover, focus
  • hidden (Boolean): true 则初始状态为隐藏
  • scrollable (Boolean): true 使内容可滚动(通过鼠标或按键)
  • keys (Boolean): true 使组件可以接收键盘事件
  • mouse (Boolean): true 使组件可以接收鼠标事件
  • vi (Boolean): true 为可滚动组件启用 vi 风格的导航键(k, j, g, G
  • tags (Boolean): true (默认) 启用内容中的标签语法

生命周期管理最佳实践

  1. 总是指定 parent: 创建任何组件时,都必须明确其 parent。这能确保组件被正确地添加到组件树中并进行渲染。

  2. 使用 screen.destroy() 清理: 当你的应用程序退出时,务必调用 screen.destroy()。这会恢复终端到原始模式,移除所有监听器,并销毁所有子组件,防止终端状态混乱。

  3. 合理使用 render(): blessed 会在内部对 render 调用进行优化和节流。通常你不需要频繁地手动调用 screen.render()。只有在进行了大量同步更新后,希望立即看到变化时,才需要手动调用。

  4. 动态添加和移除组件: 使用 parent.append(child)child.destroy() (或 parent.remove(child)) 来动态管理界面元素。destroy() 会彻底清理组件及其子组件,并移除所有相关的监听器,是比 remove 更彻底的清理方式。

  5. 事件监听器管理: 在 destroy 组件时,blessed 会自动移除该组件上通过 .on() 方法添加的监听器。这避免了常见的内存泄漏问题

javascript
// 退出逻辑
screen.key(["q", "C-c"], (ch, key) => {
  // 在退出前销毁 screen 对象
  return screen.destroy()
})

代码示例

理论结合实践是最好的学习方式。以下是一些从简到繁的代码示例

基础 Hello World

这是一个最简单的 blessed 应用,它会在屏幕中央显示一个带边框的文本框

javascript
// hello-world.js
const blessed = require("blessed")

// 创建一个 screen 对象
const screen = blessed.screen({
  smartCSR: true,
  title: "Hello Blessed!"
})

// 创建一个 box 组件
const box = blessed.box({
  parent: screen,
  top: "center",
  left: "center",
  width: "50%",
  height: "50%",
  content: "Hello {bold}world{/bold}!",
  tags: true,
  border: {
    type: "line"
  },
  style: {
    fg: "white",
    bg: "magenta",
    border: {
      fg: "#f0f0f0"
    }
  }
})

// 监听 'q' 或 'Ctrl+C' 按键事件,用于退出程序
screen.key(["q", "C-c"], (ch, key) => {
  return process.exit(0)
})

// 渲染屏幕
screen.render()

List 组件

创建 list.js

  • 在 blessed 里根组件是 screen,所有的小组件都要 screen.append 来添加
  • 指定 fullUnicode: true 这样可以支持中文字符
  • 然后创建 list 组件,指定 width、height、align、border,还有颜色,以及 items 数据
  • blessed 可以通过键盘控制,还支持鼠标控制
javascript
import blessed from "blessed"

const screen = blessed.screen({
  fullUnicode: true
})

const data = [
  "白夜行",
  "解忧杂货店",
  "挪威的森林",
  "追风筝的人",
  "小王子",
  "飘",
  "麦田里的守望者",
  "时间简史",
  "人类简史",
  "活着为了讲述",
  "白夜行",
  "百鬼夜行"
]

const list = blessed.list({
  width: "50%",
  height: "50%",
  border: "line",
  label: "书籍列表",
  align: "left",
  right: 0,
  bottom: 0,
  keys: true,
  mouse: true,
  style: {
    fg: "white",
    bg: "default",
    selected: {
      bg: "blue"
    }
  },
  items: data
})

screen.append(list)

list.select(0)

list.on("select", function (item) {
  screen.destroy()
  console.log(item.getText())
})

screen.key("C-c", function () {
  screen.destroy()
})

list.focus()

screen.render()

运行文件:

bash
node list.js

Form 组件

创建 form.js

javascript
const blessed = require("blessed")

const screen = blessed.screen({
  fullUnicode: true
})

const prompt = blessed.prompt({
  parent: screen,
  border: "line",
  height: "shrink",
  width: "half",
  top: "center",
  left: "center",
  label: " {blue-fg}登录{/blue-fg} ",
  tags: true
})

const msg = blessed.message({
  parent: screen,
  border: "line",
  width: "half",
  height: "shrink",
  top: "center",
  left: "center",
  label: " {blue-fg}提示{/blue-fg} ",
  tags: true,
  hidden: true
})

prompt.input("你的用户名?", "", function (err, username) {
  prompt.input("你的密码?", "", function (err, password) {
    if (username === "guang" && password === "aaa123") {
      msg.display("登录成功!", 1)
    } else {
      msg.display("用户名或密码错误!", 1)
    }

    setTimeout(function () {
      screen.destroy()

      console.log(username, password)
    }, 1000)
  })
})

screen.key("C-c", function () {
  screen.destroy()
})

screen.render()

File Manager

创建 filemanger.js

javascript
import blessed from "blessed"

const screen = blessed.screen({
    fullUnicode: true
});

const fm = blessed.filemanager({
    parent: screen,
    border: 'line',
    height: 'half',
    width: 'half',
    top: 'center',
    left: 'center',
    label: ' {blue-fg}%path{/blue-fg} ',
    cwd: process.cwd(),
    keys: true,
    style: {
        selected: {
            bg: 'blue'
        }
    },
    scrollbar: {
        bg: 'white'
    }
});

fm.on('file', (file)=> {
    screen.destroy();

    console.log(file);
})

screen.key('C-c', function() {
    screen.destroy();
});

fm.refresh();

screen.render();

Table 组件

创建 table.js

javascript
const blessed = require("blessed")

const screen = blessed.screen({
  fullUnicode: true
})

const table = blessed.table({
  parent: screen,
  width: "80%",
  height: "shrink",
  top: "center",
  left: "center",
  data: null,
  border: "line",
  align: "center",
  tags: true,
  style: {
    border: {
      fg: "white"
    },
    header: {
      fg: "blue",
      bold: true
    },
    cell: {
      fg: "green"
    }
  }
})

const data = [
  ["姓名", "性别", "年龄", "电话号码"],
  ["东东", "男", "20", "13233334444"],
  ["光光", "男", "20", "13233332222"],
  ["小红", "女", "21", "13233335555"],
  ["小刚", "男", "22", "13233336666"]
]

data[1][0] = "{red-fg}" + data[1][0] + "{/red-fg}"

table.setData(data)

screen.key("C-c", function () {
  screen.destroy()
})

screen.render()

ProgressBar 组件

创建 progressbar.js

javascript
import blessed from "blessed"

const screen = blessed.screen({
    fullUnicode: true
});

const progressBar = blessed.progressbar({
    parent: screen,
    top: '50%',
    left: '50%',
    height: 2,
    width: 20,
    style: {
        bg: 'gray',
        bar: {
            bg: 'green'
        }
    }
})

screen.key('C-c', function() {
    screen.destroy();
});

let total = 0;
const timer = setInterval(() => {
    if(total === 100) {
        clearInterval(timer);
    }

    progressBar.setProgress(total)
    screen.render();

    total += 2;
}, 100);

screen.render();

性能优化指南

尽管 blessed 提供了很高的开发效率,但在构建复杂或高刷新率的 TUI 应用时,性能问题仍然值得关注。以下是一些关键的性能优化技巧。

渲染性能优化技巧

  1. 保持 smartCSR: true:

    这是最重要的性能开关,它在 screen 的默认配置中是开启的。smartCSR (Smart Cursor and Screen Rendering) 机制会计算出屏幕上真正发生变化的区域,并只更新这部分内容,而不是每次都重绘整个屏幕。这能极大地减少终端的 I/O 操作

  2. 减少不必要的 screen.render() 调用:

    blessed 会在事件循环的下一个 tick 中自动批量处理更新并调用 render。除非你确实需要立即看到更新,否则应避免手动、高频地调用 screen.render()。例如,在一个循环中更新多个组件时,只需在循环结束后让 blessed 自动渲染一次即可

  3. 使用 box 作为静态背景:

    如果你的界面有复杂的静态背景(例如,由很多 box 组成的边框或图案),可以考虑将它们组合在一个大的 box 中,并尽量避免重绘它。将动态内容放在这个静态背景的上层

  4. 隐藏不可见的元素:

    如果一个元素暂时不需要显示,使用 element.hide() 将其隐藏。被隐藏的元素不会参与渲染计算,可以减轻 blessed 的工作量。对于弹出式窗口或标签页界面,这一点尤其重要

  5. 避免复杂的文本标签 (tags):

    虽然 {bold} 等标签很方便,但 blessed 需要解析这些标签并转换为终端序列。对于需要频繁更新的大段文本,如果其中不包含样式变化,可以考虑设置 tags: false 来关闭标签解析,从而获得微小的性能提升

内存管理注意事项

  1. 及时销毁不再使用的组件:

    当一个组件(尤其是包含大量子组件或持有大量数据的组件,如 LogList)不再需要时,应该调用 element.destroy() 来销毁它。destroy 方法会:

    1. 从其父节点中移除自己
    2. 递归销毁所有子节点
    3. 移除自身所有的事件监听器 这能有效地释放内存,防止内存泄漏
  2. 谨慎处理 Log 组件:

    Log 组件默认会缓存所有添加的日志行,以便用户可以回滚查看。如果日志量非常大,这可能会消耗大量内存。可以考虑:

    1. 设置 scrollback 选项,限制缓存的行数
    2. 定期手动清理 Log 内容,例如 logger.setContent('')
  3. 管理外部数据引用:

    确保在组件的事件监听器中引用的外部对象能够被垃圾回收。如果一个组件被销毁了,但外部还有一个对象持有对它的引用,或者它的监听器闭包中引用了不会被释放的外部对象,都可能导致内存泄漏

大尺寸界面处理建议

  1. 分页和虚拟滚动:

    对于需要显示大量数据(成千上万行)的列表或表格,不要一次性将所有数据都添加到组件中。应该实现分页逻辑,或者像虚拟滚动一样,只向组件中添加当前视口内可见的数据项。当用户滚动时,动态地更新组件的内容

  2. 延迟加载组件:

    对于复杂的、由多个页面或标签组成的 TUI,可以采用延迟加载的策略。只在用户切换到某个页面或标签时,才创建和渲染该页面所需的组件,而不是在启动时就创建所有组件

  3. 简化布局计算:

    blessed 的百分比和 center 布局非常方便,但每次 render 都需要重新计算。对于一个固定的、网格化的布局,可以考虑在启动时计算好所有组件的绝对位置和尺寸,之后不再改变。这可以减少 blessed 在渲染时的布局计算开销

  4. 测试不同终端的性能:

    不同的终端模拟器在处理大量数据输出时的性能差异可能很大。例如,iTerm2Alacritty (GPU 加速) 通常比 Terminal.appxterm 在高吞吐量下的表现更好。如果你的应用对性能要求很高,建议在目标用户常用的高性能终端上进行测试和优化

生态系统

blessed 拥有一个虽然不大但相当活跃的生态系统,提供了许多实用的插件和工具,可以极大地扩展其功能。

blessed 官方并未维护一个正式的插件列表,但其社区贡献了大量高质量的模块。

常用第三方扩展

  • blessed-contrib: 这是 blessed 生态系统中最著名、最强大的扩展包。它提供一系列用于构建仪表盘(Dashboard)的高级组件,包括:

    • Grid: 一个网格布局系统,可以轻松地将屏幕划分为多个区域
    • Line Chart: 实时折线图
    • Bar Chart: 柱状图
    • Stacked Bar Chart: 堆叠柱状图
    • Map: 在终端中显示世界地图
    • Donut: 甜甜圈图
    • Gauge: 仪表盘式的计量器
    • Sparkline: 紧凑的迷你折线图
    • LCD Display: 模拟 LCD 数字显示效果

    blessed-contrib 是构建监控类 TUI 应用的首选工具

  • blessed-xterm: 允许你在 blessed 应用中嵌入一个功能完整的 xterm 终端。这比 blessed 内置的 Terminal 组件功能更强大,因为它直接使用了 node-ptyxterm.js 的部分代码,提供了更真实的终端模拟

  • blessed-react: 使用 React 的声明式语法和 JSX 来构建 blessed 界面。它将 React 组件的生命周期和状态管理与 blessed 的渲染能力结合起来,使得构建复杂的、状态驱动的 TUI 更加方便

  • blessed-vue: 类似于 blessed-react,但面向 Vue.js 开发者。它允许你使用 Vue 的模板语法和组件化思想来开发 TUI

调试工具链

调试 blessed 应用可能比调试传统的 Node.js 应用要棘手一些,因为程序的输出被 blessed 的界面占用了。以下是一些有效的调试方法:

  1. 使用日志文件: 这是最简单直接的方法。不要使用 console.log(因为它会扰乱 blessed 的屏幕渲染),而是将调试信息写入到一个单独的日志文件中。

    javascript
    const fs = require("fs")
    function debugLog(message) {
      fs.appendFileSync("debug.log", `[${new Date().toISOString()}] ${message}\n`)
    }
    
    // 在你的代码中
    debugLog("Something happened")
  2. 使用 blessed.log 组件: 在你的界面中专门开辟一个 Log 组件用于调试。你可以将需要观察的变量或事件信息实时输出到这个组件中。

  3. Node.js 内置调试器: 你可以使用 Node.js 的内置调试器。通过 node inspect your-app.js 启动应用。然后你可以在另一个终端或 Chrome DevTools 中连接到调试服务。但这对于 TUI 来说可能体验不佳,因为断点会冻结整个界面。

  4. VS Code 调试器: 配置 VS Code 的 launch.json 文件来进行调试是比较推荐的方式。你需要将调试控制台设置为一个外部或集成的终端,而不是默认的调试控制台。

    json
    // .vscode/launch.json
    {
      "version": "0.2.0",
      "configurations": [
        {
          "type": "node",
          "request": "launch",
          "name": "Launch Blessed App",
          "program": "${workspaceFolder}/your-app.js",
          "console": "integratedTerminal" // 或 "externalTerminal"
        }
      ]
    }

    这样,你的 blessed 应用会运行在一个独立的终端窗口中,而你可以在 VS Code 中设置断点、检查变量。

典型组件组合案例

这个例子演示组合使用 ListbarListBox 来创建一个简单的交互式应用

javascript
// layout-example.js
const blessed = require("blessed")

const screen = blessed.screen({
  smartCSR: true,
  title: "Component Layout Example"
})

// 顶部菜单栏
const menu = blessed.listbar({
  parent: screen,
  top: 0,
  left: 0,
  right: 0,
  height: 1,
  items: {
    File: () => showContent("File Content"),
    Edit: () => showContent("Edit Content"),
    View: () => showContent("View Content"),
    Help: () => showContent("Help Content"),
    Exit: () => process.exit(0)
  },
  style: {
    bg: "blue",
    item: {
      bg: "red",
      hover: {
        bg: "green"
      }
    },
    selected: {
      bg: "green"
    }
  }
})

// 内容显示区域
const contentBox = blessed.box({
  parent: screen,
  top: 1,
  left: 0,
  right: 0,
  bottom: 0,
  content: "Select an item from the menu...",
  padding: 1,
  style: {
    bg: "#222"
  }
})

function showContent(text) {
  contentBox.setContent(text)
  screen.render()
}

screen.key(["q", "C-c"], () => process.exit(0))

menu.focus()
screen.render()

高级功能实现示范

此示例展示使用 Log 组件实时显示日志,并使用 Prompt 与用户进行交互

javascript
// advanced-example.js
const blessed = require("blessed")

const screen = blessed.screen({ smartCSR: true, title: "Advanced Example" })

// 日志窗口
const logger = blessed.log({
  parent: screen,
  top: 0,
  left: 0,
  width: "70%",
  height: "100%",
  border: "line",
  label: "Real-time Log",
  scrollable: true,
  alwaysScroll: true,
  scrollbar: { ch: " ", track: { bg: "cyan" } },
  keys: true,
  vi: true
})

// 控制按钮
const sendButton = blessed.button({
  parent: screen,
  top: 1,
  right: 1,
  width: "25%",
  height: 3,
  content: "Send Command",
  align: "center",
  valign: "middle",
  border: "line",
  style: {
    fg: "white",
    bg: "green",
    hover: { bg: "darkgreen" }
  }
})

// 模拟日志输出
let logCounter = 0
setInterval(() => {
  logger.log(`Log entry ${++logCounter} at ${new Date().toLocaleTimeString()}`)
}, 1000)

// 按钮点击事件
sendButton.on("press", () => {
  const prompt = blessed.prompt({
    parent: screen,
    top: "center",
    left: "center",
    height: "shrink",
    width: "shrink",
    border: "line",
    label: "Input Command"
  })
  prompt.input("Enter command:", "", (err, value) => {
    if (value) {
      logger.log(`> Command received: ${value}`)
    }
    screen.render()
  })
})

screen.key(["q", "C-c"], () => process.exit(0))

screen.render()