【说明】此文中在页眉插入跳转到目录项的超链接的代码几经改进,但改进后并未删除改进之前的代码,是为了有个对比利于学习。如果想节约时间,该步骤可直接查看该部分最后一个代码块。
对于Word长文档,标准做法是按文章结构为不同段落指定不同大纲级别的样式,方便插入目录并在文档中灵活跳转到所需内容。这样的文档在Word中编辑或查阅固然方便跳转,但是一旦转换为pdf文档,阅读时跳转就不方便了,需要不停地滚动页面。
在文档中插入自动目录,转换为pdf文件后可以方便从目录跳转到相应内容处,但要想返回目录就只能靠手工翻页或者先为pdf文件创建书签目录。如果在编辑Word文档时事先就建立标题段落到目录项的链接,并在每页的页眉也插入超链接,链接到本页所属标题段落对应的目录项,那么转换为pdf文件后在任意页面都可以很方便地返回对应的目录区域。
如下图中的文档自动生成的目录:

点击其中的目录项“一、域应用基础”,可以很方便地跳到对应的大纲级别为1、样式名称为“标题 1”的段落所在位置,如下图:

但是点击图中的“标题 1”段落“一、域应用基础”,无法返回目录中相应的目录项。此外,如果在这一小节中阅读几页后,就无法直观地看出当前页面属于哪一节的内容(可以通过在页眉中插入styleref域实现这个功能,但styleref域无法实现超链接功能),当然也无法通过点击文档中的内容跳回目录。再看下面这个页面:

从页面右上角可以很清楚地看到当前内容属于“二、域速查一览”这一节,如果想跳转到其他章节,也可以方便地点击页眉中的超链接回到目录,再从目录中跳转到其他章节。完成上图中的效果需要文档符合以下要求:
1、每个章节的标题指定了“标题 1”样式,且文档中不存在样式为“标题 1”的空行;
2、在每个章节的标题前插入了分页型分节符。
如果文档符合上述要求,通过以下四个步骤即可实现上图中的效果:
1、在文档中插入自动目录,此步骤可通过引用面板上的目录工具完成。
2、在自动目录的目录项处插入书签。
3、在各节标题处插入跳转到到对应目录项的超链接。
4、在各节页眉处插入跳转到到对应目录项的超链接。
以下介绍使用VBA完成第2、3、4步的方法。三个步骤可以在一个宏里完成,但是文档如果很长,执行时间可能也很长,易出问题,而且很难做到以最高效率完成每一个步骤,因此用三个宏分步执行。

在自动目录的目录项处插入书签

下面的VBA代码完成在自动目录的目录项处插入书签的功能(仅在一级目录处插入书签),原理参见代码注释:

Sub 为自动生成的目录中的目录项创建书签()Dim aPara As Paragraph, i As IntegerOn Error Resume Next' 选择目录ActiveDocument.TablesOfContents(1).Range.Select' 变量i用于为目录定义的书签名编序号i = 1' 遍历目录项,为一级标题目录项创建书签For Each aPara In Selection.ParagraphsIf aPara.Style = "TOC 1" And Len(aPara.Range.Text) > 1 Then' 为一级标题建立书签,命名方式为“con_”加上序号With ActiveDocument.Bookmarks.DefaultSorting = wdPosition.Add Range:=aPara.Range, _name:="con_" & iEnd Withi = i + 1End IfNext
End Sub

从各章节标题跳回目录

下面的VBA代码在各章节的标题处插入跳转到上一个宏生成的书签的超链接,从而提供从各章节标题跳回目录的功能:

Sub 创建标题段落到目录项的链接()
'
' 自动生成的目录只能从目录项链接到标题段落
' 此宏通过为一级目录创建书签,再在一级目录
' 对应的标题段落处插入到相应书签的链接,从
' 而建立标题段落与相应目录项的链接。
'Dim aPara As Paragraph, i As IntegerOn Error Resume Nexti = 1' 在每一个样式为“标题 1”的段落插入超链接,目标为相应书签。' 注意在遍历文档段落时分节符也算一个段落,所以要排除空白段落(文本长度为1的段落)For Each aPara In ActiveDocument.ParagraphsIf aPara.Style = "标题 1" And Len(aPara.Range.Text) > 1 ThenActiveDocument.Hyperlinks.Add Anchor:=aPara.Range, Address:="", _SubAddress:="con_" & ii = i + 1End IfNext
End Sub

再补充一种效率更高的方式。上面的代码是遍历文档中所有段落,下面的代码直接在文档的标题段落中跳转,省去了对正文段落的判断:

Sub 创建标题段落到目录项的链接v2()Dim i As Integer, title As String' 变量title用于保存标题文本,初始值用一个不是文档标题的字符串即可,空字符串也行title = ""' 变量i用于计算书签编号i = 1' 禁止屏幕更新,避免光标跳转时屏幕滚动影响效率Application.ScreenUpdating = FalseWith Selection' 光标回到文档开头.HomeKey unit:=wdStoryDo' 光标移动到下一个标题段落处.GoTo what:=wdGoToHeading, which:=wdGoToNext' 选择该标题段落全部内容.MoveDown unit:=wdParagraph, Extend:=wdExtend' 标题段落样式为“标题 1”且不是空白段落(排除分节符段落)则插入超链接If .Paragraphs(1).Style = "标题 1" And Len(.Range.Text) > 1 Then' 插入超链接ActiveDocument.Hyperlinks.Add Anchor:=.Range, Address:="", _SubAddress:="con_" & ii = i + 1End If' 标题段落文本不发生变化时认定处理完成,退出循环' 这种判别方法只适用于不存在两个连续标题段落文本相同的情况If title = .Range.Text ThenExit DoElse' 保存标题段落文本title = .Range.TextEnd If' 以下比较当前光标所在节的编号与总节数,如果相等推定操作完成,退出循环' 这样判断只适用于最后一节只有一个非空白“标题 1”段落的情况,可省去取存标题文本的操作,效率更高。' 如果最后一节有多个非空白“标题 1”段落,则只有第一个段落会被处理,后续段落会被遗漏' If Selection.Information(wdActiveEndSectionNumber) = activedocument.Sections.Count Then'     Exit Do' End IfLoopEnd With' 恢复屏幕更新Application.ScreenUpdating = True
End Sub

在每页页眉中插入到目录项的超链接

以下是在页眉中插入跳转到相应一级目录项的超链接的代码,同样有详尽注释:

Sub 页眉中插入到相应一级目录项的链接()
'
' 此宏在Word文档中每页页眉插入返回文档目录中相应位置的超链接
' 超链接显示的文本为当前页面所属章节的标题
' 此宏顺利执行的前提:
'      1、每个章节的标题指定了“标题 1”样式
'      2、在每个章节的标题前插入了分节符
'      3、文档中插入了自动目录,运行本文第一个宏为每个一级标题目录项生成了
'   形如“con_”加数字序号的书签。
'Dim disText As String, secCount, i As Integeri = 1' 禁止屏幕滚动以提高效率,执行文档内容插入与修改一般应当这样做Application.ScreenUpdating = False' 将页面视图激活区域指定为主文档ActiveWindow.ActivePane.View.SeekView = wdSeekMainDocument' 取得文档分节总数secCount = ActiveDocument.Sections.Count' 光标移至文档开头Selection.HomeKey unit:=wdStoryDo' 将光标移动到下一个大纲级别为1的段落While Selection.Paragraphs(1).OutlineLevel > 1' 将光标移动到下一个标题段落,直至大纲级别为1停止循环Selection.GoTo what:=wdGoToHeading, which:=wdGoToNext, Count:=1Wend' 取得段落的文本,前面加上tab键,并去掉结尾的回车符disText = Selection.Paragraphs(1).Range.TextdisText = vbTab & Left(disText, Len(disText) - 1)' 将页面视图激活区域指定为页眉,完成页眉编辑后恢复为主文档With ActiveWindow.ActivePane.View.SeekView = wdSeekCurrentPageHeader' 取消将页眉链接到上一节,各节独立设置页眉Selection.HeaderFooter.LinkToPrevious = False' 插入超链接ActiveDocument.Hyperlinks.Add Anchor:=Selection.Range, Address:="", _SubAddress:="con_" & i, ScreenTip:="", TextToDisplay:=disTexti = i + 1.SeekView = wdSeekMainDocumentEnd With' 当前光标所在节的编号与总节数相等,意味着已操作完最后一节,退出循环If Selection.Information(wdActiveEndSectionNumber) = secCount ThenExit DoEnd If' 光标移动到下一节Selection.GoTo what:=wdGoToSection, which:=wdGoToNext, Count:=1Loop' 恢复屏幕更新Application.ScreenUpdating = TrueEnd Sub

下面是采用Selection.Move方法实现在每页页眉中插入到目录项的超链接:

Sub 页眉中插入到相应一级目录项的链接()
'
' 此宏在Word文档中每页页眉插入返回文档目录中相应位置的超链接
' 超链接显示的文本为当前页面所属章节的标题
' 此宏顺利执行的前提:
'      1、每个章节的标题制定了“标题 1”样式
'      2、在每个章节的标题前插入了分节符
'      3、文档中插入了自动目录,运行本文第一个宏为每个一级标题目录项生成了
'   形如“con_”加数字序号的书签。
'Dim disText As String, i As Integer, aPara As Paragraphi = 1' 禁止屏幕滚动以提高效率,执行文档内容插入与修改一般应当这样做Application.ScreenUpdating = False' 将页面视图激活区域指定为主文档ActiveWindow.ActivePane.View.SeekView = wdSeekMainDocumentWith Selection' 光标移动至文档开头.HomeKey unit:=wdStory    Do' 将光标向前移动一个段落,并记录移动数量moved = .Move(unit:=wdParagraph, Count:=1)' selection.move方法返回0表示无法再向前移动,文档已处理完成,退出循环If moved < 1 ThenExit DoEnd IfdisText = .Paragraphs(1).Range.Text' 判断光标所在段落的样式名称及是不是空行If .Paragraphs(1).Style = "标题 1" And Len(disText) > 1 ThenWith ActiveWindow.ActivePane.View.SeekView = wdSeekCurrentPageHeader' 取消将页眉链接到上一节,各节独立设置页眉Selection.HeaderFooter.LinkToPrevious = False' 删除链接前一节页眉生成的页眉Selection.Paragraphs(1).Range.Delete' 插入超链接ActiveDocument.Hyperlinks.Add Anchor:=Selection.Range, Address:="", _SubAddress:="con_" & i, ScreenTip:="", TextToDisplay:=vbTab & Left(disText, Len(disText) - 1)i = i + 1.SeekView = wdSeekMainDocumentEnd WithEnd IfLoopEnd With    ' 恢复屏幕更新Application.ScreenUpdating = True
End Sub

上面的代码每次向下移动一个段落,因此效率较低。如果直接将光标移动到下一节,毫无疑问可以提高效率。但是Selection.Move方法不能使用wdSection为参数unit赋值,只有Selection.GoTo方法才可以通过为what参数赋值为wdSection在节之间移动光标。然而,与Selection.Move方法返回移动数量不同的是,Selection.GoTo方法返回一个Range,如何判断已经全部处理完并退出循环是个问题。经测试发现,在移动到最后一节后,Selection.GoTo what:=wdGoToSection, which:=wdGoToNext语句将使光标一直停留在最后一节开头,因此,可以先将各节标题文本保存起来,如果执行Selection.GoTo what:=wdGoToSection, which:=wdGoToNext语句后,标题文本与事先保存的标题文本相同,就可以推定已经处理完毕(如果文档中有相邻两节的标题完全一样且并非最后两节,这个推定就是错的。希望你手上的文档没有这么奇葩。如果真碰上了这么奇葩的文档,那就用本步骤中第一个代码块的方式,每次循环中处理完一节的页眉后,判断一下当前光标所在节编号是不是与总节数相等来决定是否结束循环吧),从而终止循环。以下是效率较高的做法:

Sub 页眉中插入到相应一级目录项的链接()
'
' 此宏在Word文档中每页页眉插入返回文档目录中相应位置的超链接
' 超链接显示的文本为当前页面所属章节的标题
' 此宏顺利执行的前提:
'      1、每个章节的标题制定了“标题 1”样式
'      2、在每个章节的标题前插入了分节符
'      3、文档中插入了自动目录,运行本文第一个宏为每个一级标题目录项生成了
'   形如“con_”加数字序号的书签。
'Dim disText As String, i As Integer, aPara As Paragraph' 变量i用于计算书签中的数字序号i = 1' 变量disText用于记录章节标题文本内容disText = ""' 禁止屏幕滚动以提高效率,执行文档内容插入与修改一般应当这样做Application.ScreenUpdating = False' 将页面视图激活区域指定为主文档ActiveWindow.ActivePane.View.SeekView = wdSeekMainDocumentWith Selection' 光标移动至文档开头.HomeKey unit:=wdStoryDo' 光标跳到下一节开头.GoTo what:=wdGoToSection, which:=wdGoToNext' 选择下一节开头的标题段落.MoveDown unit:=wdParagraph, Extend:=wdExtend' 判断光标所在段落的样式名称及是不是空行If .Paragraphs(1).Style = "标题 1" And Len(.Range.Text) > 1 Then' 如果选择的文本与此前保存的标题段落文本相同,可以推定' 在原地跳转,也就是说已处理完毕,终止循环。否则保存标' 题段落文本If disText = .Range.Text ThenExit DoElsedisText = .Range.TextEnd IfWith ActiveWindow.ActivePane.View' 激活当前页页眉进行页眉编辑.SeekView = wdSeekCurrentPageHeader' 取消将页眉链接到上一节,各节独立设置页眉Selection.HeaderFooter.LinkToPrevious = False' 删除链接前一节页眉生成的页眉Selection.Paragraphs(1).Range.Delete' 插入超链接,加上了tab键便于页眉的对齐处理,去掉了段尾回车ActiveDocument.Hyperlinks.Add Anchor:=Selection.Range, Address:="", _SubAddress:="con_" & i, ScreenTip:="", _TextToDisplay:=vbTab & Left(disText, Len(disText) - 1)i = i + 1' 激活主文档视图以便将光标跳转到下一节开头.SeekView = wdSeekMainDocumentEnd WithEnd IfLoopEnd With' 恢复屏幕更新Application.ScreenUpdating = True
End Sub

以下是在页眉中插入链接到目录项的超链接最简单且最不会出错的方法,还进一步对页眉进行了处理:

Sub 页眉中插入到相应目录项的链接()Dim aSec As Section, i As Integer, styleName As String, leadingTxt As StringstyleName = "标题 1"leadingTxt = "金卡斯·博尔巴"Application.ScreenUpdating = False' 书签编号i = 1On Error Resume Next' 遍历所有节For Each aSec In ActiveDocument.Sections' 这里只在每节第一行为非空白的标题1段落小节的页眉插入链接If aSec.Range.Paragraphs(1).Style = styleName And _Len(aSec.Range.Paragraphs(1).Range.Text) > 1 Then' 取消链接到上一节页眉aSec.Headers(wdHeaderFooterPrimary).LinkToPrevious = False' 选择当前节页眉区域aSec.Headers(wdHeaderFooterPrimary).Range.SelectWith Selection' 键入前导文字、tab键,添加引用标题内容的域.TypeText Text:=leadingTxt & vbTab.Fields.Add Range:=Selection.Range, Type:=wdFieldEmpty, Text:= _"STYLEREF  """ & styleName & """", PreserveFormatting:=True' 再次重新选择页眉,设置字体大小,插入超链接,重新设置制表位位置.Paragraphs(1).Range.Select' 插入超链接ActiveDocument.Hyperlinks.Add Anchor:=.Range, Address:="", _SubAddress:="con_" & i, ScreenTip:="".Font.Size = 10 ' 字体大小为五号.ParagraphFormat.TabStops.ClearAll ' 清除默认的制表位' 设置右对齐制表位,A4纸左右页边距2.5cm时设置在16cm处靠近页面右边距位置.ParagraphFormat.TabStops.Add Position:=CentimetersToPoints(16 _), Alignment:=wdAlignTabRight, Leader:=wdTabLeaderSpacesEnd With' 调整节编号i = i + 1End IfNextApplication.ScreenUpdating = True' 恢复视图为页面视图If ActiveWindow.View.SplitSpecial <> wdPaneNone ThenActiveWindow.Panes(2).CloseEnd IfActiveWindow.ActivePane.View.Type = wdPrintView
End Sub

用VBA在Word文档中每页页眉插入返回文档目录中相应位置的超链接相关推荐

  1. Maven在pom文件中添加资源插件后,src/main/resource目录中的文件编译后不拷贝解决方法。

    在pom文件中添加以下资源插件后 <!--添加的资源插件--> <build><resources><resource><directory> ...

  2. DataGrid中,读取数据库中的图片并绑定数据列或磁盘目录中的图片,用输出流方式...

    显示效果如下 SID 图片显示 180 181 182 183 184 1 图片显示页面Html:DataGridShowPicture.aspx <%@ Page language=" ...

  3. H5中 JS 禁用安卓手机物理返回键 , 微信浏览器中也支持

    XBack = {};       (function(XBack) {         XBack.STATE = 'x - back';         XBack.element;        ...

  4. c# mysql 插入返回id_在C#中,mysql插入一条数据时,怎么同时把这条数据的主键返回?...

    展开全部 可以尝试使用  last_insert_id()  来获取一下看看. 下面是 仅仅在 mysql 下面的测试例子: mysql> CREATE TABLE test_create_ta ...

  5. 简单的可视化批量插入pdf页面(将另一份含n页的pdf插入到当前的pdf中的第m页之后)(使用pdf-xchange editor或迅捷pdf/acorbat)

    同时打开被插入pdf和待插入pdf 这里打开matlab 和第3章 编程 打开预览窗口,Ctrl+A(或选定指定的页面) Ctrl+C复制 转到被插入的matlab文件的页面预览窗口,点击第m(由自己 ...

  6. 如何在Microsoft Word中插入PDF文档?

    文章来源:https://www.reneelab.com.cn/how-to-insert-pdf-into-word.html 目录 一.在Windows上将PDF插入到Word文档的方法 方法一 ...

  7. javascript在第三个文本框中显示文字_一段中的个别文字,显示在目录中

    样例 说明 通常,目录中显示的文字是应用了标题样式的整段文字,而不是段落中的个别文字但有时,需要让个别文字,或者正文中根本不存在的文字,显示在目录中.要求:目录中只显示段落开头的摘要二字简述 设置 步 ...

  8. go get 的不再src目录中_如何正确的开始用Go编程

    本文会演示简单的Go软件包的开发过程,并介绍了 go命令行工具,这是我们获取,构建和安装Go软件包和命令的标准方法. go工具要求你以特定方式组织代码.我们会介绍Go安装启动和运行的最简单方法,一定要 ...

  9. python函数isdisjoint方法_Python学习之---Python中的内置函数(方法)(更新中。。。)...

    add(item)#将item添加到s中,如果item已经在s中,则无任何效果 break#退出循环,不会再运行循环中余下的代码 bool()#将参数转换为布尔型 bytes()#将值转成bytes类 ...

最新文章

  1. C++动态链接库dll及静态链接库lib制作及使用教程
  2. TCP/IP总结(4)TCP 概述
  3. 搭量化数据库——互联网金融之三
  4. 「GIT SourceTree冲突」解决方案
  5. 【转】Spring Bean单例与线程安全
  6. codeforces1471 D. Strange Definition
  7. Codeforces Round #654 (Div. 2)
  8. 工业以太网交换机选机攻略
  9. [CareerCup][Google Interview] 找出最小排序次数
  10. AI给植物看病,宾大用TensorFlow做的这款应用造福坦桑尼亚农民
  11. linux运维命令3
  12. (2015省赛系列--团体热身赛第二场)
  13. gif透明背景动画_汉服美女表情包(PS做GIF动图简易教程分享)
  14. Programming Ruby读书笔记
  15. java调用腾讯地图根据经纬度获取位置信息
  16. 详解C盘Windows文件夹里重要文件作用
  17. 结对第一次—原型设计(文献摘要热词统计)
  18. 商品规格sku算法应用
  19. MATLAB学习笔记5:绘图基础与数据可视化(中)
  20. WordPress常见问题及其解决方法

热门文章

  1. pip安装pytorch和torchvision
  2. PS部分实现helloworld
  3. 加拿大11年级计算机课程代码,加拿大读11年级,我经历的选课、学英语、拿高分...
  4. 2020-12-03_EditPlus下载安装注册
  5. VSP编译工具链安装
  6. Linux下使用ps命令查看某个进程文件的启动位置
  7. 获取不到摄像头名称???
  8. linux安装自动化部署工具jenkins
  9. springboot配置拦截器,在拦截器中获取@RequestBody注解参数和post请求参数以及get请求参数
  10. win10虚拟机创建