10 对于book文档类如何优雅地去除多页目录页的页码?

发布于 2024-11-16 22:07:45

如题。
MWE1:仅仅使用\pagestyle{empty}

\documentclass[landscape,openany]{book}
\usepackage[a6paper]{geometry}
% \usepackage{tocloft}
% \tocloftpagestyle{empty}
\begin{document}
\pagestyle{empty}
\frontmatter
\title{This is a title}
\author{Explorer}
\date{\today}
\maketitle
\tableofcontents \clearpage
\mainmatter
\chapter{First}
\chapter{Second}
\chapter{Third}
\chapter{First}
\chapter{Second}
\chapter{Third}
\chapter{First}
\chapter{Second}
\chapter{Third}
\end{document}

效果图1:
image.png

MWE2:使用tocloft宏包提供的\tocloftpagestyle{empty}

\documentclass[landscape,openany]{book}
\usepackage[a6paper]{geometry}
\usepackage{tocloft}
\tocloftpagestyle{empty}
\begin{document}
% \pagestyle{empty}
\frontmatter
\title{This is a title}
\author{Explorer}
\date{\today}
\maketitle
\tableofcontents \clearpage
\mainmatter
\chapter{First}
\chapter{Second}
\chapter{Third}
\chapter{First}
\chapter{Second}
\chapter{Third}
\chapter{First}
\chapter{Second}
\chapter{Third}
\end{document}

效果图2:
image.png

MWE3: combine both of them...固然可行,但是觉得很不优雅

\documentclass[landscape,openany]{book}
\usepackage[a6paper]{geometry}
\usepackage{tocloft}
\tocloftpagestyle{empty}
\begin{document}
\pagestyle{empty}
\frontmatter
\title{This is a title}
\author{Explorer}
\date{\today}
\maketitle
\tableofcontents \clearpage
\mainmatter
\chapter{First}
\chapter{Second}
\chapter{Third}
\chapter{First}
\chapter{Second}
\chapter{Third}
\chapter{First}
\chapter{Second}
\chapter{Third}
\end{document}

image.png

What's is the BEST Practice to clear the page in toc?

查看更多

关注者
0
被浏览
365
Eureka
Eureka 2024-11-17
这家伙很懒,什么也没写!

其实这几个问题的共同原因都在 \chapter 命令的定义中了, 参见 book.cls 中的定义:

\newcommand\chapter{\if@openright\cleardoublepage\else\clearpage\fi
                   \thispagestyle{plain}%
                   \global\@topnum\z@
                   \@afterindentfalse
                   \secdef\@chapter\@schapter}

这个命令里面的 \thispagestyle{plain} 就产生了这个页码. 而对应的 \tableofcontents 的定义如下:

\newcommand\tableofcontents{%
   \if@twocolumn
     \@restonecoltrue\onecolumn
   \else
     \@restonecolfalse
   \fi
   \chapter*{\contentsname
       \@mkboth{%
          \MakeUppercase\contentsname}{\MakeUppercase\contentsname}}%
   \@starttoc{toc}%
   \if@restonecol\twocolumn\fi
   }

这个里面调用的是 \chapter* 命令,其实就是上面的那个 \@schapter 命令. 所以说解决办法也就很简单了, 在一个局部里面, 把 \tableofcontents 内部的这个 \chapter* 改一下就行了. 你可以选择重定义前者,也可以选择重定义后者. 这里我使用前者:

\documentclass[landscape,openany]{book}
\usepackage[a6paper]{geometry}
\makeatletter
\renewcommand\tableofcontents{%
          \if@twocolumn
            \@restonecoltrue\onecolumn
          \else
            \@restonecolfalse
          \fi
          \@schapter{\contentsname
              \@mkboth{%
                  \MakeUppercase\contentsname}{\MakeUppercase\contentsname}}%
          \@starttoc{toc}%
          \if@restonecol\twocolumn\fi
          }
\makeatother

\begin{document}
\pagestyle{empty}
\tableofcontents 

\chapter{First}
\chapter{Second}
\chapter{Third}
\chapter{First}
\chapter{Second}
\chapter{Third}
\chapter{First}
\chapter{Second}
\chapter{Third}
\end{document}

编译结果如下:
image.png

为了更好的理解这个问题,你可以试试下面这个例子:

\documentclass[landscape,openany]{book}
\usepackage[a6paper]{geometry}
\makeatletter

\begin{document}
\pagestyle{empty}
\@schapter{Contents}
\thispagestyle{plain} % comment this line to test page style
\@starttoc{toc}

\chapter{First}
\chapter{Second}
\chapter{Third}
\chapter{First}
\chapter{Second}
\chapter{Third}
\chapter{First}
\chapter{Second}
\chapter{Third}
\end{document}

至于你后面提到的 tocloft 宏包,你可以自己去看它的实现.

2 个回答
Sagittarius Rover
Sagittarius Rover 2024-11-17
我要成为TikZ糕手/(ㄒoㄒ)/~~

非常感谢Eureka老师的详细回答以及对@恐惧症患者的鼓励.

下面有一个小小的疑惑,如果采用重定义\chapter*定义的操作是不是会影响后续如果需要使用\chapter*的功能,虽然可以在局部修改,但是个人觉得这种方式远不如修改\tableofcontenst(将\chapter*替换为\@schapter)来得优雅简单.

\documentclass[landscape,openany]{book}
\usepackage[a6paper]{geometry}
\begin{document}
\pagestyle{empty}
\begingroup
\makeatletter
\renewcommand\chapter{\if@openright\cleardoublepage\else\clearpage\fi
            %\thispagestyle{plain}%
            \global\@topnum\z@
            \@afterindentfalse
            \secdef\@chapter\@schapter
            }
\makeatother
\tableofcontents 
\endgroup
% \mainmatter % 读源码的力量 get!
\cleardoublepage 
\pagenumbering{arabic}
\chapter{First}
\chapter{Second}
\chapter{Third}
\chapter*{First}
\chapter*{Second}
\chapter*{Third}
\chapter{First}
\chapter{Second}
\chapter{Third}
\end{document}

image.png

顺便补充几个命令定义(其实看macro名称也能大致看出它的含义):

\pagenumbering:
macro:#1->\global \c@page \@ne \gdef \thepage {\csname @#1\endcsname \c@page }

\secdef:
macro:#1#2->\@ifstar {#2}{\@dblarg {#1}}

\@starttoc:
macro:#1->\begingroup \makeatletter \@input {\jobname .#1}\if@filesw \expandafter \newwrite \csname tf@#1\endcsname \immediate \openout \csname tf@#1\endcsname \jobname .#1\relax \fi \@nobreakfalse \endgroup
\def\@schapter#1{\if@twocolumn
                   \@topnewpage[\@makeschapterhead{#1}]%
                 \else
                   \@makeschapterhead{#1}%
                   \@afterheading
                 \fi}
\def\@makeschapterhead#1{%
  \vspace*{50\p@}%
  {\parindent \z@ \raggedright
    \normalfont
    \interlinepenalty\@M
    \Huge \bfseries  #1\par\nobreak
    \vskip 40\p@
  }}

对于补充的思考练习:

  • case1:如果注释去\thispagestyle{plain}行,则可以去除所有ToC标题:

image.png

这是因为和正确的结果相比,上面的操作相当于用更底层的\@schapter命令排版了无编号的标题,同时不改变页码设置,相当于跳过了原有\chapter*中设定为plain的步骤,并且直接将当前section的信息写入.toc文件读取并刷新缓存;
  • case2:变式(指定\thispagestyle{plain}

image.png

虽然\@schapter在排版标题时并没有页码样式仍为empty,但由于首页还未自然结束,故而会继续进行ToC的排版,而在进行\@schapter排版之前已经指定了\thispagestyle{plain},因此首页ToC会出现页码而后续ToC不出现页码。
  • case3:自行测试使用\clearpage断页

image.png
[上图有个typo,正文是被\chapter设置为plain....]

撰写答案

请登录后再发布答案,点击登录

发布
问题

分享
好友

手机
浏览

扫码手机浏览