直接跳到内容

Textual-vuepy 快速上手

Textual-vuepy 是基于 Vue.py 和 Textual 构建终端 TUI(Text User Interface)应用的组件库。它让你使用 Vue.py 的响应式开发体验来编写运行在终端中的交互式应用:

  • 丰富的终端组件 — 直接映射 Textual 所有内置 Widget,开箱即用
  • 响应式 SFC 开发 — 与 IPywUI/Panel-vuepy 使用完全相同的 .vue 文件语法
  • TCSS 样式支持 — 在 <style lang="tcss"> 块中编写 Textual CSS
  • VueUse 工具集onKeyStrokeuseMouse 等键鼠事件组合式函数
  • 一键运行 — 通过 vuepy run 命令行直接运行 .vue 文件

安装

sh
pip install 'vuepy-core[textual]'

运行应用

命令行运行(推荐)

使用 vuepy run 命令直接运行 .vue 文件(默认使用 textual 后端):

sh
vuepy run App.vue

开发模式(启用 Textual devtools):

sh
vuepy run App.vue --dev

通过 textual-serve 以 Web 方式访问(需安装 pip install textual-serve):

sh
vuepy run App.vue --servable --serve-port 8000

查看所有内置可运行的应用名称:

sh
vuepy run --help

代码方式运行

import_sfc
使用插件
python
from vuepy import create_app, import_sfc

App = import_sfc('App.vue')
app = create_app(App, backend='textual')
app.mount()

第一个 Textual-vuepy 应用

创建 App.vue 文件:

vue
<template>
  <VBox style="height: 1fr; align: center middle;">
    <Label :label="f'Count: {count.value}'" />
    <HBox>
      <Button label="+" @click="increment()" />
      <Button label="-" @click="decrement()" />
    </HBox>
  </VBox>
</template>

<script lang="py">
from vuepy import ref

count = ref(0)

def increment():
    count.value += 1

def decrement():
    count.value -= 1
</script>

<style lang="tcss">
VBox {
    height: 1fr;
    align: center middle;
}

Button {
    width: 6;
    margin: 0 1;
}
</style>

运行:

sh
vuepy run App.vue

与 IPywUI 的关键差异

特性IPywUI(Jupyter)Textual-vuepy(终端)
安装vuepy-core[ipywidgets]vuepy-core[textual]
运行环境JupyterLab终端
后端参数backend='ipywidgets'(默认)backend='textual'
样式语言CSSTCSS(Textual CSS)
<style>不支持✅ 支持
HTML 转义✅ 转义(HTML 渲染)❌ 不转义(终端渲染)
访问底层对象-app.tt_app(Textual App 实例)
通知/消息-app.message("text")

ref 获取底层 Widget

通过 ref 引用组件,再调用 .value.unwrap() 获取底层 Textual Widget 对象:

vue
<template>
  <RichLog ref="log_ref" highlight markup />
</template>

<script lang="py">
from vuepy import ref, onMounted

log_ref = ref(None)

@onMounted
def on_mount():
    widget = log_ref.value.unwrap()  # 获取 Textual RichLog widget
    widget.write("[bold green]Hello[/bold green]")
    widget.focus()
</script>

TCSS 样式

<style lang="tcss"> 块中编写 Textual CSS

vue
<template>
  <VBox id="container">
    <Button id="btn-primary" label="主按钮" @click="on_click()" />
  </VBox>
</template>

<style lang="tcss">
#container {
    height: 1fr;
    align: center middle;
    background: #1a1d23;
}

#btn-primary {
    width: 20;
    background: $accent;
    color: $text;
}
</style>

也可以在模板中用 :style 绑定内联 TCSS:

vue
<Button :style="f'width: {width.value}fr;'" label="动态宽度" />

键鼠事件(VueUse)

Textual-vuepy 提供了 VueUse 风格的组合式函数:

vue
<script lang="py">
from textual_vuepy.vueuse import onKeyStroke, useMouse

# 监听键盘按键
def on_ctrl_q(event):
    app.tt_app.exit()

onKeyStroke('ctrl+q', on_ctrl_q)

# 追踪鼠标坐标
mouse_x, mouse_y = useMouse()
</script>

Provide / Inject

通过 TextualProvides.APP_MIXIN 向 Textual App 注入 Mixin,实现自定义按键处理、命令等:

vue
<script lang="py">
from vuepy.compiler_sfc.codegen_backends.textual import TextualProvides

class KeyHandlerMixin:
    def _on_key(self, event) -> None:
        # 将按键信息写入日志
        log_ref.value.unwrap().write(repr(event))

app.provide(TextualProvides.APP_MIXIN, KeyHandlerMixin)
</script>

内置应用

安装 textual_vuepy 后,以下应用已通过 VuepyAppStore 注册,可直接按名称运行:

应用名说明
playground交互式 SFC 编辑器,支持实时预览和文件热重载
keys按键查看器,显示所有键盘事件信息
sh
# 启动内置 Playground
vuepy run playground

# 启动按键查看器
vuepy run keys

下一步

Textual-vuepy 快速上手已经加载完毕