LaTeX教程(012)- LaTeX \LaTeX LATEX文档结构(12)
2.3.2 titletoc
包-设计目录列表的高级接口
titletoc
包(作者Javier Bezos)最初是作为一个和titlesec
包结合使用的包而开发的,但是它也可以单独使用。该包调用它自己的接口来排版目录的结构,这样就避免了原生
LaTeX
\LaTeX
LATEX对这一工作的限制。在开发一个新的文档类时,对这类列表的调整就是必要的了,此时titletoc
包就是一个很好的选择。
为单个级别的目录条目设计布局
一个目录条目通常由一个标头(通常只有一个标题编号,也可以设置一些额外预定义文本,如第X章),一行或多行标题文本,一串引导线,以及一个页码组成。常规的排版是使所有条目的页码靠右对齐,因此,通常从标题到页码之间会有一段距离,往往使用空白、一条直线或一串圆点来填补这一段距离。
标准 LaTeX \LaTeX LATEX的目录中,标题文本所有行的左右两端都有缩进,分别用来放置标头和页码,标头设置为左对齐的无衬线字体,而页码由一串实心圆点或者一条直线(我们将这它们称为引导线,引导线负责连接标题文本与页码)将其标题文本块分离。一个典型的多行标题如下图所示:
标准布局
titletoc
包支持上述类型的标准布局,并且相较于标准
LaTeX
\LaTeX
LATEX,还提供了更方便的定制方式。此外,它还支持其它布局,例如将低级标题一起放置在单个段落中,或者定制一个局部的目录列表。而对于上面展示的常规情形,该包提供了一个\dottedcontents
命令,它的形式如下:
\dottedcontents{type}[left-indent]{before-code}{label-width}{leader-width}
- 第一个参数
type
指我们为之设计样式的条目的类型,它可以是划分命令的名称(不带前面的反斜线),如section
、chapter
等。也可以是浮动体的环境名称,如figure
或table
。 left-indent
: 从页面的左边距到标题文本的距离。它应当比label-width
更大,因为label-width
是内嵌在left-indent
中的。尽管在语法上它是一个可选参数,但在实际应用中,它总是必要的,这一点要切记。before-code
: 我们已经见过很多命令中的before-code
参数了,它们的作用基本相同。这里主要放置影响条目的前置代码,如使用\addvspace
添加一段垂直距离,或者放置一些可以影响整个条目样式的代码,如字体声明代码等。这里也可以使用\filleft
、\filright
、\filcenter
、或者\fillast
(我们在讲titlesec
包时讲过的命令)设置条目的对齐方式。label-width
: 标签(就是条目的标题编号,下文中的标签均指条目中的标题编号)的名义宽度,也就是标签左侧到第一行标题文本左侧之间的距离。它也应当足够大,以容纳同级别的最长标签。否则可能会有标签与标题文本重合。leaders-width
,引导线的两个最小单元之间的距离,在上述例子中,就是两个圆点之间的距离。
例如,我们用\dottedcontents
命令排版上述条目:
\dottedcontents{section}[40pt]{\normalfont\sffamily\filright}{24pt}{6pt}
这行代码表示,它所设置的是\section
条目的样式。从左边距到标题文本之间的距离是40pt
,标签也在这段距离内,它从左边距向右16pt
(40-24)处开始,占据水平空间不超过24pt
,也就是说,从标签最左侧到标题文本的距离是24pt
。整个条目靠左对齐(因为使用了\filright
),而\normalfont\sffamily
是字体与字号声明。最后,每个圆点占据6pt
的间距。
我们用一个例子演示一下:
\documentclass{book}
\usepackage[a5paper]{geometry}
\usepackage{titletoc} % 使用titletoc包
\begin{document}
\tableofcontents
\dottedcontents{section}[40pt]{\normalfont\sffamily\filright}{24pt}{6pt}
% 定制section条目
\chapter{This is a chapter}
\section{This is a section}
\section{This is a sample section entry which has been deliberately made very long so that it spans three lines to exhibit the handling of the first and the last line in the entry}
\end{document}
编译(只截取目录部分):
试着调整一下其中的几个参数,比如将left-indent
改成10pt
,将label-width
改成8pt
,将leaders-width
改成24pt
,再次编译:
可以看到左边的缩进变小了,标签的空间也变小了,以至于与标题文本重合了一部分,另外,每两个圆点之间的距离变大了。
你可能想知道,条目中标题文本的右侧缩进是多少,以及它为什么没有作为\dottedcontents
的一个参数而受到控制。主要原因是在所有的设计中,所有条目都有相同的右侧缩进,因此在条目级别提供它可能会很繁琐且容易出错。在大多数文档类中,默认值都是足够大的,它足以容纳3位数字的页码(按当前文档的正文字体)。如果不够用(或者太大了),可以使用\contentsmargin
命令全局地改变它,该命令的形式如下:
\contentsmargin[correction]{right-sep}
该声明的right-sep
参数指定了所有条目的右侧缩进,也就是放置页码的空间。它应该足够大,否则页码可能会和条目中的标题文本重合。另外,如果我们使用了correction
参数,在条目中的标题文本设置了对齐方式的时候,该参数会对标题文本除最后一行的所有行再次进行缩进。我们用一个例子演示:
\documentclass{book}
\usepackage[a5paper]{geometry}
\usepackage{titletoc}
\begin{document}
% 将标题文本设置为两端对齐
\dottedcontents{section}[40pt]{\normalfont\sffamily\fillast}{24pt}{6pt}
% 将右侧缩进设置为40pt,这行命令要放在\tableofcontents前面
\contentsmargin{40pt}
\tableofcontents
\chapter{This is a chapter}
\section{This is a section}
\section{This is a sample section entry which has been deliberately made very long so that it spans three lines to exhibit the handling of the first and the last line in the entry}
\end{document}
编译:
可以看到,右侧用来容纳页码的缩进距离变大了(40pt),并且引导线也和前面的标题文本保持对齐了。我们加上correction
参数,将上面的代码\contentsmargin{40pt}
改为\contentsmargin[20pt]{40pt}
,编译:
看到除了最后一行的所有行都又缩进了20pt
。
这个设置是全局的,在极少数情况下,你可能会需要为不同级别的条目设置不同的右侧缩进,那么你必须将\contentsmargin
命令放置在\dottedcontents
命令或者\titlecontents
命令(接下来要讲的)的before-code
参数中,使它仅对当前设置的条目有效。
我们用一张示意图展示一下\dottedcontents
以及\contentsmargin
两个命令的参数的作用位置:
结构更复杂的布局
大多数情况下\dottedcontents
就够用了,但它有着明显的局限,例如,如果你不想要任何引导线,或者你需要的不仅仅是对字体和缩进做出调整时,使用它就不行了。应对这类情形,titletoc
包提供了一个\titlecontents
命令以及一些辅助命令用在它的参数中。该命令的形式如下:
\titlecontents{type}[left-indent]{before-code}{numbered-entry-format}{numberless-entry-format}{page-format}[below-code]
这个命令中,参数type
、left-indent
和before-code
的作用和意义均与\dottedcontents
的参数相同。不同的是\titlecontents
命令不再简单地指定标签宽度,而是有两个参数允许我们设置标签和标题文本的样式,并且指定标签(也就是编号)为空的情形。这意味着你的设计有更多的可能性,但代价是你需要指定更多的代码。
numbered-entry-format
: 用来设置编号和标题文本样式的代码。它是在水平模式下运行的。如果我们想要该条目有编号,那么必须将编号放置在该参数中。当前条目的编号储存在命令\thecontentslabel
中,也有其它命令可以替代,我们下面会说到。该参数的最后可以放置一个带有一个参数的命令,它会接收标题文本作为该命令的参数。numberless-entry-format
: 用来设置不带编号的条目的标题文本样式的代码。它的最后也可以放置一个带有一参数的命令。也就是说,一个条目如果没有声明\numberline{text}
(空的编号也不行,只有不使用这个命令,才会被认为是没有编号的),它就会执行该参数能的代码,如果有编号,则执行numbered-entry-format
参数中的命令。
这里要注意,如果你使用带星号的划分命令,如\section*
,那么在目录中是不会生成条目的。但是我们在上一讲(011篇)中说到了手动插入目录条目的方法,如:
\addcontentsline{toc}{section}{\protect\numberline{text}Foreword}
这样使我们可以插入带有编号的条目,如果将\numberline{text}
去掉,就可以插入一个没有编号的条目了。
page-format
: 对于引导线,不再指定leader-width
了,而是用一个参数精确地定义标题文本后面在执行的代码。因此我们要手动将引导线以及页码的格式化输入包含在这些代码中。引导线可以是一些圆点,也可以是一条线,比如你可以使用\titlerule
命令填充引导线(009篇讲过)。而存储当前条目的页码的命令是\thecontentspage
。该参数依旧在水平模式下运行。below-code
: 可选参数,在垂直模式下运行,通常放置一些在条目的最后(下方)执行的代码。比如,可以放置一段垂直空间,来增大该条目与下方内容的垂直距离。
我们用一个例子演示一下:
\documentclass{book}
\usepackage[a5paper]{geometry}
\usepackage{titletoc}
\begin{document}
\titlecontents{section}[15pt]{\addvspace{2pt}\filright}% 条目靠左对齐
{\contentspush{\thecontentslabel\enspace }}% 对与带编号的条目,输出标题
{\LaTeX{}\ \MakeUppercase}% 对于不带编号的条目,将所有字母变成大写,并且在前面加一个LaTeX标志
{~\hrulefill\hspace{0.5cm}\thecontentspage}%引导线用一条直线填充
\tableofcontents
\chapter{This is a chapter}
\section{This is a section}
\section*{Foreword}
% 插入一个不带编号的条目
\addcontentsline{toc}{section}{\protect{}Foreword}
\section{This is a sample section entry which has been deliberately made very long so that it spans three lines to exhibit the handling of the first and the last line in the entry}
\end{document}
编译:
有几个不认识的命令,我们下面会讲。
观察前面的文档,可以发现其他的都如我们所愿,只是设置过的页码没有和默认情形下的页码对齐。此时我们就需要介绍另外两个命令,\contentslabel
和\contentspage
,可以将它们分别看作是\thecontentslabel
和\thecontentspage
的升级版。它们的形式分别是:
\contentslabel[text]{size}
\contentspage[text]
\contentslabel
用来代替\thecontentslabel
生成条目的标签(编号),不同的是,它会首先生成一个宽度为size
的盒子,该盒子在标题文本的左侧,并且紧靠着标题文本放置。text
是一个可选参数,它用来放置条目的标签。标签会在盒子中靠左放置。如果我们忽略可选参数,那么标签默认就是\thecontentslabel
,也就是当前条目的编号。如果我们放置了内容,那么条目的标签就是我们放置的内容。注意这里的设置的全局的,我就是说,如果我用\titlecontents
命令设置的条目类型是section
,并且在numbered-entry-format
参数中使用了\contentslabel[abc]{25pt}
命令,那么所有的section
条目的标签都会变成abc
,abc
会出现在标题文本前方25pt
处。可以看出,这里的size
的参数的作用,和\dottedcontents
命令的label-width
参数作用是一样的,因此要注意,left-indent
要留出足够的空间,至少要大于size
。
text
参数的正确的使用方法并不是将所有条目的标签变得一样,实际上,我们可以手动将\thecontentslabel
放置在参数text
中,并且可以根据自己的喜好为其设置样式。例如,将\bf\thecontentslabel
放置其中,就可以得到加粗显示的编号。
\contentspage
和\contentslabel
类似,首先会生成一个在标题文本的最后一行,并且靠右边距放置的盒子。text
同样是一个可选参数,它用来放置条目的页码。页码会在盒子中靠右放置。如果我们忽略可选参数,页码就默认是\thecontentspage
,也就是当前条目的页码。这个盒子实际上是放置在了我们为页码保留的右侧缩进中,而这个盒子也不需要我们为其设置宽度(size
),它和右侧缩进的大小相同,这个距离是全局的,所有条目都相同,而我们可以使用\contentsmargin[correction]{right-sep}
全局地改变它,正如上文中讲的那样。
titletoc
包提供了3个包选项,用来影响\contentslabel
的使用结果,如果我们使用了这个命令,并且没有使用text
参数,那么使用包选项rightlabels
就可以使\contentslabel
指定的条目的编号在盒子中靠右放置,而leftlabels
选项可以使其靠左(默认也是靠左的)。还有一个全局选项dotinlabels
,指定了该包选项之后,使所有条目的编号后面加上一个圆点,注意一点对所有条目有效,包括没有用\titlecontents
设置过的条目。
我们将上面的例子中的\thecontentslabel
和\thecontentspage
分别替换成\contentslabel
和\contentspage
,再次演示一下:
\documentclass{book}
\usepackage[a5paper]{geometry}
\usepackage{titletoc}
\begin{document}
\titlecontents{section}[36pt]{\addvspace{2pt}\filright}%
{\contentslabel{20pt}}% 注言这里不需要使用\contentspush了,接下来我们就讲该命令的作用
{\LaTeX{}\ \MakeUppercase}%
{~\hrulefill\contentspage}%
\tableofcontents
\chapter{This is a chapter}
\section{This is a section}
\section*{Foreword}
\addcontentsline{toc}{section}{\protect{}Foreword}
\section{This is a sample section entry which has been deliberately made very long so that it spans three lines to exhibit the handling of the first and the last line in the entry}
\end{document}
编译:
我们再用一张示意图展示一下\titlecontents
,\contentslabel
以及\contentspage
这三个命令的参数的作用位置:
观察上面两个例子,如果我们使用的是\thecontentslabel
,就需要用\contentspush
,如果使用的是\contentslabel
,就不需要了。那么,\contentspush
命令是作用是什么呢?
我们先在不使用\contentspush
的前提下使用\thecontentslabel
,看看是什么结果:
\documentclass{book}
\usepackage[a5paper]{geometry}
\usepackage{titletoc}
\begin{document}
\titlecontents{section}[36pt]{\addvspace{2pt}\filright}%
{\thecontentslabel\enspace }%
{}%
{~\hrulefill\contentspage}%
\tableofcontents
\chapter{This is a chapter}
\section{This is a section}
\section{This is a sample section entry which has been deliberately made very long so that it spans three lines to exhibit the handling of the first and the last line in the entry}
\end{document}
编译:
可见,默认情况下,标签会被当作标题文本的一部分一起缩进,缩进距离受left-indent
控制,我们加上\contentspush
,也就是将上面的例子中的\thecontentslabel\enspace
换成\contentspush{\thecontentslabel\enspace }
,编译如下:
\contentspush
会使标题文本进一步缩进,这个缩进的距离根据标题编号的长度而定,因此它是一个变化的值。这里要注意,标题文本的缩进不再是left-indent
,left-indent
是编号的缩进,而标题文本的缩进是left-indent
加上\contentspush
为编号生成的宽度。因此我们建议将left-indent
适当调小一些,像上面这样是不美观的。
我们也用一个示意图演示一下:
为什么使用一个变化的值呢?大多数时候我们都不建议这样用,除非你的章节非常多,例如有1.1,又有10.12这样的节编号,编号宽度差距会比较大。使用最大的宽度,对1.1来说太大了,小了的话10.12这样的编号又会和标题文本重合。
关注【年轻人 你渴望力量么】