确认单、报名表、签署页这类文档,除了文字字段,还经常需要两类交互元素:一组可以勾选的事项,以及一个格式统一的日期。用普通字符画出方框和日期,看起来相似,但无法记录勾选状态,日期也可能被填成各种写法。内容控件把这两类输入变成结构化对象:复选框保存 Checked 状态,日期控件保存完整的日期值与显示格式。
本文用 Spire.Doc for JavaScript 在浏览器中创建复选框与日期选择控件,并演示如何读取已有文档、批量切换复选框状态。处理过程在 WebAssembly 中完成,不依赖 Office,也不需要后端服务。
本文介绍三个功能点:
两类控件的类型与属性对象对应如下:
| 控件类型 | SDTType 取值 |
控制属性类 | 关键属性 |
|---|---|---|---|
| 复选框内容控件 | SdtType.CheckBox |
SdtCheckBox |
Checked |
| 日期选择内容控件 | SdtType.DatePicker |
SdtDate |
DateFormat、FullDate、CalendarType |
有关安装和项目配置,请参考 React 项目中集成 Spire.Doc for JavaScript。下面的示例假定 Spire.Doc 已安装、WebAssembly 模块已初始化。
添加复选框内容控件
复选框内容控件用来表示“是/否”的二值选择,通常成组出现,例如确认事项清单、设备清单、服务选项。控件本身只保存勾选状态,文档中显示的方框符号需要作为控件内容一并写入。
添加复选框内容控件涉及以下成员:
| 成员 | 作用 |
|---|---|
SdtType.CheckBox |
指定控件类型为复选框 |
SdtCheckBox |
复选框的控制属性对象 |
SdtCheckBox.Checked |
当前是否勾选 |
TextRange |
承载控件内显示的方框符号 |
CharacterFormat.FontName |
符号所用字体,示例使用 MS Gothic |
具体操作步骤如下:
- 获取 Spire.Doc 的 WASM 模块,确认已就绪。
- 载入字体,使用
Document类创建文档并添加一节,写入标题与说明。 - 为每个事项创建
StructureDocumentTagInline控件,将SDTType设为SdtType.CheckBox。 - 创建
SdtCheckBox并设置Checked,再向SDTContent写入对应的方框字符。 - 使用
SaveToFile()保存结果文件,从 VFS 读出并触发浏览器下载。
添加复选框内容控件的代码如下:
function App() {
const addCheckBox = 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 月 12 日');
subtitleRange.CharacterFormat.FontName = '微软雅黑';
subtitleRange.CharacterFormat.FontSize = 9;
subtitleRange.CharacterFormat.TextColor = wasmModule.Color.FromArgb(255, 89, 89, 89);
subtitleParagraph.Format.AfterSpacing = 16;
// 报名人信息
const info = section.AddParagraph();
info.AppendText('姓名:李然 部门:研发部');
info.Format.AfterSpacing = 10;
// 确认事项提示
const hint = section.AddParagraph();
const hintRange = hint.AppendText('请确认以下事项:');
hintRange.CharacterFormat.FontName = '微软雅黑';
hintRange.CharacterFormat.Bold = true;
hint.Format.AfterSpacing = 6;
// 逐项添加复选框控件
const items = [
['我已阅读课程须知', 'read-notice', true],
['我需要安排午餐', 'need-lunch', false],
['我需要打印纸质讲义', 'need-handout', true],
];
for (const [label, tag, checked] of items) {
const paragraph = section.AddParagraph();
paragraph.Format.LeftIndent = 24;
// 创建行内内容控件
const sdt = new wasmModule.StructureDocumentTagInline(doc);
paragraph.ChildObjects.Add(sdt);
// 指定控件类型为复选框
sdt.SDTProperties.SDTType = wasmModule.SdtType.CheckBox;
sdt.SDTProperties.Alias = label;
sdt.SDTProperties.Tag = tag;
// 设置勾选状态
const box = new wasmModule.SdtCheckBox();
box.Checked = checked;
sdt.SDTProperties.ControlProperties = box;
// 写入与状态对应的方框符号
const symbol = new wasmModule.TextRange(doc);
symbol.Text = checked ? '☒' : '☐';
symbol.CharacterFormat.FontName = 'MS Gothic';
symbol.CharacterFormat.FontSize = 12;
sdt.SDTContent.ChildObjects.Add(symbol);
// 在控件后追加事项名称
paragraph.AppendText(' ' + label);
}
// 添加提交说明
const noteParagraph = section.AddParagraph();
noteParagraph.Format.BeforeSpacing = 10;
const noteRange = noteParagraph.AppendText('请于 11 月 8 日前将本表交回培训组。');
noteRange.CharacterFormat.FontName = '微软雅黑';
noteRange.CharacterFormat.FontSize = 9;
noteRange.CharacterFormat.TextColor = wasmModule.Color.FromArgb(255, 89, 89, 89);
// 保存结果文件
const outputFileName = 'AddCheckBoxContentControl.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={addCheckBox}>生成文档</button>
</div>
);
}
export default App;
添加复选框内容控件后的文档:

勾选状态与显示符号要同步
SdtCheckBox.Checked 保存的是控件的逻辑状态,Word 显示的方框则来自控件内容中的字符。两者互相独立:只设置 Checked 而不写入符号,生成的复选框在 Word 中会是空白的;只改符号而不改 Checked,读取程序拿到的状态与看到的画面不一致。
示例用条件表达式同时处理两者:checked 为真时写 ☒(U+2612),否则写 ☐(U+2610),并把字体设为 MS Gothic,确保这两个字符有对应的字形。后续修改已有文档时,也需要按同样的规则同步更新。
添加日期选择内容控件
日期选择内容控件让填写人从日历中选取日期,并按预设格式显示,避免同一份文档中出现 2026.11.3、2026-11-03、2026年11月3日 等多种写法。控件保存完整的日期值,显示格式由 DateFormat 决定,两者分开设置。
添加日期选择内容控件涉及以下成员:
| 成员 | 作用 |
|---|---|
SdtType.DatePicker |
指定控件类型为日期选择 |
SdtDate |
日期控件的控制属性对象 |
SdtDate.DateFormat |
显示格式,如 yyyy.MM.dd |
SdtDate.FullDate |
完整日期值,需传入 JavaScript Date 对象 |
SdtDate.CalendarType |
日历类型,示例使用 CalendarType.Default |
具体操作步骤如下:
- 获取 Spire.Doc 的 WASM 模块,确认已就绪。
- 载入字体,使用
Document类创建文档并添加一节,写入标题与合同编号。 - 在段落中创建
StructureDocumentTagInline控件,将SDTType设为SdtType.DatePicker。 - 创建
SdtDate,设置DateFormat、CalendarType与FullDate,赋给ControlProperties。 - 写入格式化后的日期文字,保存文件并从 VFS 读出下载。
添加日期选择内容控件的代码如下:
function App() {
const addDatePicker = 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('合同编号 XM-2026-0527');
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.DatePicker;
sdt.SDTProperties.Alias = '签署日期';
sdt.SDTProperties.Tag = 'sign-date';
sdt.SDTProperties.Appearance = wasmModule.SdtAppearance.Tags;
// 设置日期格式与日期值
const date = new wasmModule.SdtDate();
date.CalendarType = wasmModule.CalendarType.Default;
date.DateFormat = 'yyyy.MM.dd';
date.FullDate = new Date(2026, 10, 3);
sdt.SDTProperties.ControlProperties = date;
// 写入格式化后的日期文字
const content = new wasmModule.TextRange(doc);
content.Text = '2026.11.03';
sdt.SDTContent.ChildObjects.Add(content);
// 补充签署地点
const place = section.AddParagraph();
place.AppendText('签署地点:北辰科技园 A 座 3 层会议室');
// 添加格式说明
const noteParagraph = section.AddParagraph();
noteParagraph.Format.BeforeSpacing = 10;
const noteRange = noteParagraph.AppendText('日期控件的显示格式由 DateFormat 决定,示例使用 yyyy.MM.dd。');
noteRange.CharacterFormat.FontName = '微软雅黑';
noteRange.CharacterFormat.FontSize = 9;
noteRange.CharacterFormat.TextColor = wasmModule.Color.FromArgb(255, 89, 89, 89);
// 保存结果文件
const outputFileName = 'AddDatePickerContentControl.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={addDatePicker}>生成文档</button>
</div>
);
}
export default App;
添加日期选择内容控件后的文档:

日期格式与 JavaScript Date 的月份
DateFormat 使用 Word 的日期格式占位符,大小写含义不同:
| 占位符 | 含义 | 示例 |
|---|---|---|
yyyy |
四位年份 | 2026 |
MM |
两位月份,不足补零 | 11 |
dd |
两位日期,不足补零 | 03 |
FullDate 需要传入 JavaScript 的 Date 对象,传入字符串会触发类型校验错误。需要注意,Date 构造函数中的月份从 0 开始计数,new Date(2026, 10, 3) 表示 2026 年 11 月 3 日,而不是 10 月。
批量切换复选框的勾选状态
确认单回收后,常见需求是把勾选状态整体反转,或按新的报名情况重置。逐个手工点击既慢又容易漏。用程序遍历文档中的复选框控件,翻转 Checked 并同步方块符号,可以一次处理完所有事项。
遍历方式与前文一致:先看正文对象是否为段落,再看段落子对象是否为 StructureDocumentTagInline,最后按 SdtType.CheckBox 过滤。示例从 public/data 读取 CheckBoxContentControl.docx,运行时请把该文件放入项目的 public/data 目录。
| 成员 | 作用 |
|---|---|
Document.LoadFromFile(path) |
载入 VFS 中的文档 |
SDTProperties.ControlProperties |
取得 SdtCheckBox 对象 |
SdtCheckBox.Checked |
读取或写入勾选状态 |
SDTContent.ChildObjects |
遍历控件内的符号文字并同步更新 |
具体操作步骤如下:
- 获取 Spire.Doc 的 WASM 模块,确认已就绪。
- 载入字体,把待处理的
CheckBoxContentControl.docx读入 VFS,并加载为Document。 - 遍历各节的正文对象与段落子对象,筛选出复选框内容控件。
- 翻转
Checked,再把控件内每个TextRange的文字更新为对应的方框符号。 - 使用
SaveToFile()保存结果文件,从 VFS 读出并触发浏览器下载。
批量切换复选框状态的代码如下:
function App() {
const updateCheckBox = async () => {
// 获取 Spire.Doc 的 WASM 模块
const wasmModule = window.wasmModule?.spiredoc;
if (!wasmModule) {
alert('Spire.Doc is not ready yet');
return;
}
// 载入待处理的文档
await window.spire.FetchFileToVFS('CheckBoxContentControl.docx', '', `${process.env.PUBLIC_URL}/data/`);
const doc = new wasmModule.Document();
doc.LoadFromFile('CheckBoxContentControl.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.CheckBox) continue;
// 翻转勾选状态
const box = child.SDTProperties.ControlProperties;
box.Checked = !box.Checked;
// 同步控件内的方框符号
for (let k = 0; k < child.SDTContent.ChildObjects.Count; k++) {
const inner = child.SDTContent.ChildObjects.get_Item(k);
if (inner.DocumentObjectType === wasmModule.DocumentObjectType.TextRange) {
inner.Text = box.Checked ? '☒' : '☐';
}
}
}
}
}
// 保存结果文件
const outputFileName = 'UpdateCheckBox.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={updateCheckBox}>生成文档</button>
</div>
);
}
export default App;
处理前后的对比如下,左图为原始文档,右图为切换后的文档:

常见问题
复选框内容控件在 Word 中为什么不显示方框
Checked 只决定逻辑状态,Word 不会根据它自动绘制符号。控件内的方框来自 SDTContent 中的字符,示例写入 ☒(U+2612)或 ☐(U+2610),并指定 MS Gothic 字体。缺少这段内容时,控件在文档中就呈现为空白。
FullDate 传入字符串为什么会报错
SdtDate.FullDate 要求的是 JavaScript Date 对象,不是格式化后的字符串。把字符串赋给它会在保存或读取属性时触发类型错误。正确写法是 date.FullDate = new Date(2026, 10, 3),显示文字另外通过 TextRange 写入。
为什么切换 Checked 后文档里的方框没有变化
同样是逻辑状态与显示内容分离导致的。程序修改 Checked 之后,还需要遍历 SDTContent.ChildObjects,把其中的 TextRange.Text 改成对应的方框字符。只改其中一项,就会出现状态与画面不一致的情况。
日期格式中的 MM 与 mm 有区别吗
有区别。在 Word 的日期格式中,M/MM 表示月份,m/mm 表示分钟;d/dd 表示日期,y/yyyy 表示年份。写成 yyyy.mm.dd 会把月份位置显示为分钟,结果不符合预期。示例统一使用 yyyy.MM.dd。
获取免费许可证
如果您希望删除结果文档中的评估消息,或者摆脱功能限制,请该Email地址已收到反垃圾邮件插件保护。要显示它您需要在浏览器中启用JavaScript。获取有效期 30 天的临时许可证。







