---
order: 3
navTitle: HTML/FTL 页面
---
# HTML 和 FTL 自定义页面

在 SuccApp 中，开发者可以使用 `.html` 或 `.ftl` 编写自定义页面，再按需引入 `.css`、`.ts` / `.js` 前端脚本和系统模块。`.html` 适合静态页面或轻量展示内容，`.ftl` 适合需要服务端渲染、动态数据、权限判断或输出 JSON/XML/TXT 等内容的页面。

本文作为 HTML/FTL 自定义页面开发入口，说明两类文件的选择方式、常见资源引入方法，以及如何跳转到对应文件类型参考。

## 选择 HTML 还是 FTL{#choose-file-type}

| 文件类型 | 适合场景 | 参考 |
| --- | --- | --- |
| `.html` | 页面内容基本静态，只需要浏览器端脚本和样式完成展示或交互。 | [.html HTML 文件](../../meta/file-types/views/html.md) |
| `.ftl` | 需要服务端渲染 HTML、读取请求参数、配合 `.action.ts` 查询数据，或输出 JSON、XML、TXT 等内容。 | [.ftl 服务端模板文件](../../meta/file-types/views/ftl.md) |

如果页面主要通过可视化设计器搭建，优先考虑 `.spg`、`.tpg`、`.dash` 或 `.rpt` 等页面类文件；只有需要维护自定义 HTML 结构、服务端模板或轻量静态页面时，再使用 `.html` 或 `.ftl`。

## 推荐文件组织{#file-organization}

自定义页面相关文件通常放在同一目录下，便于页面、样式和脚本一起维护：

```text
demo.app/
├── index.html
├── index.ftl
├── index.css
├── index.ts
└── index.js
```

日常开发优先维护 `.ts` 源码，由系统编译为 `.js` 后在浏览器端加载。只有没有同名 `.ts`，或确实需要维护兼容脚本时，才直接修改 `.js`。

## 引入 CSS{#import-css}

在 `.html` 页面中，可以使用标准 `<link>` 标签引入同目录样式：

```html
<link rel="stylesheet" href="./index.css">
```

在 `.ftl` 输出的 HTML 页面中，推荐把样式写在 `<@head>` 中，让系统合并注入页面头部：

```ftl
<@html>
<@head>
    <title>自定义页面</title>
    <link rel="stylesheet" href="./index.css">
</@head>
<@body>
    <div class="page">页面内容</div>
</@body>
</@html>
```

如果样式文件放在公共目录或跨目录引用，使用稳定路径，避免页面 URL 省略文件名后相对路径解析错误。

## 引入页面同目录脚本{#import-file}

页面脚本建议使用 `.ts` 编写，再通过编译后的 `.js` 在浏览器端运行。页面内可以通过 `sys.ready()` 加载同目录脚本：

```html
<script type="text/javascript">
    require(["sys/sys"], function(sys) {
        sys.ready("./index").then(function(page) {
            page.init();
        });
    });
</script>
```

如果页面是目录索引页，例如用户通过 `http://localhost:8080/demo` 访问 `index.html`，当前 URL 中不包含 `index.html` 文件名。此时可以基于 `location.pathname` 拼接脚本地址：

```html
<script type="text/javascript">
    var pathname = location.pathname;

    require(["sys/sys"], function(sys) {
        sys.ready(pathname + "/index.js").then(function(page) {
            page.init();
        });
    });
</script>
```

`sys.ready("./index")` 适合页面 URL 和文件名一致的场景；索引页、省略扩展名或通过路由访问时，先确认浏览器地址栏中的最终 URL，再决定是否需要使用绝对路径或 `location.pathname`。

## 在 FTL 页面中引入脚本{#import-in-ftl}

如果页面由 `.ftl` 输出 HTML，推荐使用 `<@html>`、`<@head>`、`<@body>` 指令组织页面。`<@head>` 和 `<@body>` 会合并注入 HTML 页面运行所需的系统资源，页面内脚本可以继续使用 `require(["sys/sys"], ...)` 和 `sys.ready()`。

```ftl
<@html>
<@head>
    <title>自定义页面</title>
    <link rel="stylesheet" href="./index.css">
</@head>
<@body>
    <div id="app">页面内容</div>

    <script type="text/javascript">
        require(["sys/sys"], function(sys) {
            sys.ready("./index").then(function(page) {
                page.init();
            });
        });
    </script>
</@body>
</@html>
```

如果 `.ftl` 不是 HTML 模板，例如 `data.json.ftl`、`export.txt.ftl`，页面不会注入 HTML 运行资源，也不适合在模板中编写浏览器端脚本。需要输出 HTML 并执行前端交互时，使用 `page.ftl`、`page.html.ftl` 或 `page.htm.ftl` 这类 HTML 模板。

## 加载系统模块{#import-sys-module}

`.html` 或 HTML 型 `.ftl` 页面发送给浏览器时，系统会注入通用 CSS 和 JS。页面脚本可以通过 `sys.ready()` 同时加载页面同目录脚本和系统模块：

```html
<script type="text/javascript">
    var pathname = location.pathname;

    require(["sys/sys"], function(sys) {
        sys.ready([pathname + "/index.js", "common/tree"]).then(function(modules) {
            modules[0].init();
            new modules[1].Tree(...);
        });
    });
</script>
```

如果页面不需要 SuccApp 前端运行环境，只是普通静态页面，也可以使用浏览器原生的 `<script src="./index.js"></script>` 引入脚本。但只要需要调用系统模块、组件或前端 API，就应使用系统注入的脚本环境和 `sys.ready()`。

## 更多说明{#more}

- `.ts` 是推荐维护的前端脚本源码，`.js` 通常是 `.ts` 的编译结果。没有同名 `.ts` 时，才建议直接维护 `.js`。
- `.html` 和 HTML 型 `.ftl` 页面可以通过 `<link>` 引入 CSS，通过 `sys.ready()` 加载页面脚本或系统模块。
- `.ftl` 中的 `<@useScript>` 用于引入服务端 `.action.ts` 并在模板渲染阶段调用导出函数，不等同于浏览器端 `sys.ready()`。
- 需要了解 `.html` 文件的定位和编辑注意事项，参考 [.html HTML 文件](../../meta/file-types/views/html.md)。
- 需要了解 `.ftl` 的路由、模板语法、内置指令和输出类型，参考 [.ftl 服务端模板文件](../../meta/file-types/views/ftl.md)。
