# 一切都是 Component

> CrossFly 的统一理念 —— 只存在 Component，而 container = Component + Layout。

Source: https://crossfly.dev/zh/docs/concepts/everything-is-a-component — CrossFly documentation. Full docs as one file: https://crossfly.dev/llms-full.txt

# 一切都是 Component

这是让框架其余部分"豁然开朗"的核心理念。在 CrossFly 中，**不存在"widget"与"container"
两套层级**。只有**一个**基类型 —— `Component` —— 而任何 `Component` 一旦获得一个 `Layout`，
就在那一刻变成了容器。

## `container = Component + Layout`
```java
Component painel = new Component();       // 一个「空」的 Component
painel.setLayout(new VerticalLayout());   // 现在它组织子项 → 是一个容器
painel.add(LAY_AUTO, new Label("Título"));
painel.add(LAY_FILL, new ListView<>(...));
```
`Button` 是一个 `Component`。`Label` 是一个 `Component`。`Window`（屏幕）是一个全屏的
`Component`。**不存在特殊的 `Container` 类** —— "容纳能力"就只是拥有一个 `Layout`。
这意味着你始终用同样的方式组合界面，从一个按钮到整个应用皆是如此。

## 为什么基类要这样设计
`Component` 必须能扩展到**成千上万个实例**而不撑爆内存。两个关键决策：

- **用位域（`cbits`）代替几十个 `boolean`。** 诸如 *enabled*、*visible*、*focused*、
  *pressed*、*是否有布局*、*是否有聚焦样式*…… 这些状态是同一个 long 整数中的若干位，而非独立字段。
  成千上万个组件 × 几十个布尔标志将造成巨大浪费；一个位域用单个字段就解决了问题。
- **_惰性_属性映射（`property(k, v)`）。** 可选的东西（回调、自定义皮肤、背景
  图、备用样式）不是固定字段 —— 它们存在于一个**按需**创建的映射中。一个简单的
  `Label` 不必为一个永远不会用到的"背景图"字段付出代价。

```java
// property(...) 是表示可选值的惯用「数据袋」：
comp.property("meuFlag", true);
boolean f = comp.property("meuFlag");   // 取回（从未设置则为 null）
```
**样式**遵循同样的理念：它们是按需从 `Skin` 创建的，而非在一开始就为每个组件
实例化。

## 单一父级层级
每个 `Component` **最多有一个父级**。组合树是严格分层的：将
一个组件添加到某个容器会把它从任何先前的父级中移除。这让布局和事件
传播保持可预测（每个组件恰好属于一个位置）。

## 由此推导出的结论
- **组合一切的方式只有一种：** 学会搭建一个面板 = 学会搭建一个屏幕。
- **布局是可插拔的：** 同一个容器只需更换 `Layout` 就能改变排布方式（这是
  响应式的基础 —— 参见 [Layout 与 Relative 模型](/docs/concepts/the-layout-and-relative-model)）。
- **每个组件成本低：** 位域 + 惰性属性正是让大型列表可行的原因。

## 参见
- 应用：[布局](/docs/ui/layouts) · [组件目录](/docs/ui/widgets)
- 下一篇：[渲染管线](/docs/concepts/rendering-pipeline)
