# 应用入口与页面

入口文件必须默认导出一个函数。名称可以自定，文档统一使用 `render`。

```js
export default async function render(root, platform) {
  root.replaceChildren(platform.ui.loading());
  try {
    const user = await platform.user();
    root.replaceChildren(platform.ui.card([
      platform.ui.title("你好，" + user.name),
    ]));
  } catch (error) {
    root.replaceChildren(platform.ui.hint(error.message));
  }
}
```

| 参数 | 类型 | 说明 |
| --- | --- | --- |
| `root` | HTMLElement | 宿主提供的应用根节点 `#root`，界面渲染到这里。 |
| `platform` | object | 数据、UI 组件与宿主能力。 |
| 返回值 | void 或 Promise | 异步入口完成后宿主显示应用就绪。 |

不要默认导出 JSX、配置对象或页面对象。当前加载器只接受函数形式，没有自动识别 `pages`、`start` 或 `ctx.go` 的页面路由功能。

## 页面与逻辑分离

页面函数接收 `root`、`platform` 和必要参数。入口负责创建导航函数，再传入页面。数据访问可以放入 `lib/`，页面模块放入 `pages/`。

```js file="index.js"
import { showHome } from "./pages/home.js";
import { showDetail } from "./pages/detail.js";

export default async function render(root, platform) {
  const navigation = {
    home: () => showHome(root, platform, navigation),
    detail: (id) => showDetail(root, platform, navigation, id),
  };
  await navigation.home();
}
```

这个示例说明页面的组织方式，两个页面模块需要由应用提供。[多文件待办](/doc/examples/multi-file)给出了完整可运行文件包。

## 异步事件与错误

事件监听器不会自动处理 Promise 的失败。在回调内部使用 `try/catch`，向用户显示错误；写入期间禁用提交按钮，避免重复提交。

切换自己的页面时，应移除旧页面创建的全局监听器与定时器。宿主不会为应用的自定义路由执行清理函数。
