评估结论、部门名称、产品线归属这类字段,取值范围通常是有限的几种。让填写人自由输入,容易出现“研发部”“研发中心”“研发”混用的情况,后续汇总时不得不逐条清洗。Word 的下拉列表与组合框内容控件把可选值预先写入文档,填写人只能从中挑选,数据格式从源头上就统一了。
两者的区别在于是否允许超出预置范围:下拉列表只接受列表内的选项,组合框则允许在列表之外自行输入。选择哪一种,取决于业务上是否需要保留例外。
本文用 Spire.Doc for JavaScript 在浏览器中创建这两类控件,并演示如何修改已有组合框的列表项与选中值。全部处理在 WebAssembly 中完成,文档不经过服务器。
本文介绍三个功能点:
两类控件都通过 SDTProperties.ControlProperties 挂载列表数据,SdtListItem 是列表中的一项:
| 控件类型 | SDTType 取值 |
控制属性类 | 是否允许自定义输入 |
|---|---|---|---|
| 下拉列表内容控件 | SdtType.DropDownList |
SdtDropDownList |
否 |
| 组合框内容控件 | SdtType.ComboBox |
SdtComboBox |
是 |
有关安装和项目配置,请参考 React 项目中集成 Spire.Doc for JavaScript。下面的示例假定 Spire.Doc 已安装、WebAssembly 模块已初始化。
添加下拉列表内容控件
下拉列表适合取值完全固定的字段,例如评估等级、审批结论、费用类别。创建时先设定 SDTType 为 SdtType.DropDownList,再构造 SdtDropDownList,把每个选项以 SdtListItem 的形式加入 ListItems。
添加下拉列表内容控件涉及以下成员:
| 成员 | 作用 |
|---|---|
SdtType.DropDownList |
指定控件类型为下拉列表 |
SdtDropDownList |
下拉列表的控制属性对象 |
ListItems.Add(item) |
向列表追加一个选项 |
SdtListItem(displayText) |
创建选项,显示文本与值相同 |
SdtListItem(displayText, value) |
创建选项,分别指定显示文本与值 |
ListItems.get_Item(index) |
按索引获取选项,索引从 0 开始 |
具体操作步骤如下:
- 获取 Spire.Doc 的 WASM 模块,确认已就绪。
- 载入字体,使用
Document类创建文档并添加一节,写入标题与说明文字。 - 在段落中创建
StructureDocumentTagInline控件,将SDTType设为SdtType.DropDownList。 - 创建
SdtDropDownList并逐个加入SdtListItem,然后赋给ControlProperties。 - 向
SDTContent写入当前选中项的文字,保存文件并从 VFS 读出下载。
添加下拉列表内容控件的代码如下:
function App() {
const addDropDownList = async () => {
// 获取 Spire.Doc 的 WASM 模块
const wasmModule = window.wasmModule?.spiredoc;
if (!wasmModule) {
alert('Spire.Doc is not ready yet');
return;
}
// 载入字体
await window.spire.FetchFileToVFS('msyh.ttc', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
await window.spire.FetchFileToVFS('msyhbd.ttc', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
// 创建文档并添加一节
const doc = new wasmModule.Document();
const section = doc.AddSection();
// 添加标题与副标题
const titleParagraph = section.AddParagraph();
const titleRange = titleParagraph.AppendText('供应商分级评估表');
titleRange.CharacterFormat.FontName = '微软雅黑';
titleRange.CharacterFormat.FontSize = 19;
titleRange.CharacterFormat.Bold = true;
titleRange.CharacterFormat.TextColor = wasmModule.Color.FromArgb(255, 15, 110, 90);
titleParagraph.Format.AfterSpacing = 6;
const subtitleParagraph = section.AddParagraph();
const subtitleRange = subtitleParagraph.AppendText('采购部 2026 年第三季度');
subtitleRange.CharacterFormat.FontName = '微软雅黑';
subtitleRange.CharacterFormat.FontSize = 9;
subtitleRange.CharacterFormat.TextColor = wasmModule.Color.FromArgb(255, 89, 89, 89);
subtitleParagraph.Format.AfterSpacing = 16;
// 添加控件前的说明文字
const paragraph = section.AddParagraph();
paragraph.AppendText('评估结论: ');
// 创建行内内容控件并放入段落
const sdt = new wasmModule.StructureDocumentTagInline(doc);
paragraph.ChildObjects.Add(sdt);
// 指定控件类型为下拉列表
sdt.SDTProperties.SDTType = wasmModule.SdtType.DropDownList;
sdt.SDTProperties.Alias = '评估结论';
sdt.SDTProperties.Tag = 'evaluation-result';
sdt.SDTProperties.Appearance = wasmModule.SdtAppearance.Tags;
// 构造下拉列表并添加选项
const list = new wasmModule.SdtDropDownList();
list.ListItems.Add(new wasmModule.SdtListItem('优秀'));
list.ListItems.Add(new wasmModule.SdtListItem('良好'));
list.ListItems.Add(new wasmModule.SdtListItem('合格'));
list.ListItems.Add(new wasmModule.SdtListItem('待改进'));
sdt.SDTProperties.ControlProperties = list;
// 写入当前选中项的文字
const content = new wasmModule.TextRange(doc);
content.Text = list.ListItems.get_Item(1).DisplayText;
sdt.SDTContent.ChildObjects.Add(content);
// 添加说明文字
const noteParagraph = section.AddParagraph();
noteParagraph.Format.BeforeSpacing = 10;
const noteRange = noteParagraph.AppendText('下拉列表只允许从预置选项中挑选,适合结论、等级一类的固定取值。');
noteRange.CharacterFormat.FontName = '微软雅黑';
noteRange.CharacterFormat.FontSize = 9;
noteRange.CharacterFormat.TextColor = wasmModule.Color.FromArgb(255, 89, 89, 89);
// 保存结果文件
const outputFileName = 'AddDropDownListContentControl.docx';
doc.SaveToFile({ fileName: outputFileName, fileFormat: wasmModule.FileFormat.Docx2013 });
doc.Dispose();
// 从 VFS 读取生成的文件,触发下载
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>添加下拉列表内容控件</h1>
<button onClick={addDropDownList}>生成文档</button>
</div>
);
}
export default App;
添加下拉列表内容控件后的文档:

选项的显示文本与值
SdtListItem 有两个构造函数:
| 写法 | 显示文本 | 内部值 |
|---|---|---|
new SdtListItem('良好') |
良好 | 良好 |
new SdtListItem('良好', 'good') |
良好 | good |
只传一个参数时,显示文本与内部值相同,适合选项本身就是业务术语的场景。传入两个参数时,文档中显示的是第一个参数,而程序读取、比较时可以使用第二个参数;把内部值设为稳定的英文标识,可以在界面文案调整后仍保持数据含义不变。
添加组合框内容控件
组合框在提供候选列表的同时,允许填写人输入列表以外的内容,适合产品线、供应商名称这类“通常固定、偶尔有例外”的字段。代码结构与下拉列表几乎完全一致,只是把类型换成 SdtType.ComboBox,控制属性类换成 SdtComboBox。
具体操作步骤如下:
- 获取 Spire.Doc 的 WASM 模块,确认已就绪。
- 载入字体,使用
Document类创建文档并添加一节,写入标题与说明文字。 - 在段落中创建
StructureDocumentTagInline控件,将SDTType设为SdtType.ComboBox。 - 创建
SdtComboBox并加入候选项,赋给ControlProperties,再写入选中项文字。 - 使用
SaveToFile()保存结果文件,从 VFS 读出并触发浏览器下载。
添加组合框内容控件的代码如下:
function App() {
const addComboBox = async () => {
// 获取 Spire.Doc 的 WASM 模块
const wasmModule = window.wasmModule?.spiredoc;
if (!wasmModule) {
alert('Spire.Doc is not ready yet');
return;
}
// 载入字体
await window.spire.FetchFileToVFS('msyh.ttc', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
await window.spire.FetchFileToVFS('msyhbd.ttc', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
// 创建文档并添加一节
const doc = new wasmModule.Document();
const section = doc.AddSection();
// 添加标题与副标题
const titleParagraph = section.AddParagraph();
const titleRange = titleParagraph.AppendText('产品线登记表');
titleRange.CharacterFormat.FontName = '微软雅黑';
titleRange.CharacterFormat.FontSize = 19;
titleRange.CharacterFormat.Bold = true;
titleRange.CharacterFormat.TextColor = wasmModule.Color.FromArgb(255, 15, 110, 90);
titleParagraph.Format.AfterSpacing = 6;
const subtitleParagraph = section.AddParagraph();
const subtitleRange = subtitleParagraph.AppendText('市场部 2026 年 11 月');
subtitleRange.CharacterFormat.FontName = '微软雅黑';
subtitleRange.CharacterFormat.FontSize = 9;
subtitleRange.CharacterFormat.TextColor = wasmModule.Color.FromArgb(255, 89, 89, 89);
subtitleParagraph.Format.AfterSpacing = 16;
// 添加控件前的说明文字
const paragraph = section.AddParagraph();
paragraph.AppendText('合作产品线: ');
// 创建行内内容控件并放入段落
const sdt = new wasmModule.StructureDocumentTagInline(doc);
paragraph.ChildObjects.Add(sdt);
// 指定控件类型为组合框
sdt.SDTProperties.SDTType = wasmModule.SdtType.ComboBox;
sdt.SDTProperties.Alias = '合作产品线';
sdt.SDTProperties.Tag = 'product-line';
sdt.SDTProperties.Appearance = wasmModule.SdtAppearance.Tags;
// 构造组合框并添加候选项
const combo = new wasmModule.SdtComboBox();
combo.ListItems.Add(new wasmModule.SdtListItem('办公套件'));
combo.ListItems.Add(new wasmModule.SdtListItem('文档服务'));
combo.ListItems.Add(new wasmModule.SdtListItem('数据平台'));
combo.ListItems.Add(new wasmModule.SdtListItem('演示组件'));
sdt.SDTProperties.ControlProperties = combo;
// 写入当前选中项的文字
const content = new wasmModule.TextRange(doc);
content.Text = combo.ListItems.get_Item(1).DisplayText;
sdt.SDTContent.ChildObjects.Add(content);
// 添加说明文字
const noteParagraph = section.AddParagraph();
noteParagraph.Format.BeforeSpacing = 10;
const noteRange = noteParagraph.AppendText('组合框在保留预置选项的同时,允许填入列表以外的内容。');
noteRange.CharacterFormat.FontName = '微软雅黑';
noteRange.CharacterFormat.FontSize = 9;
noteRange.CharacterFormat.TextColor = wasmModule.Color.FromArgb(255, 89, 89, 89);
// 保存结果文件
const outputFileName = 'AddComboBoxContentControl.docx';
doc.SaveToFile({ fileName: outputFileName, fileFormat: wasmModule.FileFormat.Docx2013 });
doc.Dispose();
// 从 VFS 读取生成的文件,触发下载
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>添加组合框内容控件</h1>
<button onClick={addComboBox}>生成文档</button>
</div>
);
}
export default App;
添加组合框内容控件后的文档:

修改组合框的列表项与选中值
实际业务中,选项会随时间调整:某个产品线下线,需要从列表中删掉;新增一条产品线,需要补进去;回答某些表单时,还需要预先替用户选中推荐值。这些操作都可以在已加载的文档上完成,无需重新生成整个文件。
修改时先遍历正文中的段落与表格,找到 DocumentObjectType 为 StructureDocumentTagInline 且类型为 ComboBox 的控件,再对其 ControlProperties 调用 ListItems 的增删方法。示例从 public/data 读取 ComboBox.docx,运行时请把该文件放入项目的 public/data 目录。
| 成员 | 作用 |
|---|---|
ListItems.RemoveAt(index) |
删除指定索引的选项 |
ListItems.Add(item) |
追加一个新选项 |
ListItems.Count |
当前选项数量 |
ListItems.SelectedValue |
选中值,需赋值为 SdtListItem 对象 |
具体操作步骤如下:
- 获取 Spire.Doc 的 WASM 模块,确认已就绪。
- 载入字体,把待处理的
ComboBox.docx读入 VFS,并加载为Document。 - 遍历各节的正文对象与段落子对象,筛选出组合框内容控件。
- 用
RemoveAt删除旧选项,用Add追加新选项,再按Value比较并设置SelectedValue。 - 使用
SaveToFile()保存结果文件,从 VFS 读出并触发浏览器下载。
修改组合框列表项与选中值的代码如下:
function App() {
const updateComboBoxItems = async () => {
// 获取 Spire.Doc 的 WASM 模块
const wasmModule = window.wasmModule?.spiredoc;
if (!wasmModule) {
alert('Spire.Doc is not ready yet');
return;
}
// 载入待处理的文档
await window.spire.FetchFileToVFS('ComboBox.docx', '', `${process.env.PUBLIC_URL}/data/`);
const doc = new wasmModule.Document();
doc.LoadFromFile('ComboBox.docx');
// 遍历各节,查找组合框内容控件
for (let s = 0; s < doc.Sections.Count; s++) {
const section = doc.Sections.get_Item(s);
for (let i = 0; i < section.Body.ChildObjects.Count; i++) {
const obj = section.Body.ChildObjects.get_Item(i);
if (obj.DocumentObjectType !== wasmModule.DocumentObjectType.Paragraph) continue;
for (let j = 0; j < obj.ChildObjects.Count; j++) {
const child = obj.ChildObjects.get_Item(j);
if (child.DocumentObjectType !== wasmModule.DocumentObjectType.StructureDocumentTagInline) continue;
if (child.SDTProperties.SDTType !== wasmModule.SdtType.ComboBox) continue;
const combo = child.SDTProperties.ControlProperties;
// 删除索引为 1 的旧选项,再追加一个新选项
combo.ListItems.RemoveAt(1);
combo.ListItems.Add(new wasmModule.SdtListItem('智能文档', '智能文档'));
// 按 Value 查找新选项并设为选中值
for (let k = 0; k < combo.ListItems.Count; k++) {
const item = combo.ListItems.get_Item(k);
if (item.Value === '智能文档') {
combo.ListItems.SelectedValue = item;
}
}
}
}
}
// 保存结果文件
const outputFileName = 'UpdateComboBoxItems.docx';
doc.SaveToFile({ fileName: outputFileName, fileFormat: wasmModule.FileFormat.Docx2013 });
doc.Dispose();
// 从 VFS 读取生成的文件,触发下载
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>修改组合框的列表项与选中值</h1>
<button onClick={updateComboBoxItems}>生成文档</button>
</div>
);
}
export default App;
处理前后的对比如下,左图为原始文档,右图为修改后的文档:

定位控件时的遍历顺序
示例只扫描了正文直属段落里的行内控件,这是最常见的存放位置。如果控件位于表格单元格中,需要先判断对象是否为 Table,再逐行、逐单元格地进入 Cell.ChildObjects 查找;如果控件是块级的 StructureDocumentTag,则应在 Body.ChildObjects 这一层直接比对。遍历时先判断 DocumentObjectType 再读取属性,可以避免把普通段落误当成控件处理。
常见问题
下拉列表与组合框应该如何选择
如果字段的取值需要严格限定在预置范围内,选下拉列表;如果列表只是提供常用候选、业务上允许填写列表以外的内容,选组合框。下拉列表更适合等级、状态、类别这类需要统一口径的字段,组合框更适合名称、产品线这类可能随业务扩展的字段。
设置 SelectedValue 后控件显示的文字没有变化
SelectedValue 要求赋值为 SdtListItem 对象,直接赋字符串不会生效。示例中先遍历 ListItems,用 Value 比较找到目标项,再把该项对象赋给 SelectedValue。修改完成后保存文件,Word 中的显示会随选中项更新。
RemoveAt 之后为什么选错了项
RemoveAt 删除元素后,后续选项的索引会整体前移。如果先删除再按原索引访问,得到的可能是另一个选项。稳妥的做法是删除后重新遍历 ListItems,按 Value 或 DisplayText 查找目标项,而不是沿用删除前的索引。
如何按用户看到的文字选中选项
Value 与 DisplayText 可能不同。若业务上以界面文字为准,把比较条件改为 item.DisplayText === '智能文档' 即可;若以稳定的内部标识为准,则继续比较 Value。两者不要混用,否则文案调整后容易出现选中失败。
获取免费许可证
如果您希望删除结果文档中的评估消息,或者摆脱功能限制,请该Email地址已收到反垃圾邮件插件保护。要显示它您需要在浏览器中启用JavaScript。获取有效期 30 天的临时许可证。







