目录

goxui

基于 Gio 的轻量 UI 框架:使用 JS/JSX 描述 UI(返回一棵 VDOM JSON),由 Go/Gio 渲染为原生窗口界面,并把点击/输入事件回传到 JS 驱动重渲染。

当前模块名:gitlink.org.cn/nanakura/goxui

特性

  • JS/JSX 作为 UI 声明入口:App() 返回 VDOM(JSON)
  • 原生渲染:Go + Gio(非 WebView)
  • 事件回传:onClick / onChange / onSubmit 回调由 Go 触发并回传事件 JSON
  • JSX 支持模块化:入口 JSX 可 import 其他 JSX/TSX,启动时由 esbuild 打包为单文件执行

快速开始

运行 JS 示例(无需 CGO)

go run ./cmd/jsgui -script examples/counter.js

运行 JSX 示例(需要 QuickJS + CGO)

Windows 下请确保 gcc/clang 可用:

where gcc
go env CGO_ENABLED CC CXX

运行:

$env:CGO_ENABLED="1"
go run -tags quickjs ./cmd/jsgui -script examples/counter.jsx

运行 Todo 示例(包含多文件 import、弹窗、输入框):

$env:CGO_ENABLED="1"
go run -tags quickjs ./cmd/jsgui -script examples/todo/app.jsx

运行 Go API 示例(在 JSX 中调用 Go 宿主函数):

$env:CGO_ENABLED="1"
go run -tags quickjs ./cmd/jsgui -script examples/goapi/app.jsx

示例说明

项目内置示例:

  • examples/counter.js:最小 JS 示例(ES5)
  • examples/counter.jsx:JSX 示例(需要 -tags quickjs
  • examples/todo/app.jsx:Todo 管理应用(组件拆分在 examples/todo/components/*
  • examples/im/app.jsx:Telegram 风 IM(假数据、多会话、多用户、气泡)
  • examples/widgets/app.jsx:更多组件演示(ScrollView/Checkbox/Switch/Slider/Image)
  • examples/hurlmgr_mock/app.jsx:Hurl Manager UI Mock(Splitter/Tabs/TextArea)
  • examples/flow/app.jsx:Flow 编排控件 MVP(拖拽节点、点击连线、平移画布)

JSX 的 import 行为:

  • 入口 .jsx/.tsx 通过 esbuild 进行 bundle(Format=IIFEGlobalName=__jsguiTarget=ES2020
  • import "./components/XXX.jsx" 会被打包进同一份输出脚本,再交给 QuickJS 执行

VDOM 约定

JS 侧 App() 需要返回一棵可 JSON 序列化的树结构:

{
  type: "View" | "Text" | "Button" | "Input" | "Modal",
  props: { ... },
  children: [ ... ]
}

内置组件

  • View
    • 布局容器,默认纵向;props.direction === "row"style.flexDirection === "row" 为横向
  • Text
    • props.text 文本内容
  • Button
    • props.text 按钮文案
    • props.onClick 点击回调(由 JSX runtime 编译成 handler id)
  • Input
    • props.value 当前文本
    • props.placeholder 占位提示
    • props.onChange(e) 输入变化回调,e.value 为新文本
    • props.onSubmit(e) 提交回调(需要 props.submit=true 或在 JSX 中显式传 submit)
    • props.multiline 多行(默认单行)
  • Modal
    • props.open 是否打开
    • children 约定:<Modal open> {baseUI} {dialogUI} </Modal>
      • baseUI:正常页面
      • dialogUI:弹窗内容(居中显示,并带遮罩)
  • ScrollView
    • 可滚动容器(目前仅纵向),children 按列表渲染
  • Checkbox
    • props.checked: boolean
    • props.text: string
    • props.onChange(e)e.checked 为新值
  • Switch
    • props.checked: boolean
    • props.text: string
    • props.onChange(e)e.checked 为新值
  • Slider
    • props.min/max/value: number
    • props.onChange(e)e.value 为新值(float)
  • Image
    • props.src: string(本地文件路径)
    • props.fit: "contain"|"cover"|"fill"|"scaleDown"|"unscaled"
  • Splitter
    • props.direction: "horizontal"|"vertical"(默认 horizontal)
    • props.ratio: number(初始比例,0~1)
    • children 约定:必须两个子节点(左/右 或 上/下)
  • Tabs / Tab
    • Tabs.props.activeKey: string 当前 Tab key
    • Tabs.props.onChange(e)e.key 为切换目标
    • Tabs.props.onClose(e)e.key 为关闭目标
    • Tab.props.title: string 标题
    • Tab.props.closable: boolean 是否可关闭(默认 true)
  • TextArea
    • props.value/placeholder/onChange 与 Input 相同
    • props.readOnly: boolean 只读
  • Flow
    • props.nodes: Array<{id,title,x,y}>
    • props.edges: Array<{from,to}>
    • props.onChange(e)e.nodes/e.edges 为更新后的数据

JS 调用 Go(宿主函数)

运行时会注入一个全局对象 go,用于从 JS/JSX 调用 Go 实现的函数(示例见 examples/goapi/app.jsx)。

当前内置函数:

  • go.now(): string 返回 RFC3339 时间字符串
  • go.sha256(text: string): string 返回 hex 编码的 sha256
  • go.add(a: number, b: number): number 返回 a+b

自定义注册函数(示例,使用 Ctx 注册并注入到引擎):

package main

import (
    "gitlink.org.cn/nanakura/goxui/host"
    "gitlink.org.cn/nanakura/goxui/internal/js"
)

func Add(a, b int) int { return a + b }

func main() {
    h := host.NewCtx()
    _ = h.Register("Add", Add)
    _ = h.Register("Other", func(s string) string { return "hi " + s })

    engine := js.NewEngineWithHost(h)
    _ = engine.LoadPrelude()
    _ = engine.EvalFile("examples/goapi/app.jsx")
}

注册后即可在 JSX/JS 中调用:

go.Add(2, 40); // 42

style 支持

目前支持的 style 字段(通过 props.style 传入):

  • padding / margin / gap
  • width / height
  • flex(仅影响 View 的子元素在 flex 布局中的比例)
  • flexDirectionrow/column
  • background#RRGGBB#RRGGBBAA
  • color(文本/前景色,#RRGGBB#RRGGBBAA
  • fontSize
  • borderRadius

构建与运行原理(简述)

  • Go 侧启动 JS 引擎,加载内置 prelude(JSX runtime + 事件 handler 注册)
  • 执行脚本后调用 RenderJSON() 取得 VDOM JSON
  • Go 将 JSON 解析为 internal/vdom.Node,用 Gio 渲染
  • 交互事件(按钮点击、输入变化)在渲染阶段被捕获,回传到 JS:__callHandler(handlerID, event)
  • JS 更新状态后,再次 RenderJSON(),实现重渲染

限制与注意事项

  • quickjs+cgo 构建下仅适合运行 ES5 .js.jsx/.tsx 会提示使用 -tags quickjs
  • 当前内置组件较少(View/Text/Button/Input/Modal),暂无滚动、列表虚拟化、复杂布局等
  • 没有 Node.js 标准库(如 fs 等);JSX 只是“描述 UI 的脚本”,不是浏览器环境
关于
182.0 KB
邀请码