LaTeX教程(013)- LaTeX \LaTeX LATEX文档结构(13)
接上一篇
一个新的设计案例
首先,我们先建立一个目录文件,并导入到文档中。操作如下:
第一步创建文件test.tex
,写入如下代码并编译两次:
\documentclass{book}
\usepackage[a5paper,margin=1in]{geometry}
\usepackage{titletoc}
\begin{document}
\tableofcontents
\chapter{Chapter one}
\section{Section 1.1}
\section{Section 1.2}
\chapter{Chapter two}
\section{Section 2.1}
\section{Section 2.2}
\section{Section 2.3}
\chapter{Chapter three}
\section{Section 3.1}
\section{Section 3.2}
\section{Section 3.3}
\end{document}
两次编译之后,我们就得到一个test.toc
文件。进行第二步,打开test.toc
文件,并将该文件里面,后两章的代码复制下来,即从\contentsline {chapter}{\numberline {2}Chapter two}{5}{}%
开始,直到最后的内容都复制下来。创建一个新的文件,命名为partial.toc
文件,将复制的内容放置其中。最后加一行命令\contentsfinish
。这里在注意,所有自定义的特殊目录文件,最后最好都放上这个命令。当然,使用它的前提是调用了titletoc
包。对标准的目录,\contentsfinish
命令是在底层默认调用的。
第三步,创建一个新文件:
\documentclass{book}
\usepackage[a5paper,margin=1in]{geometry}
\usepackage{titletoc}
\begin{document}
\input{partial.toc} % 引入文件
\end{document}
编译:
这样我们就得到了一个局部的目录。局部命令在编写一部体量较大的书时很实用,这种情形下,我们可以在一个part
或者一个chapter
后面放置这个部分的目录。并且,.toc
文件中的内容(如编号,页码等)是可以手动修改的,只是通常都用不着去动它。通过这种方法,我们也可以看出像\tableofcontents
这样的命令在 LaTeX \LaTeX LATEX的底层是如何工作的。
现在我们可以在上面例子的基础上给条目增加一些样式。我们设置chapter
条目为靠左对齐(\filright
)的粗体(\bfseries
),在条目上方放置一段1 派卡(pica,单位pc)的垂直距离(1pc=12pt)和一条紧随其后的线段(rule
)。条目缩进5pc,在这5pc的空间中放置标头。首先将\chaptername
,也就是Chapter
,改成大写形式,放置一个空格之后,再放置标题编号。对于无编号的标题并没有特别的设置。页码的前面使用\hfill
填充(空白),并在chapter
条目的下面放置一个2pt的垂直距离,使其与后面的section
条目分得更开。
\documentclass{book}
\usepackage[a5paper,margin=1in]{geometry}
\usepackage{titletoc}
\titlecontents{chapter}[6.5pc]%
{\addvspace{1pc}\bfseries\titlerule[2pt]\filright}%
{\contentslabel[{\MakeUppercase{\chaptername}}\ \thecontentslabel]{6.5pc}}%
{}{\hfill\contentspage}[\addvspace{2pt}]
\begin{document}
\input{partial.toc}
\end{document}
编译:
为了方便对比,我们将partial.toc
文件中的chapter
标题换成长短不一的文本,然后再将样式进行以下修改: 将chapter
的标题设置成无衬线字体,标题文本居中,标题编号靠左,页码靠右,其余空间用基线上的线段填充。section
标题缩进1pc
,标题编号与标题文本之间用一个短破折号连接,并且没有页码。
\documentclass{book}
\usepackage[a5paper,margin=1in]{geometry}
\usepackage{titletoc}
\titlecontents{chapter}[0pt]%
{\addvspace{6pt}}%
{\large\sffamily\oldstylenums{\thecontentslabel}\ \hrulefill\ }%
{}{\large\sffamily\ \hrulefill\
\oldstylenums{\thecontentspage}}[\addvspace{2pt}]\titlecontents{section} [1pc]{}
{\oldstylenums{\thecontentslabel} -- }{}{}\begin{document}
\input{partial.toc}
\end{document}
编译:
最后一个例子中,我们将标题编号取消,将页码放在左边,也就是原本放编号的地方。chapter
标题靠右对齐,页码和标题文本之间用\dotfill
填充。section
标题的页码和标题文本之间用一个短破折号连接。
\documentclass{book}
\usepackage[a5paper,margin=1in]{geometry}
\usepackage{titletoc}
\titlecontents{chapter}[2pc]
{\addvspace{5pt}}%
{\large\bfseries\contentslabel[\hfill\thecontentspage]{2pc}\dotfill}%
{}{}[\addvspace{2pt}]\titlecontents{section}[2pc]{}
{\contentslabel[\hfill\thecontentspage]{2pc}%
\enspace --\enspace }{}{}\begin{document}
\input{partial.toc}
\end{document}
编译:
将条目合并到段落中
标准 LaTeX \LaTeX LATEX只支持将目录条目放置在单独的行中,而有时候将一些低级条目合并到一个段落里是一种更经济的方式,我们使用titletoc
包可以做到它。
达到这一目的需要使用\titlecontents
命令的变体,即\titlecontents*
,根据我们指定选项的个数的不同,它有以下三种形式:
\titlecontents*{type}[left-indent]{before-code}{numbered-entry-format}{numberless-entry-format}{page-format}[mid-code]
\titlecontents*{type}...{page-format}[mid-code][final-code]
\titlecontents*{type}...{page-format}[start-code][mid-code][final-code]
\titlecontents*
命令用于将一些条目放置在一个段落中,即,它们会水平地拼接在一起,在达到段落右边距时断行,就像排版段落文本时那样。该命令的前六个参数和\titlecontents
的前六个参数相同。
在这六个参数之后,\titlecontents
还有最后一个可选参数,below-code
,而\titlecontents*
的最后的可选参数,分别是start-code
,mid-code
和final-code
。这三个选项的执行规则与普通的选项不同,在最后三个选项中,当我们只指定一个进项时,它会被当作mid-code
选项执行,当我们指定两个选项时,它们会按照从左到右的顺序被分别当作mid-code
和final-code
,指定三个选项时,它们会按照从左到右的顺序被分别当作start-code
,mid-code
和final-code
。也就是上面展示的三种形式。这三个选项中的命令依情况而有选择地执行(以递归的方式):
- 如果当前条目是第一个被拼接的条目,那么在排版该条目之前,先执行
start-code
。 - 如果前面已经有被拼接的条目了,那么:
- 如果当前条目与前面的条目是同一级别的,那么在当前条目的前面执行
mid-code
。 - 如果当前条目是更低级别的,那么这意味着这是一个新的层级的第一个条目,因此在该条目的前面执行
start-code
。 - 如果当前条目是更高级别的,这意味着前面的低级别的若干条目拼接结束了,因此首先执行前面所有的已经结束了的层级的
final-code
。然后,如果当前条目不再参与拼接,则完成拼接(执行上一个同级条目的final-code
)。否则,继续将mid-code
插入到该条目的前面。
- 如果当前条目与前面的条目是同一级别的,那么在当前条目的前面执行
我们先看一个例子(在这之前,为了使文档更具代表性,你最好修改一下partial.toc
文件,将不同的标题文本改成长短不一的文本):
\documentclass{book}
\usepackage[a5paper,margin=1.5in]{geometry}
\usepackage{titletoc}
\usepackage{xcolor} %用来设置颜色的红包
\contentsmargin{0pt}
%回顾一下,这是设置右侧缩进的命令,用来放置页码的,现在不需要页码了,设置为0
\titlecontents*{chapter}[0pt]{\sffamily}{}{}{, \thecontentspage}%
[\ \textbullet \ ] [~\P] % mid, final
% \textbullet生成一个实心圆点 \P是一个特殊符号
\titlecontents*{section}[0pt]{\color{blue}\footnotesize\slshape}{}{}{}%
[ \{] [; ] [\}] % start, mid, final
\begin{document}
\input{partial.toc}
\end{document}
编译:
如果有几个不同的层级被拼接起来,那么需要将段落的排版信息放在被拼接的最高级条目的设置命令的before-code
中,否则你的设置可能不会覆盖整个段落。
如果你觉得前面的描述比较绕,那么我们就从这个例子并始讲解,请仔细观察。
首先是第一个chapter
条目,我们说过,第一个被拼接的条目,在排版该条目前执行它所在层级的start-code
,由于我们没有指定chapter
标题的start-code
,所以不执行。其次是第一个section
条目,我们前面说,如果当前条目比前一个条目层级更低,就意味着该条目是它所在层级的第一个条目,于是要在该section
条目的前面执行section
条目的start-code
,在这个例子中,section
条目的start-code
是左大括号{
。然后到了第二个section
条目。我们前面说过,如果当前条目与前一个条目层级相同,那么在当前条目的前面插入mid-code
,这个例子中mid-code
是一个分号。第三个section
条目依旧是在前面插入一个分号。
到了第二个chapter
条目,我们说如果当前条目比前一个条目的层级更高,就意味着前面的更低层级的条目拼接已经完成,我们执行前一个条目所在层级的final-code
,也就是右大括号}
。然后开始当前条目的拼接,我们前面说,如果当前条目继续参与拼接,那么在当前条目的前面插入mid-code
。chapter
条目的mid-code
是一个圆点,我们用\textbullet
表示。接着,第二个chapter
条目下的section
条目,重复上一过程。从第一个开始,直到最后一个section
条目拼接完成,其后不再有参与拼接的条目,则执行前面拼接结束了的条目层级的final-code
。chapter
的final-code
是一个特殊符号,我们用\P
来生成它,~
是一个空格,和普通的空格不同的是,这种方式生成的空格使 LaTeX \LaTeX LATEX不会在此处断页。
仔细观察可以发现,其实条目拼接的基本逻辑就是同层级条目的相互拼接,而低级条目是高级条目的附属。即,无论一个chapter
条目下有多少个section
条目,不管它们如何拼接,都不影响下一个chapter
的拼接方式,因为它本质上是与上一个chapter
条目拼接。并且直到所有section
标题拼接完成,且不再有新的chapter
条目参与拼接,才会执行chapter
条目的final-code
。而subsection
之于section
也是如此,层层嵌套。
基于这样的逻辑,我们说在最高级条目的before-code
中的排版设置会影响整个段落(如上一个例子中了\sffamily
)。而低层级的条目设置不会影响高层级的条目。
在下一个例子中,我们使用圆点来连接section
标题,并且在圆点两侧各放置一段弹性距离,我们将它定义为\xquad
,最后用一个句点结束。chapter
标题将页码放在左边(注意这个例子中,chapter
条目不参与拼接),并且所有标题取消编号。我们将页码放到了左边,和上一个例子一样,将右侧缩进设置为0。
\documentclass{book}
\usepackage[a5paper,margin=1in]{geometry}
\usepackage{titletoc}
\contentsmargin{0pt}
\titlecontents{chapter}[0pt]%
{\addvspace{1.4pc}\bfseries}{{\Huge\thecontentspage\quad}}{}{}
\newcommand\xquad{\hspace{1em plus.4em minus.4em}}
\titlecontents*{section}[0pt]{\filright\small}{}{}{,~\thecontentspage}%
[\xquad\textbullet\xquad][.] % mid, final
\begin{document}
\input{partial.toc}
\end{document}
编译:
生成局部目录
前面讲了如何通过引入一个新的.toc
文件来生成一个局部的目录。接下来我们讲一下如何通过titletoc
的一些命令在每一章的章标题下面生成本章的次级条目列表,如本章的所有节目录。
首先介绍两个命令,第一个是
\startcontents[name]
这个命令用来收集局部命令的数据,并将它们存储在一个.ptc
文件中。第二个命令是
\printcontents[name]{prefix}{start-level}{toc-code}
这个命令用来将收集到的局部命令的数据打印到文档中。我们用一个例子演示一下:
\documentclass{book}
\usepackage[a5paper,margin=1in]{geometry}
\usepackage{titletoc}
\begin{document}
\chapter{This is chapter one}
\startcontents %开始收集
\printcontents{p-}{1}{} %打印该次收集
some test of the current chapter
\section{this is section one}
\section{this is section two}
\subsection{this is subsection one}
\subsection{this is subsection two}
\startcontents %结束上一次收集,并开始下一个收集
\chapter{this is chapter two}
\end{document}
编译(截取部分):
可以看到,我们在第一章的标题下面放置了一个局部目录,它正是我们用命令\startcontents
收集,并且用\printcontents
打印出来的。一个文档中可以有很多个\startcontents
命令(实际上,如果使用了这个命令,很少有只用一个的情况),第一个局部目录的数据从第一个\startcontents
开始,到第二个\startcontents
结束,第二个局部目录的数据从第二个\startcontents
开始,到第三个\startcontents
结束,以此类推,\startcontents
结束一个局部目录的收集,同时也会发起下一个收集。如果我们要打印第一个局部目录,就在第一个\startcontents
和第二个\startcontents
之间使用\printcontents
命令, LaTeX \LaTeX LATEX就会根据\printcontents
的位置将这个局部目录放置在文档中,以此类推,第n个\printcontents
要放置在第n个\startcontents
与第n+1个\startcontents
之间。
局部目录的收集是可以重叠的(大多数时候是嵌套),例如,你可能会想在part
标题的下方放置该part的所有本章、节与子节的目录列表,同时也想在chapter标题下放置该章所有的节和子节标题,那么必然有一些目录是重复的,那么,如何收集重复的目录数据呢?例如,我们在文档中放置4个\startcontents
:
\startcontents % A
...
\startcontents % B
...
\startcontents % C
...
\startcontents % D
我们如何让 LaTeX \LaTeX LATEX知道,我们想收集从A到D的目录,和从B到C的目录呢?因为按照上述原理, LaTeX \LaTeX LATEX会收集A-B、B-C以及C-D这三个区域的局部目录标题。这个时候就要用到选项name
了。name
是一个自定义的自符串,用来将相应的\startcontents
匹配起来,并且在使用\printcontents
时使用指定name
选项,能够让 LaTeX \LaTeX LATEX知道我们要打印哪一部分的局部目录。若要实现上述想法,只需要:
\startcontents[part] % A
\printcontents[part]{p-}{0}{}
...
\startcontents[chapter] % B
\printcontents[chapter]{p-}{1}{}
...
\startcontents[chapter] % C
...
\startcontents[part] % D
这样,我们就可以A-D中间的局部目录在\printcontents[part]{p-}{0}{}
处打印出来,将B-C中间的局部目录在\printcontents[chapter]{p-}{1}{}
处打印出来。name
可以是任意字符串,但是通常用有意义的名字,以便于我们能够轻易识别它们的意义。如果不指定name
,则默认name
是default
。\startcontents
开始收集一个局部目录的数据,直到下一个相同name
的\startcontents
停止,同时开始收集下一个局部目录的数据,以此类推。这些目录的收集将同时进行,最后所有局部目录的数据都被放入一个.ptc
文件中。该文件在\startcontents
命令执行后自动生成。
现在我们暂且不管prefix
的作用,这里讲一下start-level
参数。它表示被打印出来的当前局部目录的开始层级。在前面的例子中,如果我们将第7行的\printcontents{p-}{1}{}
中的参数1改为2,那么此处的局部目录就会从subsection
(2级标题)开始打印:
我们可以设置开始层级,那么如何设置结束层级呢?即,如何告诉 LaTeX \LaTeX LATEX该局部目录显示的最底层级呢?我们可以在toc-code
中设置tocdepth
,回忆一下,这是一个影响目录显示深度的计数器。其他的初始化操作也都可以放在toc-code
中,比如我们前面将目录条目的右侧缩进设置为0,这是因为局部目录是作为一个单独段落排版的,不需要右侧缩进。
难道我们每生成一个局部目录,就要手动输入一次收集与打印命令吗?当然不用,回忆一下我们讲过的titlesec
包(从007篇开始),该包有一个用来定制标题样式的命令:
\titleformat{cmd}[shape]{format}{label}{sep}{before-code}[after-code]
我们可以将\startcontents
和\printcontents
放在after-code
中,这样,被定制样式的标题每生成一个,就会自动执行这两个命令,也就会自动收集该标题下的局部目录的信息,并将它们打印出来:
\documentclass{book}
\usepackage[a5paper,margin=1in]{geometry}
\usepackage{titlesec,titletoc}
\begin{document}
\titleformat{\section}{\normalfont}%
{\large\bfseries\thesection\enspace}{0.5em}{\large\bfseries}%
[\vspace*{5pt}\startcontents\printcontents{p-}{2}{\contentsmargin{0pt}}]\titlespacing*{\section}{0pc}{*4}{*2.3}[1pc]\chapter{This is chapter one}
\section{this is section one}
\section{this is section two}
\subsection{this is subsection one}
\subsection{this is subsection two}
\section{this is section three}
\subsection{this is subsection three}
\end{document}
编译:
如果我们想为局部目录的条目单独设置样式,使其与主目录的样式不同,应该如何做呢?我们上一讲中讲过设置条目样式的命令\titlecontents
,其后的第一个命令就是划分命令的标题,如\titlecontents{subsection}...
,那么如何区分主目录的subsection
和局部目录的subsection
呢?这就要讲到\printcontents
命令的prefix
参数了,它用来给局部目录中的条目类型增加一个前缀,用来将它与主目录区分开来,例如我们将其设置为-p
,那么局部目录中的条目类型前面就会多出一个-p
,如p-subsection
。
另外再讲两个命令,分别是
\stopcontens[name]
\subsection{test}
\resumecontents[name]
\stopcontens[name]
用来中断一个局部目录的收集,\resumecontents[name]
用来继续一个局部目录的收集。\resumecontents[name]
和startcontents[name]
的功能不同,后者会开始一个新的局部目录,而前者会继续旧的局部目录。前面展示的情况中,名为name
的局部目录的收集会在\subsection{test}
之前停止,然后在其后继续,即会跳过\subsection{test}
。我们用一个例子演示一下(连同局部目录的条目样式设置):
\documentclass{article}
\usepackage[a5paper,margin=1in]{geometry}
\usepackage{titlesec,titletoc}
\titleformat{\section}[frame]{\normalfont}{\footnotesize \enspace SECTION \thesection\enspace}%
{6pt}{\large\bfseries\filcenter}%
[\vspace*{5pt}\startcontents\printcontents{p-}{2}{\contentsmargin{0pt}}]\titlespacing*{\section}{1pc}{*4}{*2.3}[1pc]%
\titlecontents*{p-subsection}[0pt]%
{\small\itshape\fillast}{}{}{}[ --- ][.]\begin{document}
\section{A Title Test}
Some text to prove that this paragraph is not indented.
\subsection{A first} Some text \ldots \newpage
\subsection{A longer second} Some more text.
\stopcontents \subsection{A third} \resumecontents
\subsection{An even longer fourth}
\end{document}
编译(只截取一部分):
注意,上面的两个例子,经过笔者本人反复测试,一旦指定了name
选项,就会报错。当前使用的 LaTeX \LaTeX LATEX版本是TeXLive2024。读者也可自行测试,如果发现问题的原因,请留言。
还有一些类似的用来生成局部的表格清单和图形清单的命令,如\startlist
,\printlist
,\stoplist
和\resumelist
等。语法上有一些细微的差别,它们很少用到,我们这里不再细讲,如果需要,讲查阅titletoc
包文档。
关注【年轻人 你渴望力量么】