文本结构和样式

在幻灯片 API 中,文本可以包含在形状或表格单元格中。在对文本进行操纵和设置样式之前,您需要了解文本的结构和样式设置的工作原理。

本页介绍了文本在幻灯片 API 中的表示方式。

文本元素序列

形状或表格单元格中包含的文本由一系列 TextElement 结构组成。此序列按照文本从头到尾出现的顺序表示文本的结构。

以这张幻灯片的内容为例,所有内容都包含在一个文本框中:

一张简单幻灯片的屏幕截图

上面这张幻灯片包含一个文本框,其 text 字段包含一系列文本元素,如下图所示:

显示文本元素序列的示意图

具体而言,此文本序列在幻灯片 API 中的表示如下:

"textElements": [ {
    "endIndex": 224,
    "paragraphMarker": { "style": {} }
  }, {
    "endIndex": 130,
    "textRun": { "content": "Li lingues differe in li grammatica e li vocabules. Omnicos directe al desirabilite de un nov ", "style": {} }
  }, {
    "endIndex": 143,
    "startIndex": 130,
    "textRun": { "content": "lingua franca", "style": { "italic": True } }
  }, {
    "endIndex": 224,
    "startIndex": 143,
    "textRun": { "content": ": solmen va esser necessi far:\n", "style": {} }
  }, {
    "endIndex": 243,
    "startIndex": 224,
    "paragraphMarker": {
      "style": { "indentStart": { "magnitude": 36, "unit": "PT" }, "direction": "LEFT_TO_RIGHT", "indentFirstLine": { "magnitude": 18, "unit": "PT" }, "spacingMode": "COLLAPSE_LISTS" },
      "bullet": { "listId": "foo123", "glyph": "\u25cf" }
    }
  }, {
    "endIndex": 243,
    "startIndex": 224,
    "textRun": { "content": "uniform grammatica\n", "style": {} }
  }, {
    "endIndex": 257,
    "startIndex": 243,
    "paragraphMarker": {
        "style": { "indentStart": { "magnitude": 36, "unit": "PT" }, "direction": "LEFT_TO_RIGHT", "indentFirstLine": { "magnitude": 18, "unit": "PT" }, "spacingMode": "COLLAPSE_LISTS" },
        "bullet": { "listId": "foo123", "glyph": "\u25cf" }
    }
}, {
    "endIndex": 257,
    "startIndex": 243,
    "textRun": { "content": "Pronunciation\n", "style": {} }
}, {
    "endIndex": 277,
    "startIndex": 257,
    "paragraphMarker": {
        "style": { "indentStart": { "magnitude": 36, "unit": "PT" }, "indentFirstLine": { "magnitude": 18, "unit": "PT" }, "spacingMode": "COLLAPSE_LISTS" },
        "bullet": { "listId": "foo123", "glyph": "\u25cf" }
    }
}, {
    "endIndex": 277,
    "startIndex": 257,
    "textRun": { "content": "plu sommun paroles.\n", "style": {} }
}, {
    "endIndex": 500,
    "startIndex": 277,
    "paragraphMarker": { "style": {} }
}, {
    "endIndex": 500,
    "startIndex": 277,
    "textRun": { "content": "Ka swu thefognay, tay waddeant varpa u inzo.\n", "style": {} }
}]

TextElement 内容

每个文本元素都包含从零开始的开始索引和结束索引(用于描述元素在页面元素完整文本中的位置)以及以下类型的文本对象:

文本种类 说明
ParagraphMarker 此文本元素表示新段落的开头。文本元素的起始索引和结束索引表示整个段落,包括结束段落的换行符。一个段落绝不会与其他段落重叠。段落始终以换行符结束,因此形状或表格单元格的文本内容的末尾始终会有一个换行符。

段落可以属于项目符号列表或编号列表。如果是这样,ParagraphMarker.bullet 字段内容将包含列表 ID。此 ID 引用存在于 TextContent 以及 TextElement 序列内的列表元素。同一逻辑列表内的段落将引用相同的列表 ID。
TextRun 此文本元素表示所有具有相同文本样式的连续文本字符串。文本运行从不跨越段落边界:即使一个段落结尾的文本与下一个段落开始的文本具有相同的样式,内容也会在换行符之后分隔,以形成单独的文本段。

如果您需要处理页面元素内的完整文本字符串,请遍历所有文本元素,将在所有文本段中找到的字符串串联起来。
AutoText 自动文本是指文本中会根据上下文动态变化的位置。在幻灯片中,它用于表示文本中当前的幻灯片编号。

修改文本内容

如果需要使用 Slides API 修改文本,则不必显式创建所有适当的文本元素。您可以像在幻灯片编辑器中那样操作文本:插入文本、删除范围以及更新范围的样式。这些操作会根据需要隐式创建 ParagraphMarkerTextRun 元素以反映您的更改。

插入文本

您可以在对 batchUpdate 的调用中使用 InsertTextRequest 请求在索引处插入文本。此方法的 insertionIndex 字段指定插入文本的位置;您可以使用文本元素内的开始索引字段和结束索引字段计算此索引。

文本插入功能会产生一些反映幻灯片编辑器行为的副作用:

  • 插入换行符会隐式创建一个新的段落,从而创建一个从换行符的索引开始并以下一个换行符结束的 ParagraphMarker 文本元素。段落样式(包括项目符号和列表详细信息)会从当前段落复制到新段落。
  • 所插入字符的样式会自动确定,通常与插入索引处已有的文本样式保持一致。因此,文本通常会插入到该索引处的现有 TextRun 中。您稍后可以使用 UpdateTextStyle 请求更新此样式。

正在删除文本

您可以在对 batchUpdate 的调用中使用 DeleteTextRequest 消息删除一系列文本。删除文本涉及一些细微差别:

  • 跨越段落边界的删除操作会将两个段落合并,同时删除分隔的 ParagraphMarker 文本元素。
  • 新的合并段落将使用合并段落样式,这与幻灯片编辑器中的行为一致。
  • 如果删除的范围涵盖文本运行,则会移除文本运行的所有内容,也会删除文本运行本身。
  • 如果删除的范围包含 AutoText 元素,则会删除 AutoText 元素。

正在更新文本样式

幻灯片中文本的呈现外观由文本样式属性决定:

  • 缩进、对齐方式和项目符号等段落样式由段落标记上的属性定义。
  • 粗体、斜体和下划线等字符样式由各个文本段的属性定义。

正在更新角色样式

您可以在对 batchUpdate 的调用中使用 UpdateTextStyleRequest 消息更新字符样式。

与其他文本操作一样,字符样式会应用于一系列文本,并根据需要隐式创建新的 TextRun 对象。

设置某些字符样式会隐式更新其他相关样式,以与幻灯片编辑器中的行为保持一致。例如,添加链接会自动更改文本前景颜色和下划线属性。如需了解详情,请参阅 TextStyle 参考文档。

正在更新段落样式

您可以在对 batchUpdate 的调用中使用 UpdateParagraphStyleRequest 消息更新段落样式。

Slides API 支持 CreateParagraphBulletsRequest,它镜像了幻灯片编辑器中用于创建项目符号列表和编号列表的项目符号预设功能。同样,DeleteParagraphBulletsRequest 也会移除段落上的任何现有项目符号。

继承的样式

某些形状(称为placeholders)可以从其他父形状继承文本样式:请参阅placeholders,了解有关形状继承的常规详情。

本部分将重点介绍样式沿用,即如何创建幻灯片中显示的最终渲染文本样式。

占位符中的样式表示法

有关placeholders的部分介绍了父形状和子形状之间继承的工作方式。文本样式的继承由继承模型中的其他功能处理:

  • ParagraphMaker 文本元素的属性定义了段落格式。
  • TextRun 文本元素的属性用于定义字符格式设置。
  • 父占位符的内容包含 8 个这样的 ParagraphMarker/TextRun 对(以支持 8 个级别的列表嵌套)。
  • 子占位符会从其父占位符文本内容中的这些文本元素继承其默认文本属性。

下图显示了直观展示这些关系的一种方式:

子形状继承文本属性的示意图

父形状中的第一个 ParagraphMarker/TextRun 决定大部分继承的文本样式设置;其余七对中的样式设置只会影响渐进式更深层的嵌套项目符号级别的段落:

父文本元素对 它控制的子项格式设置
ParagraphMarker
TextRun
0 级(最外层)列表段落和所有非列表段落的文本样式。
第二个ParagraphMarker
第二个TextRun
其余(嵌套)列表级别 1-7 的文本样式
第三个ParagraphMarker
第三个TextRun
第四个ParagraphMarker
第四个TextRun
第五个ParagraphMarker
第五个TextRun
第六个ParagraphMarker
第六个TextRun
第七个ParagraphMarker
第七个TextRun
第八个ParagraphMarker
第八个TextRun

如需访问这些文本元素对,请在 textElements 字段中使用它们的显式索引,如以下代码段所示,其中展示了如何为级别 0 和非列表段落设置默认(可继承)样式:

"text": {
  "textElements": [  {
     "startIndex": 0,
     "endIndex": 1,
     "paragraphMarker": {
       "style": {  "alignment": "START",  ...  },
       "bullet": {  "nestingLevel": 0,  ...  }
     }
   },{
     "startIndex": 0,
     "endIndex": 1,
     "textRun": {
       "content": "\n",
       "style": {  "foregroundColor": {  "opaqueColor": {  "themeColor": "DARK1"  }  },  }
     }
   },{
     ...
   } ]
 }

请注意,父形状的 TextRuncontent 字段始终由单个换行符组成。

可以覆盖继承的样式

子形状可以在其内容中指定 ParagraphMarkerTextRun 元素的样式属性。这些局部指定的属性将替换其局部范围内的任何继承属性。未指定任何样式的元素将使用从父样式继承的相应样式。

如果从子形状中移除显式样式属性,使其不再设置,会导致其从父形状继承。

示例

根据上图所示的继承关系,假设形状 ParentPlaceholder 具有以下文本内容:

"text": {
  "textElements": [
    { "startIndex": 0,  "endIndex": 1,
      "paragraphMarker": {
        "style": {"alignment": "START", ...},
        "bullet": {"nestingLevel": 0, ...}
      }
    },
    { "startIndex": 0,  "endIndex": 1,
      "textRun": {
        "content": "\n",
        "style": {"foregroundColor": {"opaqueColor": {"themeColor": "DARK1"} }, }
        ...
      }
    },
    { "startIndex": 1,  "endIndex": 2,
      "paragraphMarker": {
        "style": {"alignment": "END", ...},
        "bullet": {"nestingLevel": 1, ...}
      }
    },
    { "startIndex": 1,  "endIndex": 2,
      "textRun": {
        "content": "\n",
        "style": {"foregroundColor": {"opaqueColor": {"themeColor": "LIGHT1"} }, ...}
      }
    },
   ...
  ]
}

并且假设形状 ChildPlaceholder 具有以下文本内容:

"text": {
  "textElements": [
    { "startIndex": 0,  "endIndex": 1,
      "paragraphMarker": {
        "style": {},
      }
    },
    { "startIndex": 0,  "endIndex": 1,
      "textRun": {
        "content": "This is my first paragraph\n",
        "style": {},
      }
      ...
    },
    {  "startIndex": 1,  "endIndex": 2,
      "paragraphMarker": {
        "style": {},
        "bullet": {
          "nestingLevel": 1,
          "listId": "someListId",
          "glyph": "●"
        }
      }
    },
    { "startIndex": 1,  "endIndex": 2,
      "textRun": {
        "content": "This paragraph is in a list\n",
        "style": {},
        ...
      }
    }
  ]
}

会产生下文所述的结果。

普通段落的样式继承

子形状的第一个段落(包含文本“This is my first paragraph”)是一个普通段落(不在列表中)。 其文本内容中没有任何元素指定任何样式属性,因此它会继承其父项的所有字符和段落样式。这会导致以下渲染:

  • 文本:“This is my first paragraph”是呈现的文本。文本本身永远不会继承。
  • 对齐:文本使用 START 对齐渲染,该对齐方式继承自父项的第一个 ParagraphMarker
  • 前景颜色:文本使用 DARK1 前景颜色渲染,该前景颜色继承自父项的第一个 TextRun

列表段落的样式继承

包含文本“This paragraph is in a list”的下一个段落位于嵌套级别为 1 的项目符号列表中,因为其对应的 ParagraphMarkerbullet 字段设置为该级别。因此,它会继承父级中嵌套级别 1 的文本和段落样式。这会导致以下呈现效果:

  • 文本:“此段落位于列表中”是呈现的文本。文本本身永远不会继承。
  • 对齐:文本使用“END”对齐渲染,该对齐方式继承自父项的第二个 ParagraphMarker
  • 前景颜色:文本使用 LIGHT1 文本前景颜色渲染,该颜色继承自父项的第二个 TextRun

更新和继承文本和段落样式之间的交互

子形状中未设置的文本样式将继承其父项的值。在子文件中设置的文本样式将“替换”某些局部作用域内的父项值。

您可以使用 UpdateTextStyleRequest 取消子形状的文本样式设置,使其不再具有局部替换项,从而从父形状继承其样式。此外,如果更新子项的文本样式以匹配从父项继承的值,则会隐式取消设置样式,以便其使用继承的值。

这不会影响更新后立即显示的文本的视觉外观,但如果您之后更新了父占位符中的段落或文本样式,则可能会有影响。此继承行为与幻灯片编辑器的行为一致,因此您可以先试验样式更改的结果,然后再根据 API 进行操作。

示例

请考虑上一个示例ChildPlaceholderParentPlaceholder 的定义。

现在,假设您提交了以下 UpdateTextStyleRequest

{ "updateTextStyle": {
    "objectId": "ChildPlaceholder",
    "style": {"foregroundColor": {"opaqueColor": {"themeColor": "DARK1"} }, },
    "textRange": { "type": "ALL" },
    "fields": "foregroundColor"
  }
}

此请求会尝试将 DARK1 foregroundColor 设置为 ChildPlaceholder 的所有文本,使用字段掩码指定只应更改元素的前景颜色。此请求具有以下结果:

  • 第一段:新的 foregroundColor 与继承的 foregroundColor 匹配,因此此样式保持不变,仍会继承样式。
  • 第二段:新的 foregroundColor 与继承的 foregroundColor 不匹配,因此第二个段落的前景颜色更新为 DARK1

ChildPlaceholder 的文本内容现在为:

"text": {
  "textElements": [
    { "startIndex": 0,  "endIndex": 1,
      "paragraphMarker": {
        "style": {},
      }
    },
    { "startIndex": 0,  "endIndex": 1,
      "textRun": {
        "content": "This is my first paragraph\n",
        "style": {},
      }
      ...
    },
    { "startIndex": 1,  "endIndex": 2,
      "paragraphMarker": {
        "style": {},
        "bullet": {"nestingLevel": 1, "listId": "someListId", "glyph": "●" }
      }
    },
    { "startIndex": 1,  "endIndex": 2,
      "textRun": {
        "content": "This paragraph is in a list\n",
        "style": {"foregroundColor": {"opaqueColor": {"themeColor": "DARK1"} }, },
        ...
      }
    }
  ]
}

项目符号文本样式

与普通文本一样,项目符号也有控制字形渲染方式的文本样式。这些文本样式无法直接使用幻灯片 API 进行修改。不过,如果您使用 UpdateTextStyleRequest 更新包含项目符号的完整段落,Slides API 就会更新项目符号的文本样式以保持一致。

项目符号文本样式遵循的继承层次结构与普通文本样式略有不同。

  1. 特定嵌套级别的项目符号首先会继承项目符号的 List 对象内 NestingLevel.bullet_style 字段中设置的 TextStyle
  2. 接下来,它会从其父占位符的 List 中的相应 NestingLevel.bullet_style 继承。
  3. 最后,它会设法从其余的父占位符对象继承属性。