快速上手

安装、受控组件用法、跨端注意与包 source 字段约定。

安装

bash
bun add transone-ui

受控组件用法

组件全部为受控组件:状态由父级维护,交互通过 click / change / input / close 等自定义事件回传,父级用 emitters 订阅:

ts
import { Component, createComponent, h } from 'transone';
import { TuButton, TuInput, TuPopup } from 'transone-ui';

class MyPage extends Component {
  protected initState() {
    return { text: '', popupVisible: false };
  }

  protected render() {
    return h('div', { className: 'page' }, [
      createComponent({
        component: TuInput,
        props: { value: this.state.text, clearable: true },
        emitters: { input: (v: string) => (this.state.text = v) },
      }),
      createComponent({
        component: TuButton,
        props: { type: 'primary' },
        children: ['打开弹层'],
        emitters: { click: () => (this.state.popupVisible = true) },
      }),
      createComponent({
        component: TuPopup,
        props: { visible: this.state.popupVisible, position: 'bottom' },
        children: [h('div', {}, ['弹层内容'])],
        emitters: { close: () => (this.state.popupVisible = false) },
      }),
    ]);
  }
}

全部组件与属性 / 事件见组件列表下的 17 个组件页。

跨端注意

  • 插槽内的动态文本:小程序端插槽内容编译在父级 wxml、绑定父级数据;Web 端插槽内容绑定的是组件自身 state(为空时 {{}} 渲染为空)。不要在组件 children 插槽里写 模板插值,改用模板表达式字符串,例如 `计数:${this.state.count}`,或将动态文本放在页面直属节点。
  • each() 返回数组:作为 children 直接传入([object Object]),不要再包一层数组字面量(Web 渲染器只铺一层 children)。
  • 子节点类型:children 只接受 VNode | string;数字先转字符串(模板表达式自动转换)。
  • 标签映射:div → view、span → text;小程序端 text 内不能放 view / slot,所以 TuTag 根节点使用 div。
  • 事件回传:组件用 emit(name, ...args) 回传,父级用 createComponent({ ..., emitters }) 订阅;小程序端编译为页面包装方法并绑定 bind:name,同名事件自动加序号避免覆盖。
  • 组件内部:渲染(非插槽部分)不要使用 {{}},一律通过 props 传入数据。

小程序端样式与交互适配

  • 间距不使用 flex gap(老内核 WebView 支持不稳定),组件内一律用子元素 margin 实现。
  • 样式避免高级选择器(如 :not());条件样式用类名(--checked / --visible)或 directions.show 切换。
  • 安全区使用双声明:先写固定值兜底,再写 calc(env(safe-area-inset-bottom) + Npx) 覆盖。
  • 列表取数:渲染 dataIndex 属性(mp 编译为 data-index=""),回调从 e.currentTarget.dataset.index 读取,双端一致。
  • TuSearchBar 提供 confirmType(小程序键盘确认键文案),Web 端忽略;回车触发 search 事件。
  • 行内 style 的 var() 若在端上不解析,同属性在 wxss 类中有默认值兜底;主题定制优先在 app.wxss 覆盖令牌。
  • 弹层(Toast / Modal / ActionSheet / Popup)用 position: fixed 渲染于组件内部,层级统一为 --tu-popup-z-index(默认 1000)。

包 source 字段约定(CLI 编译依赖)

transone-cli 编译小程序时,从 node_modules/<包>/package.json 读取 "source" 字段定位该包的 TypeScript 入口,再沿 export / re-export 链解析组件类的实际文件。因此发布组件库时必须声明:

json
{
  "name": "transone-ui",
  "source": "./lib/index.ts",
  "peerDependencies": { "transone": ">=0.1.2" }
}
注意
只有 source 指向的入口及其 re-export 链中的类会被静态编译分析;组件的 render() / initState() / initStyles() 需保持静态可分析(字面量、三元、&&、each 等受支持语法),方法体独立翻译、不能闭包捕获。

开发

bash
# 构建 dist(类型声明 + Bun.build)
bun run --cwd packages/transone-ui build

# 组件运行时测试(Web DOM 环境)
bun test packages/transone-ui/tests/components.test.ts

# 演示页整页集成测试(覆盖受控数据流)
bun test packages/transone-ui/tests/demo-integration.test.ts

演示项目位于 playground/ui-demo,覆盖全部组件与受控交互,可分别构建 Web / 微信 / 阿里 / 字节产物。