文档属性记录的是内容之外的信息:标题、作者、主题、关键词、公司、修订次数,以及由业务系统写入的自定义字段。批量归档时,属性可以把文档从文件名中解放出来;内容审阅时,属性又能说明文档的来历与版本。把属性读写放进浏览器,用户选中文件即可完成核对与补录,不必上传到服务器。
本文用 Spire.Doc for JavaScript 在浏览器中读取与写入 Word 文档属性。示例使用三份文档:Archive.docx 为已归档的《2026 年第三季度经营分析报告》,属性齐全;Draft.docx 为待补录属性的《2027 年度数字化转型项目立项建议书》;Contract.docx 为带有合同号等自定义属性的《智能仓储设备采购合同》。整个过程基于 WebAssembly 在浏览器端完成,无需安装 Office,也不依赖任何后端,文档在本地完成读写,不会因使用该库而上传到服务器。
本文介绍三个功能点:
Word 文档的属性分为两类,存放位置与用途不同:
| 类别 | 访问入口 | 典型字段 |
|---|---|---|
| 内置属性 | Document.BuiltinDocumentProperties |
标题、作者、主题、关键词、公司、修订次数 |
| 自定义属性 | Document.CustomDocumentProperties |
合同号、项目编号、审核状态等业务字段 |
内置属性由 Word 规定名称与含义,多数可以在“文件 - 信息”面板中看到;自定义属性由业务方定义,名称与用途不受限制,值的类型由 DocumentProperty.ValueType 描述。
有关安装和项目配置,请参考 React 项目中集成 Spire.Doc for JavaScript。下面的示例假定 Spire.Doc 已安装、WebAssembly 模块已初始化。
读取 Word 文档的内置摘要属性
读取 Word 文档的内置摘要属性,通过 Document.BuiltinDocumentProperties 完成。该属性返回一个集合,标题、作者、主题等字段以与 C# 一致的首字母大写形式暴露,直接按名称读取即可。读取结果通常用于核对:确认标题与文件名是否一致、作者是否为空、创建时间是否落在归档区间内。
内置属性可以按用途分为三组:
| 分组 | 典型字段 | 读取特点 |
|---|---|---|
| 摘要信息 | Title、Subject、Author、Keywords、Comments、LastAuthor、RevisionNumber、CreateDate、LastSaveDate |
字符串或日期,可直接读取 |
| 扩展信息 | Category、Company、Manager、ContentStatus、HyperLinkBase |
字符串,未设置时可能为空 |
| 统计信息 | PageCount、WordCount、CharCount、ParagraphCount、LinesCount、BytesCount |
只读,来自文件保存时记录的统计值 |
具体操作步骤如下:
- 获取 Spire.Doc 的 WASM 模块,确认已就绪。
- 读入字体文件与
Archive.docx,创建Document对象并加载该文件。 - 通过
BuiltinDocumentProperties依次读取标题、作者、主题等属性。 - 把各项值拼成制表符分隔的文本,写入 VFS。
- 从 VFS 读出文本文件并触发浏览器下载。
读取 Word 文档的内置摘要属性的代码如下:
function App() {
const readBuiltinProperties = async () => {
// 获取 Spire.Doc 的 WASM 模块
const docModule = window.wasmModule?.spiredoc;
if (!docModule) {
alert('Spire.Doc is not ready yet');
return;
}
// 载入待检查的文档
await window.spire.FetchFileToVFS('Archive.docx', '', `${process.env.PUBLIC_URL}/data/`);
const doc = new docModule.Document();
doc.LoadFromFile('Archive.docx');
// 日期属性返回 Date 对象,先格式化再拼入文本
const formatDate = (value) =>
value instanceof Date ? value.toLocaleString('zh-CN', { hour12: false }) : '';
const props = doc.BuiltinDocumentProperties;
const report = [
`标题\t${props.Title ?? ''}`,
`主题\t${props.Subject ?? ''}`,
`作者\t${props.Author ?? ''}`,
`最后修改者\t${props.LastAuthor ?? ''}`,
`关键词\t${props.Keywords ?? ''}`,
`备注\t${props.Comments ?? ''}`,
`类别\t${props.Category ?? ''}`,
`公司\t${props.Company ?? ''}`,
`修订次数\t${props.RevisionNumber ?? ''}`,
`创建时间\t${formatDate(props.CreateDate)}`,
`最后保存时间\t${formatDate(props.LastSaveDate)}`,
].join('\r\n');
// 写入 VFS,再读出为 Blob 触发下载
window.dotnetRuntime.Module.FS.writeFile('BuiltinProperties.txt', report);
doc.Dispose();
const fileArray = window.dotnetRuntime.Module.FS.readFile('BuiltinProperties.txt');
const blob = new Blob([fileArray], { type: 'text/plain;charset=utf-8' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'BuiltinProperties.txt';
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>读取文档属性</h1>
<button onClick={readBuiltinProperties}>导出属性清单</button>
</div>
);
}
export default App;
导出的属性清单如下,左侧为待检查的归档文档:

清单共 11 项,标题、主题、作者、关键词、备注、类别与公司均与归档要求一致;修订次数为 7;创建时间与最后保存时间已由 toLocaleString 格式化为本地时间,分别为 2026/10/12 09:20:00 与 2026/10/15 16:05:00。
未设置的属性返回什么
未设置的内置属性多数返回空字符串;Keywords、ContentStatus 等字段在文档中没有对应项时返回 null,示例中的 Draft.docx 即如此。日期类属性返回 JavaScript Date 对象,未设置时是公元 1 年的默认值,而不是空字符串。因此,null 与空字符串都只表示没有可读的值,不能据此判断属性是“从未设置”还是“写入过空值”。代码中的 ?? '' 只是防止 null 被拼成 undefined,并不代表属性确实存在。
统计类属性与正文内容的关系
PageCount、WordCount、CharCount、ParagraphCount 等统计字段读取的是文件保存时记录在 docProps/app.xml 中的值,而不是按当前内容重新统计的结果。示例文档未记录统计值,读取时 WordCount、CharCount、ParagraphCount 均为 0,PageCount 默认为 1。调用 doc.UpdateWordCount() 后,字数、字符数与段落数会按当前内容重新计算(示例分别为 898、1151、88),PageCount、LinesCount 与 BytesCount 不受影响。需要准确的统计值时,应先调用该方法,而不是直接读取属性。
设置 Word 文档的内置摘要属性
设置 Word 文档的内置摘要属性,通过为 BuiltinDocumentProperties 的对应字段赋值完成。归档、交付和审核都要求属性完整,与其逐个在 Word 中补录,不如在生成环节统一写入:标题取文档名称、作者取当前处理部门、关键词取业务标签,保证一批文档的属性口径一致。
示例为讨论稿补录以下字段:
| 属性 | 写入值 | 说明 |
|---|---|---|
Title |
2027 年度数字化转型项目立项建议书 | 文档标题 |
Subject |
项目立项建议 | 主题 |
Author |
数字化转型办公室 | 作者 |
Keywords |
数字化转型; 立项建议; 2027 年度 | 多个关键词用分号分隔 |
Comments |
按归档规范补录摘要属性 | 备注 |
Category |
立项材料 | 类别 |
Company |
衡远智造股份有限公司 | 公司 |
RevisionNumber |
'5' |
按字符串写入 |
LastAuthor |
数字化转型办公室 | 最后修改者 |
CreateDate |
new Date('2026-10-08T10:00:00+08:00') |
需传 Date 对象 |
具体操作步骤如下:
- 获取 WASM 模块,读入字体与
Draft.docx并加载。 - 为标题、主题、作者、关键词、备注、类别与公司赋值。
- 以字符串写入修订次数与最后修改者,以
Date对象写入创建时间。 - 保存为
DraftWithProperties.docx。 - 从 VFS 读出结果文件并触发浏览器下载。
设置 Word 文档的内置摘要属性的代码如下:
function App() {
const setBuiltinProperties = async () => {
// 获取 Spire.Doc 的 WASM 模块
const docModule = window.wasmModule?.spiredoc;
if (!docModule) {
alert('Spire.Doc is not ready yet');
return;
}
// 载入待补录属性的文档
await window.spire.FetchFileToVFS('Draft.docx', '', `${process.env.PUBLIC_URL}/data/`);
const doc = new docModule.Document();
doc.LoadFromFile('Draft.docx');
const props = doc.BuiltinDocumentProperties;
props.Title = '2027 年度数字化转型项目立项建议书';
props.Subject = '项目立项建议';
props.Author = '数字化转型办公室';
props.Keywords = '数字化转型; 立项建议; 2027 年度';
props.Comments = '按归档规范补录摘要属性';
props.Category = '立项材料';
props.Company = '衡远智造股份有限公司';
// 修订次数按字符串写入;日期属性需要传 Date 对象
props.RevisionNumber = '5';
props.LastAuthor = '数字化转型办公室';
props.CreateDate = new Date('2026-10-08T10:00:00+08:00');
const outputFileName = 'DraftWithProperties.docx';
doc.SaveToFile({ fileName: outputFileName, fileFormat: docModule.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={setBuiltinProperties}>写入属性</button>
</div>
);
}
export default App;
保存后重新加载结果文档,读回的属性如下:

重新加载后读回的 10 项属性与写入值一致,说明属性已随文档保存;创建时间写入的是 Date 对象,读回后同样按本地时间显示为 2026/10/8 10:00:00。
只读属性无法写入
PageCount、WordCount、CharCount、BytesCount、LinesCount 等统计字段只有读取接口,赋值不会写入结果;在 ES 模块中直接赋值还会抛出 TypeError,提示该属性只有 getter。这类值应在保存前通过 doc.UpdateWordCount() 按当前内容重新计算,而不是手工赋值。
修订次数与日期属性的写入类型
RevisionNumber 按字符串写入,传数字会提示 Assert failed: Value is not a String。CreateDate、LastSaveDate、LastPrinted 需要传 JavaScript Date 对象,传字符串会提示 Assert failed: Value is not a Date。示例中的 new Date('2026-10-08T10:00:00+08:00') 写入后读回仍为 2026/10/8 10:00:00;日期属性按墙上时间往返,跨时区读写时,建议先确认浏览器时区与文档所在时区是否一致。
修改后如何确认属性已经保存
写入是否成功,以重新加载后读取到的值为准。保存后新建一个 Document 加载结果文件,再读取对应字段即可核对:
// 保存后重新加载结果文档,读回写入的值
const check = new docModule.Document();
check.LoadFromFile('DraftWithProperties.docx');
const checkProps = check.BuiltinDocumentProperties;
console.log(checkProps.Title);
console.log(checkProps.Author);
check.Dispose();
属性写入后为何在资源管理器中看不到
Windows 资源管理器的详细信息栏只显示部分摘要字段,且依赖属性处理程序。Category、Company 等字段需要在 Word 中打开“文件 - 信息 - 属性 - 高级属性”查看。写入是否成功,应以重新加载文档后读取到的值为准,而不是依赖文件列表的显示。
管理 Word 文档的自定义属性
管理 Word 文档的自定义属性,通过 Document.CustomDocumentProperties 集合完成。业务字段不适合塞进内置属性:合同号、项目编号、审核状态这类信息,用自定义属性保存更清晰,名称自定、互不干扰,也便于按名称检索。该集合支持新增、按名称或索引读取、修改与删除。
涉及的主要成员如下:
| 成员 | 作用 |
|---|---|
CustomDocumentProperties.Add(name, value) |
新增属性,类型按传入的 JavaScript 值推断 |
CustomDocumentProperties.get_Item(name) |
按名称取出 DocumentProperty |
CustomDocumentProperties.get_Item(index) |
按索引取出,用于遍历 |
DocumentProperty.Name |
属性名称 |
DocumentProperty.Value |
属性值,读取时返回包装对象,需用 ToString() 转成文本 |
DocumentProperty.ValueType |
属性类型枚举 |
CustomDocumentProperties.Remove(name) |
按名称删除属性 |
CustomDocumentProperties.Count |
属性总数 |
示例合同已带有 ContractNo(合同号)与 Department(归口部门)两个自定义属性。演示过程新增审核状态与档案盒号,改写合同号,再删除档案盒号,最后遍历全部属性生成清单。
具体操作步骤如下:
- 获取 WASM 模块,读入字体与
Contract.docx并加载。 - 新增
ReviewStatus与ArchiveBox两个自定义属性。 - 按名称取出合同号属性,用包装后的字符串改写其值。
- 按名称删除档案盒号属性。
- 遍历全部自定义属性生成清单,保存文档并同时下载文档与清单。
管理 Word 文档的自定义属性的代码如下:
function App() {
const manageCustomProperties = async () => {
// 获取 Spire.Doc 的 WASM 模块
const docModule = window.wasmModule?.spiredoc;
if (!docModule) {
alert('Spire.Doc is not ready yet');
return;
}
// 载入合同文档
await window.spire.FetchFileToVFS('Contract.docx', '', `${process.env.PUBLIC_URL}/data/`);
const doc = new docModule.Document();
doc.LoadFromFile('Contract.docx');
const custom = doc.CustomDocumentProperties;
// 新增自定义属性
custom.Add('ReviewStatus', '待审核');
custom.Add('ArchiveBox', 'A-03');
// 按名称取出,用包装后的字符串修改值
custom.get_Item('ContractNo').Value = new docModule.String('HY-CG-2026-0418-REV2');
// 按名称删除
custom.Remove('ArchiveBox');
// 遍历全部属性生成清单
let report = '名称\t值\t类型\r\n';
for (let i = 0; i < custom.Count; i++) {
const prop = custom.get_Item(i);
report += `${prop.Name}\t${prop.ToString()}\t${prop.ValueType}\r\n`;
}
window.dotnetRuntime.Module.FS.writeFile('CustomProperties.txt', report);
const outputFileName = 'ContractWithProperties.docx';
doc.SaveToFile({ fileName: outputFileName, fileFormat: docModule.FileFormat.Docx2013 });
doc.Dispose();
// 依次下载结果文档与属性清单
const outputs = [
[outputFileName, 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'],
['CustomProperties.txt', 'text/plain;charset=utf-8'],
];
for (const [fileName, mime] of outputs) {
const fileArray = window.dotnetRuntime.Module.FS.readFile(fileName);
const blob = new Blob([fileArray], { type: mime });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = fileName;
a.click();
URL.revokeObjectURL(url);
}
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>管理自定义属性</h1>
<button onClick={manageCustomProperties}>处理属性</button>
</div>
);
}
export default App;
处理后的文档与属性清单如下:

合同号已改为 HY-CG-2026-0418-REV2,新增的 ReviewStatus 保留在集合中,ArchiveBox 已被删除,原有的 Department 保持不变;类型列取自 DocumentProperty.ValueType,三项均为 PropertyValueType.String。
修改已有属性的正确写法
对同名属性再次调用 Add() 不会覆盖原值,集合的项数与值都保持不变,因此不能用 Add() 完成修改。字符串属性应通过 get_Item() 取出 DocumentProperty,再用 new docModule.String() 包装新值赋给 Value;直接传字符串会提示参数为空(ArgumentNull_Generic)。数字与布尔属性需要与类型匹配的包装值,较为直接的做法是先删除再新增,让 Add() 按新值重新推断类型:
const custom = doc.CustomDocumentProperties;
// 字符串值:用 new docModule.String 包装
custom.get_Item('ContractNo').Value = new docModule.String('HY-CG-2026-0418-REV2');
// 数字或布尔值:先删除再新增,类型随新值推断
custom.Remove('Amount');
custom.Add('Amount', 367.2);
名称大小写与重复新增
自定义属性的名称不区分大小写:已有 ContractNo 时再调用 Add('contractno', ...),集合中不会多出一项。对同名属性再次调用 Add() 同样会被忽略,既不会新增条目,也不会改写原值。修改已有属性请使用上文的 Value 赋值或先删后加。
值类型如何确定
Add(name, value) 按传入的 JavaScript 值推断类型:字符串保存为 PropertyValueType.String,整数保存为 PropertyValueType.Int,小数保存为 PropertyValueType.Double,布尔值保存为 PropertyValueType.Boolean。ValueType 返回枚举对象,直接拼进字符串即可得到 PropertyValueType.String 这样的名称,无需另行映射。
日期值暂不支持:传入 Date 对象后集合中会多出一项,但按名称读取该项会提示 Property value is of unsupported type。日期类信息建议以 2026-09-28 这样的 ISO 字符串保存,读取时再按需转换。
属性与文档变量的区别
文档变量(doc.Variables)是 Word 域代码可以引用的键值对,会随域更新显示在正文中;自定义属性则是文档元数据,不参与正文排版。需要让正文自动显示合同号时,应写入文档变量并在正文插入对应域;只需要记录信息时,使用自定义属性即可。
常见问题
读写文档属性时,文件需要上传到服务器吗
本文的用法不需要上传。Spire.Doc for JavaScript 基于 WebAssembly 在浏览器端运行,文档通过虚拟文件系统(VFS)在本地读写,加载、读取、修改与保存都在本地完成,库本身不会把文件发往服务器。文件最终是否会离开设备,取决于你在页面上另外接入的代码。
自定义属性可以保存日期吗
实测在 Spire.Doc for JavaScript 中传入 Date 对象并不可靠:Add() 调用后集合项数会增加,但按名称读取该项会提示 Property value is of unsupported type。日期类信息建议以 2026-09-28 这样的 ISO 字符串保存,读取后再按业务需要转换。
const custom = doc.CustomDocumentProperties;
// 以字符串保存日期,读取时再转换
custom.Add('SignDate', '2026-09-28');
保存后,最后修改者和最后保存时间会自动更新吗
实测保存不会自动改写这两个字段:写入 LastAuthor 与 LastSaveDate 后保存并重新加载,读到的仍是写入的值;未写入时则保留文件原有的值。需要让它们反映本次处理,应在保存前显式赋值。
读取到的属性是 null,是属性不存在吗
不一定。未设置的内置属性多数返回空字符串,Keywords、ContentStatus 等字段可能返回 null,两种结果都只表示没有可读的值,不能区分“从未设置”和“设置为空”。核对用途下,应结合文档来源与业务规则判断,而不是只看返回值。
获取免费许可证
如果您希望删除结果文档中的评估消息,或者摆脱功能限制,请该Email地址已收到反垃圾邮件插件保护。要显示它您需要在浏览器中启用JavaScript。获取有效期 30 天的临时许可证。







