---
date: "2023-05-25T16:00:00+02:00"
slug: "guidelines-frontend"
sidebar_position: 20
aliases:
  - /zh-tw/guidelines-frontend
---

# 前端开发指南

## 背景

Gitea 在其前端中使用[Fomantic-UI](https://fomantic-ui.com/introduction/getting-started.html)（基于[jQuery](https://api.jquery.com)）和 [Vue3](https://vuejs.org/)。

HTML 页面由[Go HTML Template](https://pkg.go.dev/html/template)渲染。

源文件可以在以下目錄中找到：

- **CSS 样式**： `web_src/css/`
- **JavaScript 文件**： `web_src/js/`
- **Vue 组件**： `web_src/js/components/`
- **Go HTML 模板**： `templates/`

## 通用准则

我们推荐使用[Google HTML/CSS Style Guide](https://google.github.io/styleguide/htmlcssguide.html)和[Google JavaScript Style Guide](https://google.github.io/styleguide/jsguide.html)。

## Gitea 特定准则

1. 每个功能（Fomantic-UI/jQuery 模組）應放在單独的文件/目錄中。
2. HTML 的 id 和 class 應使用 kebab-case，最好包含 2-3 个与功能相关的关键詞。
3. 在 JavaScript 中使用的 HTML 的 id 和 class 應在整个项目中是唯一的，並且應包含 2-3 个与功能相关的关键詞。建议在僅在 JavaScript 中使用的 class 中使用 `js-` 前缀。
4. 不應覆盖框架提供的 class 的 CSS 样式。始终使用具有 2-3 个与功能相关的关键詞的新 class 名稱来覆盖框架样式。Gitea 中的帮助 CSS 类在 `helpers.less` 中。
5. 后端可以通過使用`ctx.PageData["myModuleData"] = map[]{}`将复杂数据传递给前端，但不要将整个模型暴露给前端，以避免泄露敏感数据。
6. 简單页面和与 SEO 相关的页面使用 Go HTML 模板渲染生成静态的 Fomantic-UI HTML 输出。复杂页面可以使用 Vue3。
7. 明确变量類型，优先使用`elem.disabled = true`而不是`elem.setAttribute('disabled', 'anything')`，优先使用`$el.prop('checked', var === 'yes')`而不是`$el.prop('checked', var)`。
8. 使用语义化元素，优先使用`<button class="ui button">`而不是`<div class="ui button">`。
9. 避免在 CSS 中使用不必要的`!important`，如果無法避免，添加注释解释為什么需要它。
10. 避免在一个事件监听器中混合不同的事件，优先為每个事件使用独立的事件监听器。
11. 推荐使用自定义事件名稱前缀`ce-`。
12. 建议使用 Tailwind CSS，它可以通過 `tw-` 前缀获得，例如 `tw-relative`. Gitea 自身的助手类 CSS 使用 `gt-` 前缀（`gt-ellipsis`），Gitea 自身的私有框架级 CSS 类使用 `g-` 前缀（`g-modal-confirm`）。
13. 尽量避免内联脚本和样式，建议将 JS 代码放入 JS 文件中並使用 CSS 类。如果内联脚本和样式不可避免，請解释無法避免的原因。

### 可访问性 / ARIA

在历史上，Gitea 大量使用了可访问性不友好的框架 Fomantic UI。
Gitea 使用一些补丁使 Fomantic UI 更具可访问性（参见 `aria.md`），
但仍然存在许多问题需要大量的工作和时间来修复。

### 框架使用

不建议混合使用不同的框架，这会使代码难以维护。
一个 JavaScript 模組應遵循一个主要框架，並遵循該框架的最佳实践。

推荐的实現方式：

- Vue + Vanilla JS
- Fomantic-UI（jQuery）
- htmx （部分页面重新加载其他静态组件）
- Vanilla JS

不推荐的实現方式：

- Vue + Fomantic-UI（jQuery）
- jQuery + Vanilla JS
- htmx + 任何其他需要大量 JavaScript 代码或不必要的功能，如 htmx 脚本 (`hx-on`)

為了保持界面一致，Vue 组件可以使用 Fomantic-UI 的 CSS 类。
尽管不建议混合使用不同的框架，
我们使用 htmx 進行简單的交互。您可以在此 [PR](https://github.com/go-gitea/gitea/pull/28908) 中查看一个简單交互的示例，其中應使用 htmx。如果您需要更高级的反應性，請不要使用 htmx，請使用其他框架（Vue/Vanilla JS）。
但如果混合使用是必要的，並且代码设计良好且易于维护，也可以工作。

### `async` 函数

只有当函数内部存在`await`调用或返回`Promise`时，才将函数标记為`async`。

不建议使用`async`事件监听器，这可能会导致问题。
原因是`await`后的代码在事件分发之外執行。
参考：https://github.com/github/eslint-plugin-github/blob/main/docs/rules/async-preventdefault.md

如果一个事件监听器必須是`async`，應在任何`await`之前使用`e.preventDefault()`，
建议将其放在函数的開頭。

如果我们想在非异步上下文中调用`async`函数，
建议使用`const _promise = asyncFoo()`来告诉读者
这是有意為之的，我们想调用异步函数並忽略 Promise。
一些 lint 規則和 IDE 也会在未处理返回的 Promise 时发出警告。

### 获取数据

要获取数据，請使用`modules/fetch.js`中的包装函数`GET`、`POST`等。他们
接受内容的`data`選项，将自动设置 CSRF 令牌並返回
[Response](https://developer.mozilla.org/en-US/docs/Web/API/Response)。

### HTML 属性和 dataset

禁止使用`dataset`，它的驼峰命名行為使得搜索属性变得困难。
然而，仍然存在一些特殊情况，因此当前的准则是：

- 對於旧代码：

  - 應将`$.data()`重构為`$.attr()`。
  - 在极少数情况下，可以使用`$.data()`将一些非字符串数据绑定到元素上，但强烈不推荐使用。

- 對於新代码：
  - 不應使用`node.dataset`，而應使用`node.getAttribute`。
  - 不要将任何使用者数据绑定到 DOM 节点上，使用合适的设计模式描述节点和数据之间的关系。

### 显示/隐藏元素

- 推荐在 Vue 组件中使用`v-if`和`v-show`来显示/隐藏元素。
- Go 模板代码應使用 `.tw-hidden` 和 `showElem()/hideElem()/toggleElem()` 来显示/隐藏元素，請参阅`.tw-hidden`的注释以获取更多详细信息。

### Go HTML 模板中的样式和属性

建议使用以下方式：

```html
<div
  class="gt-name1 gt-name2 {{if .IsFoo}}gt-foo{{end}}"
  {{if
  .IsFoo}}data-foo{{end}}
></div>
```

而不是：

```html
<div
  class="gt-name1 gt-name2{{if .IsFoo}} gt-foo{{end}}"
  {{if
  .IsFoo}}
  data-foo{{end}}
></div>
```

以使代码更易读。

### 旧代码

许多旧代码已经存在于本文撰写之前。建议重构旧代码以遵循指南。

### Vue3 和 JSX

Gitea 現在正在使用 Vue3。我们决定不引入 JSX，以保持 HTML 代码和 JavaScript 代码分离。

### UI 示例

Gitea 使用一些自制的 UI 元素並自定义其他元素，以将它们更好地集成到通用 UI 方法中。当在开发模式（`RUN_MODE=dev`）下运行 Gitea 时，在 `http(s)://your-gitea-url:port/devtest` 下会提供一个包含一些标准化 UI 示例的页面。
