两种锚定方式的视觉规则

范围锚定(选文本)vs 点锚定(插入占位符)— 默认/选中状态对比

视觉规则总览

// 两种锚定方式
type AnchorType = "range" | "point";

// 范围锚定(选一段文本关联节点)
// 文本背景色 = 节点颜色
.range-anchor {
  background-color: var(--node-color); // 节点颜色
  opacity: 0; // 默认完全透明(和正常文本一样)
}
.range-anchor.active {
  opacity: 0.3; // 选中节点时显示背景色
}

// 点锚定(在文本中插入占位符)
.point-anchor {
  opacity: 0.3; // 默认半透明
}
.point-anchor.active {
  opacity: 1; // 选中节点时不透明
}

完整画布 — 默认状态

默认状态(未选中任何节点)
📜 课文正文 🔒 固定
秋天

天气凉了,树叶黄了,

天空那么蓝,那么高。

一群大雁往南飞,

一会儿排成个"人"字

啊!秋天来了!

1 💡 导入 范围
提问:你见过秋天的树叶吗?
2 📝 文本研习
赏析:叠词的运用
3 📚 新授 范围
讲解:大雁南飞
4 ✏️ 练习
3 道题
5 📌 小结
总结全文
🔵 范围锚定:默认 opacity:0
🔴 点锚定:默认 opacity:0.3

选中"导入"节点(范围锚定)— 文本背景显示

选中节点 1 — "天气凉了"背景色显示
秋天

天气凉了,树叶黄了,

天空那么蓝,那么高。

一群大雁往南飞,

一会儿排成个"人"字

啊!秋天来了!

1 💡 导入 范围·选中
提问:你见过秋天的树叶吗?
2 📝 文本研习
3 📚 新授
✅ 选中"导入"节点 → "天气凉了"背景显示

选中"文本研习"节点(点锚定)— 占位符不透明

选中节点 2 — 占位符 ② 100% 显示
秋天

天气凉了,树叶黄了,

天空那么蓝,那么高。

一群大雁往南飞,

一会儿排成个"人"字

啊!秋天来了!

1 💡 导入
2 📝 文本研习 点·选中
赏析:叠词的运用
3 📚 新授
✅ 选中"文本研习"节点 → 占位符 ② 不透明显示

两种锚定方式对比

特性 范围锚定(选文本) 点锚定(插入占位符)
触发方式 选中一段文字 → 关联节点 点击文本某位置 → 插入占位符
视觉表现 文本背景色 = 节点颜色 插入标记符号(①②③)
默认透明度 opacity: 0 (完全透明,和正常文本一样) opacity: 0.3 (半透明,隐约可见)
选中时透明度 opacity: 0.3 (背景色显示) opacity: 1 (不透明,完整显示)
连线透明度 默认 opacity: 0.1 · 选中时 opacity: 1
适用场景 节点与具体文字内容相关(如赏析某词、讲解某句) 节点对应文本某个位置(如在此处开始导入、在此处小结)

数据模型

// 锚点 — 统一接口,区分 type
interface NodeAnchor {
  id: string;
  nodeId: string; // 关联的节点
  type: "range" | "point"; // 两种锚定方式
  start: number; // 正文纯文本偏移量
  end?: number; // range 锚定的结束偏移(point 无)
  textPreview?: string; // range 锚定的文字预览
}

// 渲染规则
function getAnchorStyle(anchor: NodeAnchor, isActive: boolean) {
  if (anchor.type === "range") {
    return { backgroundColor: getNodeColor(anchor.nodeId), opacity: isActive ? 0.3 : 0 };
  } else { // point
    return { opacity: isActive ? 1 : 0.3 };
  }
}