> **本文回答**：大量实体只改样式（`color` / `lineWidth` / `effect_*`）时用 `styleChanged` 快路径，避免几何重算；`visible` / fill / lineType 不在快路径。

## 一、为什么要分快慢两路径

实体每次 dirty 会触发：

| 信号 | 空间索引重建 | 顶点缓冲重构 | 样式缓冲刷新 |
|---|---|---|---|
| `changed()` | ✅ | ✅ | ✅ |
| `styleChanged()` | ❌ | ❌ | ✅ |

只改颜色 / 线宽等样式 → 用 `styleChanged()` 省掉前两步，差几倍性能。

## 二、基础用法

```js
mapcadLayer.getEntities()
  .filter(e => e.layerId === '标注')
  .forEach(e => {
    e.color = 0xff0000;
    e.styleChanged();           // ← 不是 changed
  });
```

无需手动包批处理：`styleChanged` 只标脏，重绘由 `requestAnimationFrame` 自动合并到下一帧。

## 三、只修改样式的属性白名单

`styleChanged()` 快路径走 `renderCache.updateStyleProps` → 实体 `updateFeatureStyleProps(feature)`，**只回写以下 feature props**：

- `color`（→ `t.color`）
- `lineWidth`（→ `t.line_width`，跳过 TEXT_FILL/TEXT_STROKE 角色）——⚠️ 只在 `lineWidth > 0` 时写入、从不删除：把线宽**改回 0** 时缓存里的旧 `line_width` 留着，须用 `changed()`
- `effectColor` / `effectWidth` / `effectOpacity` / `effectBlur`（→ `t.effect_*`；`effectColor===-1` 时删除这些 props）

**以下属性 `styleChanged()` 不会生效，必须用 `changed()`：**

- `fillColor` / `fillOpacity` / `borderOpacity` / `opacity` —— fill/透明度 props 不在回写清单，改了画面不变
- `visible` —— 可见性只在全量重建时过滤（`!d.visible → continue`），styleChanged 后实体仍在渲染桶里
- `layerId` —— 图层隐藏检查 `hiddenLayerChecker` 只在全量路径执行
- `lineType` / `ltScale` / `ltOffset` —— 线型改变 tessellation 几何（虚线展开），必须重建
- 任何几何（point / center / radius / angle / text ...）、`rotation`（影响包围盒）
- `setCustomProperty` —— 不影响渲染（也不用 dirty，业务属性随便改）

## 四、大量实体瞬切主题

```js
function applyTheme(theme) {
  mapcadLayer.getEntities().forEach(e => {
    e.color = theme[e.layerId] || theme.default;
    e.styleChanged();
  });
}

applyTheme({ wall: 0x888888, door: 0xff4444, window: 0x44ff44, default: 0xcccccc });
```

## 五、按条件批量染色

```js
mapcadLayer.getEntities().forEach(e => {
  const temp = e.getCustomProperty('temp')?.value ?? 0;   // 返回 {type,value} 包装，取 .value
  if (temp > 100)      e.color = 0xff0000;
  else if (temp > 60)  e.color = 0xffaa00;
  else if (temp > 30)  e.color = 0x00aaff;
  else                 e.color = 0x00ff00;
  e.styleChanged();
});
```

## 六、事务包装 Undo

改属性/`styleChanged()` **不会自动记 undo**（只有 `store.add`/`store.delete` 自动入栈），空事务也不入栈——光把 `applyTheme` 包进事务，Ctrl+Z 什么都不撤。要可撤销，改之前逐个 `recordModify` 快照：

```js
const um = mapcadLayer.undoManager;
um.beginTransaction();
mapcadLayer.getEntities().forEach(e => {
  um.recordModify(e);                                // 改之前快照
  e.color = darkTheme[e.layerId] || darkTheme.default;
  e.styleChanged();
});
um.endTransaction();
```

这样一次 `Ctrl+Z` 撤销整批样式修改（撤销是按快照删旧实体再加回，见 [drawing/undo-redo](../drawing/undo-redo.md)）。

## 七、批量显隐

`visible` **不在** styleChanged 快路径（见 §3），要用 `changed()`：

```js
mapcadLayer.getEntities()
  .filter(e => e.layerId === '辅助')
  .forEach(e => { e.visible = false; e.changed(); });
```

## 八、特例：批量 deleteEntity

删除要重建空间索引，没快路径；直接循环 `deleteEntity` 即可（重绘按帧合并），需要一步撤销就包 `beginTransaction`/`endTransaction`。

## 九、常见坑

1. **用 `changed()` 改样式** → 慢数倍，几何并没变。
2. **改完几何又改颜色**：`changed()` 已含样式刷新，一次即可——**千万别在 `changed()` 之后同帧再 `styleChanged()`**：后者把 id 重新标成 style-only，本帧只 patch 缓存 feature 的样式，几何更新被吞（且 `isDirty` 被清，之后也不会补）。顺序反过来（先 `styleChanged` 后 `changed`）则无害。
3. **styleChanged 后 bounding box 不变**：正确；只有 `changed` 才会刷新空间索引。
4. **visible/fill 不属于样式快路径**：`visible`、`fillColor`、`fillOpacity` 等改了要用 `changed()`；`styleChanged()` 只会更新缓存 feature 的 color/line_width/effect_*，其余属性画面不变。
5. **实体图层字段是 `layerId`**：不是 `layer`。

## 相关

- 实体公共样式 → [entity/style-props](../entity/style-props.md)
- 渲染分桶 → [perf/render-buckets](../perf/render-buckets.md)
- 仅样式快路径 → [perf/style-only-fast-path](../perf/style-only-fast-path.md)
