浅谈js操作word文档的那些事,关于Word.Application使用

4,520 阅读15分钟

本文简单的说一下如何使用js操作word文档。这篇文章的诞生,完全是因为工作的原因。因为当时所在的公司用了金格的文档处理插件,所以老板就让我们自己研究一下,看看用js到底该怎么做。说实话,当我拿到这个任务的时候,内心是抗拒的,因为在这之前,js操作word文档的这种骚操作,我连听都没听说过(这点我敢很自信的说,绝大部分刚学前端的应该都跟我一样),这不为难我吗。但工作就是工作,即便不行,硬着头皮也是要上的,就算到后来你会得到这样一个反应——你都做的什么玩意,这能用吗?但对于一个做开发的人来说,至少其学习的过程我是享受的。说真的,找文档找得是真辛苦,因为网上的用js写的都不直接,理论偏多,没实际操作代码,就连打开文档这最开始的第一步,我都是自己测了好久才测试出来原来是这么用的。当时为了研究这个,我还专门看了好久的VB语法,然后在word软件里先录制宏,操作一遍之后,再看宏里面的VB代码,然后猜测大概什么意思,再用js模拟,所以本文内容虽然不是很多,但确实是辛辛苦苦研究了3-4天才得到的东西。

直接进入正题吧。我们都知道,在IE浏览器中,有一个对象叫ActiveXObject,是其他浏览器没有的,其实我们判断是否为IE浏览器的时候,就可以根据有没有这个对象来判断。而如果我们想用js操作WORD,得先有一个对象,这个对象可以通过new ActiveXObject(“Word.Application”)来获取(注意:此处一定要区分大小写),它是专门针对word文档提供的, 获取到的这个对象,有很多属性和方法,通过属性赋值或调用方法的方式,就能实现对word的操作。不过既然是只有IE浏览器才有该对象,当然也就只有IE浏览器可以用了,其他浏览器是不支持的,是不是感觉IE又牛逼了一把。不过要声明一点,IE浏览器的默认设置是不允许自动启用Active的相关控件的,你得把IE浏览器的安全级别重新设置一下。具体操作请看 这里,我就懒得自己写了。

再次提醒,所有代码只能在IE上运行。

1、打开本地word文档

var word=new ActiveXObject("Word.Application"); // 创建一个ActiveXObject对象word.visible=true;
word.visible=true;
var documents = word.Documents;
documents.Open("F:\\worktest\\test.doc");//返回一个Document对象

心存怀疑的,你不妨把上面的代码复制到你页面上的script标签里面,试一下能不能打开(如果不行,记得操作之前点上面给的网址进去,照着设置一下你的浏览器)。我们先来分析一下上面的代码是什么意思。由于我自己也是第一次接触,有些地方说不清楚,也有可能说错。 解释一下:

var word=new ActiveXObject("Word.Application");word.visible=true;

这两句的作用相当于是打开你的word编辑软件,而

var documents = word.Documents;

这一句就是拿到你软件的窗口对象

documents.Open("F:\\worktest\\test.doc");

就是打开文档了。如果指定的文件不存在,就会什么也没有,打开失败。

Open ApI如下

expression.Open(FileName, ConfirmConversions, ReadOnly, 
AddToRecentFiles,PasswordDocument, PasswordTemplate, 
Revert, WritePasswordDocument,WritePasswordTemplate, 
Format, Encoding, Visible, 
OpenConflictDocument,OpenAndRepair, DocumentDirection, NoEncodingDialog)

参数说明:

参数 类型 说明
FileName Variant 类型 必需。文档名(可包含路径)。
ConfirmConversions Variant 类型 可选。该属性为 True 时,如果文件不是 Microsoft Word 格式,则显示“文件转换”对话框。
ReadOnly Variant 类型 可选。如果为 True,则以只读方式打开文档。注意 本参数不会覆盖保存的文档的只读建议设置。例如,如果文档在启用只读建议设置情况下保存,将 ReadOnly参数设为 False,也不会导致以可读写方式打开文件
AddToRecentFiles Variant 类型 可选。如果为True,则会将文件名添加至“文件”菜单底部的最近使用过的文件列表中
PasswordDocument Variant 类型 可选。打开此文档时所需的密码
PasswordTemplate Variant 类型 可选。打开此模板时所需的密码
Revert Variant 类型 可选。当 FileName
WritePasswordDocument Variant 类型 可选。保存对文档进行的更改时所需的密码
WritePasswordTemplate Variant 类型 可选。保存对模板进行的更改时所需的密码
Format Variant 类型 可选。打开文档时使用的文件转换器

2、关闭打开的文档。

这个很简单,没什么说的,无非就是Close,但是里面可以传递一个布尔值,如果你的文档修改过,false表示不保存直接关闭,true表示保存更改并关闭。

documents("test.doc").Close(false);//关闭
documents("test.doc").Close(true);//关闭,并保存更改

3、保存和另存word文档其实和上边一样,我们得先获取到word的操作窗口对象,才能实现保存。但有一点需要注意,我们要保存一篇文档,得先知道保存的是哪篇文档。因为你完全有可能同时打开了多个文档。所以我们的实际代码是这样的。(假定我们打开了上面的文档,并做了修改)

word.ActiveDocument.Save();//word.ActiveDocument指当前激活的文档
word.ActiveDocument.SaveAs("F:\\worktest\\gc22.doc"); // 另存

另存为的时候,我们可以改变文件名,注意,另存用的是SaveAs,不是保存用的Save,要注意区分,这一点站在软件的角度也应该能想到才是,只有另存为的时候才可以重命名。

说到这里,我们先讲点题外话,就跟我们用wps编辑word一样,我们有可能同时打开了多个文,就像下面这样:

一旦打开了多个文档,我们不管是编辑,还是保存,都是针对的当前激活的文档,比如,上图中的文档1是激活文档,我们点击保存(不是保存全部)时只会保存文档1,而不会保存test.doc。软件如此,js亦如是,编辑和保存时,都是针对的当前激活文档。在软件中,我们是通过手动点击标签的操作来切换激活文档的。而在js中,我们就只能通过代码实现了。

4、激活文档

documents("test.doc").Activate;

也可以把名称换为序列号,跟打开文档的顺序对应,第一个打开的为0,第二个打开的为1,......

documents(0).Activate;

5、撤销,重复与选择

// 撤销
function undo(){
    word.ActiveDocument.Undo;
}

// 重复操作上一步
function redo(){
    word.ActiveDocument.Redo;
}

// 把光标移到文档开始位置
function select1(){
    word.Selection.SetRange(0,0);
}

// 选择整个文档
function select2(){
    word.Selection.WholeStory;
}

// 时间太久,忘了
function select3(){
    word.Selection.TypeBackspace;
}

// 选择段落1的文本
function getContent(){
    console.log(word.ActiveDocument.Paragraphs(1).Range.Text);
}

6、获取文档相关属性

// 获取文档相关属性
function getPro(){
    alert(documents("test.doc").Path);//获取文档路径
    alert(documents("test.doc").Saved);//看文档是否保存
    //console.log(documents("test.doc").Application);
    /*
    Type'返回文档的类型(模板或文档)。只读 WdDocumentType 类型。
    Windows'返回一个 Windows 集合,该集合代表指定文档的所有窗口。只读。
    WordOpenXML'返回一个 String 类型的值,该值代表文档的 Word Open XML 内容的 Flat XML 格式。只读。
    Words'返回一个 Words 集合,该集合代表文档中的所有字词。只读。
    Tables'返回一个 Table 集合,该集合代表指定文档中的所有表格。只读。
    Scripts'返回一个 Scripts 集合,该集合代表指定对象中的 HTML 脚本的集合。
    Sections'返回一个 Section 集合,该集合代表指定文档中的节。只读。
    Sentences'返回一个 Sentences 集合,该集合代表文档中的所有句子。只读。
    Content'返回一个 Range 对象,该对象代表主文档文字部分。只读。
    Bookmarks'返回一个 Bookmarks 集合,该集合代表文档中的所有书签。只读。
    BuiltInDocumentProperties'返回一个 DocumentProperties 集合,该集合代表指定文档的所有内置的文档属性。
    Characters'返回一个 Characters 集合,该集合代表文档中的字符。只读。
    */

    //重复最后一次撤消的操作(Undo 方法的逆操作)。如果重复操作成功,则返回 True。
    //documents("test.doc").Redo;
    //Range通过使用指定的开始和结束字符位置返回一个 Range 对象。
    documents("test.doc").Range(1,5).Font.Size=20;
    //撤消最后一次操作或最后一系列操作,这些操作显示在“撤消”列表中。如果撤消操作成功,则返回 True。
    //documents("test.doc").Undo;
    //Select'选择指定文档的内容。
    //documents("test.doc").Select;
}

7、文档段落Paragraphs

Paragraph 对象'代表所选内容、范围或文档中的一个段落。Paragraph 对象是 Paragraphs 集合的一个成员。Paragraphs 集合包含所选内容、范围或文档中的所有段落。

//为指定段落设置 12 磅的段前间距。
function par1(){
    var paragraph = word.ActiveDocument.Paragraphs; // 获取所有段落
    paragraph(3).OpenUp;//操作某一段落
}

//清除指定段落前的任何间距。
function par2(){
    word.ActiveDocument.Paragraphs(3).CloseUp;
}

function par3(){
    //Border返回一个 Borders 集合,该集合代表指定段落的所有边框。
    //CharacterUnitFirstLineIndent'返回或设置首行或悬挂缩进的值(以字符为单位)。用正值设置首行缩进,用负值设置悬挂缩进。Single 类型,可读写。
    //CharacterUnitLeftIndent'该属性返回或设置指定段落的左缩进量(以字符为单位)。Single 类型,可读写。
    //Format返回或设置一个 ParagraphFormat 对象,该对象代表指定的一个或多个段落的格式。
    //RightIndent返回或设置指定段落的右缩进(以磅为单位)。可读写 Single 类型。
    //Shading返回一个 Shading 对象,该对象引用指定段落的底纹格式。
    //SpaceAfter返回或设置指定段落或文本栏后面的间距(以磅为单位)。可读/写 Single 类型。
    //SpaceAfterAuto如果 Microsoft Word 自动设置指定段落的段后间距,则该属性为 True。可读/写 Long 类型。
    //SpaceBefore返回或设置指定段落的段前间距(以磅为单位)。可读/写 Single 类型。
    //SpaceBeforeAuto如果 Microsoft Word 自动设置指定段落的段前间距,则该属性为 True。可读/写 Long 类型。
    //Style返回或设置指定对象的样式。可读写 Variant 类型。
    alert(word.ActiveDocument.Paragraphs(3).Border);//undefined
    alert(word.ActiveDocument.Paragraphs(3).SpaceBefore);
    alert("首行缩进"+word.ActiveDocument.Paragraphs(3).CharacterUnitFirstLineIndent);
    alert(word.ActiveDocument.Paragraphs(3).ParagraphFormat);//undefined
    alert("右缩进"+word.ActiveDocument.Paragraphs(3).RightIndent);//0
    alert(word.ActiveDocument.Paragraphs(3).Style);//正文
}

// 选择段落
function par4(){
    // 选中下一段
    word.ActiveDocument.Paragraphs(3).Next.Range.Select;
    // 选中上一段
    // word.ActiveDocument.Paragraphs(3).Previous.Range.Select;
}

// 设置和获取缩进
function par6(){
    //LeftIndent'返回或设置一个 Single 类型的值,该值代表指定段落的左缩进值(以磅为单位)。可读写。
    //LineSpacing'返回或设置指定段落的行距(以磅为单位)。Single 类型,可读写。
    word.ActiveDocument.Paragraphs(3).LeftIndent = 0;
    word.ActiveDocument.Paragraphs(3).LineSpacing = 5;
    alert(word.ActiveDocument.Paragraphs(3).LeftIndent);
    alert(word.ActiveDocument.Paragraphs(3).LineSpacing);
}

8、选择文档Selection

要引用活动的段落、表格、域或其他文档元素,可使用Selection属性返回一个Selection对象。 通过 Selection对象,可访问选定内容中的所有段落或某一段。

注意selection只有在有文档打开的时候才能获取。

function selection1(){
    //第一段加边框
    var selection = word.Selection;
    selection.Paragraphs(1).Borders.Enable = true;
}
function selection2(){
    //所有段落加边框,针对选中的段落,没选中段落时无效
    var selection = word.Selection;
    selection.Paragraphs.Borders.Enable = true;
}
function selection3(){
    var selection = word.Selection;
    //将底纹应用于选定内容中第一张表格的首行,如果选定的内容不包含表格,将导致出错。
    //可使用Count属性判定选定内容中是否包含表格
    if(selection.Tables.Count >= 1){
        selection.Tables(1).Rows(1).Shading.Texture = true;
        //For Each tblTable In Selection.Tables
        //tblTable.Rows(1).Shading.Texture = wdTexture30Percent
    }else{
        console.log("Selection doesn't include a table");
    }
}

9、连续区域RangeRange

对象引用文档中的某一连续区域。每个 Range对象都是通过开始和结束字符位置来定义的。类似于在文档中使用书签的方法,在 Visual Basic 过程中使用 Range对象可以定义文档中指定的部分。Range对象可以小至一个插入点,或大至包含整篇文档。但是与书签不同,Range对象只在定义该对象的过程运行时才存在。Start、End 和StoryType属性唯一地标识一个 Range对象。Start 和 End属性返回或设置 Range对象的开始和结束字符的位置。文档开始处的字符位置为 0,第一个字符后的位置为 1,以此类推。StoryType属性的 WdStoryType 常量可以代表 11 种不同的文字部分类型。 注意 Range对象与所选内容无关。也就是说,可以定义和修改某区域而不改变当前的所选内容。也可在文档中定义多个区域,而每个文档窗格中只有一处所选内容。

function range1(){
    //对活动文档中的前 10 个字符应用加粗格式
    var rngDoc = word.ActiveDocument.Range(0,10);
    rngDoc.Bold = true;
    //如果不需要缓存选区,可以直接word.ActiveDocument.Range(0,10).Bold = true;
}
function range2(){
    //创建一个 Range对象,该对象从第二段开头开始,至第三段末尾后结束。
    var doc = word.ActiveDocument;
    var rngDoc = doc.Range(doc.Paragraphs(2).Range.Start, doc.Paragraphs(3).Range.End);
    rngDoc.Font.Color = word.wdColorYellow;
    rngDoc.Font.Size = 12;
}

function range3(){
    //Range对象的开始和结束位置相同,则该区域不包含任何文字。
    //下列示例在活动文档的开头插入文字。
    var rngDoc = word.ActiveDocument.Range(0, 0);
    rngDoc.InsertBefore("Hello");
}
function range4(){
    //使用InsertAfter 或InsertBefore方法在Selection 或Range对象之前或之后插入文字
    word.ActiveDocument.Content.InsertAfter("The end.");
}
function range5(){
    var doc = word.ActiveDocument;
    //获取某一范围
    var rngDoc = doc.Paragraphs(2).Range;
    //用SetRange方法重新定义range的范围
    rngDoc.SetRange(rngDoc.Start, rngDoc.Start + 20);
    rngDoc.InsertAfter("【我是插入到第二段的第二十个字符之后的内容】");
}

//有多种对象具有 Range属性,例如Paragraph、Bookmark 和Cell,并且该属性用于返回 Range对象。
function range6(){
    //返回一个 Range对象,该对象引用活动文档中的第一个段落。
    var Paragraph = word.ActiveDocument.Paragraphs(1).Range;
    //选定活动文档中的第二个段落并将所选内容居中。
    word.ActiveDocument.Paragraphs(2).Range.Select;

    word.Selection.ParagraphFormat.Alignment = 0;//左
}
function range7(){
    word.Selection.ParagraphFormat.Alignment = 1;//中
}
function range8(){
    word.Selection.ParagraphFormat.Alignment = 2;//右
}

10、插入表格与修改表格

// 插入表格
function insertTable(){
    var docActive = word.ActiveDocument;
    var range = docActive.Paragraphs(3).Range;
    //range.InsertAfter("\n");
    //word.ActiveDocument.Tables.Add(range,3,4);//在第三段之前
    word.ActiveDocument.Tables.Add(docActive.Range(range.End,range.End),3,4);//在第三段之后
    //var tblNew = docActive.Tables.Add(docActive.Range(0, 0), 3,4);//在文档开始处
    //var myTable0=word.ActiveDocument.Tables.Add(word.Selection.Range,3,4);//在文档开始处
}

// 填充表格数据
function fillTable(){
    //获取第一个表格
    var myTable0=word.ActiveDocument.Tables(1);
    myTable0.cell(1,1).Range.Text="请假人";
    myTable0.cell(1,2).Range.Text="张三";
    myTable0.cell(1,3).Range.Text="请假时间";
    myTable0.cell(1,4).Range.Text="2006-2-10";

    myTable0.cell(2,1).Range.Text="工号";
    myTable0.cell(2,2).Range.Text="32412";
    myTable0.cell(2,3).Range.Text="填表时间";
    myTable0.cell(2,4).Range.Text="2006-2-9";

    myTable0.cell(3,1).Range.Text="请假原因";
    myTable0.cell(3,2).Range.Text="感冒";
    myTable0.cell(3,3).Range.Text="处理方式";
    myTable0.cell(3,4).Range.Text="病假";
}

// 填充表格数据
function fillTable2(){
    var myTable0=word.ActiveDocument.Tables(1),
        //获取表格的行和列
        row = myTable0.Rows.Count,
        col = myTable0.Columns.Count,
        q = 1;
    for(var i = 1;i<=row;i++){
        for(var j = 1;j<=col;j++){
            myTable0.cell(i,j).Range.InsertAfter(i+"="+j+"="+q);
            q++;
        }
    }
}

// 获取表格里的内容
function getTableContent(){
    var myTable0=word.ActiveDocument.Tables(1),
        row = myTable0.Rows.Count,
        col = myTable0.Columns.Count,arr = [];
    //alert(myTable0.cell(1,1).Range.Text);//这样得到的文本包含了表格的结束单元格标记
    for(var i = 1;i<=row;i++){
        for(var j = 1;j<=col;j++){
            var cell = myTable0.cell(i,j);
            //alert(word.ActiveDocument.Range(cell.Range.Start, cell.Range.End - 1));
            arr.push(word.ActiveDocument.Range(cell.Range.Start, cell.Range.End - 1).Text);
        }
    }
    alert(arr);
}

// 删除单元格内容
function deleteTableContent(){
    var myTable0=word.ActiveDocument.Tables(1);
    myTable0.cell(1,1).Range.Delete;
    /*
    //选定表格
    myTable0.Select;
    myTable0.Rows(i).Select;
    myTable0.Columns(i).Select;
    */
}

//清空表格内容
function clearTable(){
    var myTable0=word.ActiveDocument.Tables(1);
    myTable0.Range.Delete;
}

//删除表格
function deleteTable(){
    var myTable0=word.ActiveDocument.Tables(1);
    myTable0.Delete;
    //ActiveDocument.Tables(1).Delete;
}

// 表格文本对齐
function centerTable0(){
    var myTable0=word.ActiveDocument.Tables(1);
    myTable0.Range.Rows.Alignment = 0;//水平左对齐
    myTable0.Range.Rows.Alignment = 1;//水平居中对齐
    myTable0.Range.Rows.Alignment = 2;//水平右对齐
    // 各个参数的意义不知道有没有记错,大家可以自行测试一下
}

// 设置表格宽度
function setWidthTable(){
    var myTable0=word.ActiveDocument.Tables(1);
    myTable0.PreferredWidth = 300;//
    //myTable0.Range.Rows.Add;
    //myTable0.Range.Columns.Add;
    //ActiveDocument.Rows(1).Cells(10).Width = 31
    //ActiveDocument.Rows(2).Cells(10).Width = 31
    //ActiveDocument.Rows(3).Cells(10).Width = 31
}

/*
myTable0.Columns(i + 1).PreferredWidthType = wdPreferredWidthPercent;
myTable0.Columns(i + 1).PreferredWidth = 30;
Columns的PreferredWidthType属性设置表格列宽的形式,这里选择的是百分比列宽,
可以根据自己的实际情况选择其他列宽形式,然后再设置相应的数值。
*/

11、一些其他的操作

Visual Basic 包含一些对象,可用这些对象修改下列文档元素:字符、单词、句子、段落和节。下面列出与这些文档元素相对应的属性和这些属性返回的对象。

表达式 返回的对象
Words(index) Range
Characters(index) Range
Sentences(index) Range
Paragraphs(index) Range
Sections(index) Range

如果使用这些属性时不带索引序号,则返回一个具有相同名称的集合对象。例如,Paragraphs属性返回Paragraphs集合对象。但是如果通过索引序号识别集合中的一项,则返回上表中第二列中的对象。例如,Words(1) 返回一个 Range对象。有了一个 Range对象之后,可以使用任何区域属性或方法修改该Range对象。

例如,下列指令将所选内容的第一个单词复制到“剪贴板”。

Selection.Words(1).Copy

例如,下列指令将活动文档的第一段复制到“剪贴板”。

ActiveDocument.Paragraphs(1).Range.Copy

上述表格中的所有文档元素属性对 Document、Selection 和 Range对象都可用。

下列示例阐明了如何使用Document、Selection 和 Range对象的这些属性。

function update1(){
    //创建一个引用活动文档中前三个单词的 Range对象 (myRange)。
    var docActive = word.ActiveDocument;
    var rngThreeWords = docActive.Range(docActive.Words(1).Start,docActive.Words(3).End);
    rngThreeWords.Font.Size = 5;
    rngThreeWords.Font.Color = 255;
}

//设置活动文档中第一个单词的大小写。
function update2(){
    word.ActiveDocument.Words(1).Case = 0;//全小写
    word.ActiveDocument.Words(1).Case = 1;//1全大写
    word.ActiveDocument.Words(1).Case = 2;//首字母大写
}

function update3(){
    //将当前节的下边距设为 0.5 英寸。
    word.Selection.Sections(1).PageSetup.BottomMargin = word.InchesToPoints(0.5);
}

function update4(){
    //将活动文档的字符间距设为两倍(Content属性返回一个 Range对象)。
    word.ActiveDocument.Content.ParagraphFormat.Space2;
}

function ShowFirstWord(){
    var strFirstWord = word.ActiveDocument.Words(1).Text;
    console.log(strFirstWord);
}

好了,本文到此结束。这本是两年前我记录在个人博客里的笔记,原文地址,目前在个人博客的阅读量有18k之多,想着可能有更多的人会需要,故今天重新整理了一下,分享到掘金,希望能帮到更多的人吧,只要多一个人阅读,我觉得这件事就是值得的。如有道友发现错误,欢迎指正。