\documentclass[12pt,b5paper,twoside]{book}
\usepackage{titlesec,xeCJK,zhlipsum,fontspec}
\usepackage[margin=2.5cm]{geometry}
\setcounter{tocdepth}{1}
\renewcommand{\normalsize}{\fontsize{10.5pt}{14pt}\selectfont}
\titleformat{\chapter}{\centering\fontsize{16pt}{16pt}\sffamily}{\fontsize{16pt}{16pt}\selectfont 第 \thechapter 章}{1em}{}
\titlespacing{\chapter}{0pt}{2cm}{20pt}
\renewcommand{\contentsname}{目 \quad 录}
\usepackage[titles]{tocloft}
\renewcommand{\cftchapnumwidth}{5em}
\renewcommand{\cftdot}{\ensuremath{\cdot}}
\renewcommand{\cftdotsep}{2}
\renewcommand{\cftchapleader}{\cftdotfill{\cftchapdotsep}}
\renewcommand{\cftchapdotsep}{\cftdotsep}
\renewcommand{\cftchappresnum}{第\ }
\renewcommand{\cftchapaftersnum}{章\ }
\renewcommand{\cftsecindent}{2em}
\renewcommand{\cftsecnumwidth}{2.5em}
\renewcommand{\cftsecpresnum}{\S\ }
\renewcommand{\cftsecaftersnum}{.}
\begin{document}
\setlength{\parindent}{2em}
\pagenumbering{Roman}
\chapter*{前序}
\zhlipsum[1]
\addcontentsline{toc}{chapter}{前言}
\tableofcontents
\clearpage
\pagenumbering{arabic}
\chapter{概述}
\section{diyi}
\zhlipsum[2]
\end{document}
需求/目标:
目录中未编号的章标题,比如前言后面取消点和页码,而正文的章标题也就是有编号的章标题,例如第1章仍然保留点和页码。
根据 tocloft
的官方文档,我们可以知道所谓的那一系列的 leader
是由命令 \cftdotfill
控制的, 此命令的声明如下:
\providecommand{\cftdotfill}[1]{%
\def\@tempa{#1}%
\def\@tempb{\cftnodots}%
\ifx\@tempa\@tempb
\hfill
\else
\ifStartUnumToc
\hfill\StartUnumTocfalse
\else
\leaders\hbox{$\m@th\mkern #1 mu\hbox{\cftdot}\mkern #1 mu$}\hfill
\fi
\fi
}
其中的 #1
就是你指定的那个 \cftXdotsep
, 这里的 X
就是 chap
. 我们可以看到里面有一个比较操作 \ifx\@tempa\@tempb
, 这里其实是比较当前传入的 \cftXdotsep
和 \cftnodots
, 查看 tocloft.sty
文档,可以发现其生命如下:
% around line 167
\newcommand{\cftnodots}{10000}
所以现在的思路就来了,只要我们在使用 \chapter*
前,让这个 \ifx
走 true
对应的分支,那么就可以取消 ToC 中对应条目后面的 leader
了. 所以只需要把对应的 \cftXdotsep
设置的足够大即可.
我为什么回去找这个 \cftdotfill
? 因为官方文档中有这样的说明: "However, if the separation is too large then no dots will be actually typeset. The macro cftnodots is a separation value that is ‘too large’"
下面就来说怎么实现上面的目标,我个人喜欢 patch 的方式,当然,你也可以采用 renewcommand 的方式. 所以这里我引入了 etoolbox
宏包用于在 \chapter*
和 \chapter
命令前设置这两个 \cftXdotsep
. 如果你读过 source2e
应该知道,一般的 star-form 的命令和对应的原始命令是通过如下的方式生命的:
\def\foo{\@ifstar\@foo\@@foo}
\def\@foo#1{...}
\def\@@foo#1{...}
所以我们这里要 patch 的命令其实是 \@schapter
和 \@chapter
,分别对应 star-form 和 original-form. 但是我们这里要把这些 \cftXdotsep
的重定义注入到 .toc
文件中. (你可以想一想为什么要注入到 .toc
文件,而不是直接放在你的 .tex
文件中?). 所以我们 patch 部分的代码为:
% ==> start patch
\usepackage{etoolbox}
\makeatletter
% 1. cancel dot line
\def\chapter@CancelLeader#1{
\write\@auxout{%
\protect\@writefile{toc}{%
\protect\renewcommand{\protect\cftchapdotsep}{#1}%
}%
}%
}
\pretocmd{\@schapter}{\chapter@CancelLeader{10000}}{}{}
\pretocmd{\@chapter}{\chapter@CancelLeader{2}}{}{}
\makeatother
patch 后的 .toc
文件大概长这样:
\renewcommand {\cftchapdotsep }{10000}
\contentsline {chapter}{前序}{I}{}%
\renewcommand {\cftchapdotsep }{10000}
\renewcommand {\cftchapdotsep }{2}
\contentsline {chapter}{\numberline {1}概述}{1}{}%
\contentsline {section}{\numberline {1.1}diyi}{1}{}%
\renewcommand {\cftchapdotsep }{2}
\contentsline {chapter}{\numberline {2}Test I}{3}{}%
\contentsline {section}{\numberline {2.1}sse I}{3}{}%
\contentsline {section}{\numberline {2.2}sse II}{3}{}%
\renewcommand {\cftchapdotsep }{10000}
\contentsline {chapter}{Test II}{5}{}%
\contentsline {section}{\numberline {2.3}sse I}{5}{}%
\contentsline {section}{\numberline {2.4}sse II}{5}{}%
最终修改后的代码为:
\documentclass[12pt,b5paper,twoside]{book}
\usepackage{titlesec,xeCJK,zhlipsum,fontspec}
\usepackage[margin=2.5cm]{geometry}
\setcounter{tocdepth}{1}
\renewcommand{\normalsize}{\fontsize{10.5pt}{14pt}\selectfont}
\titleformat{\chapter}{\centering\fontsize{16pt}{16pt}\sffamily}{\fontsize{16pt}{16pt}\selectfont 第 \thechapter 章}{1em}{}
\titlespacing{\chapter}{0pt}{2cm}{20pt}
\renewcommand{\contentsname}{目 \quad 录}
\usepackage[titles]{tocloft}
\renewcommand{\cftchapnumwidth}{5em}
\renewcommand{\cftdot}{\ensuremath{\cdot}}
\renewcommand{\cftdotsep}{2}
\renewcommand{\cftchapleader}{\cftdotfill{\cftchapdotsep}}
\renewcommand{\cftchapdotsep}{2}
\renewcommand{\cftchappresnum}{第\ }
\renewcommand{\cftchapaftersnum}{章\ }
\renewcommand{\cftsecindent}{2em}
\renewcommand{\cftsecnumwidth}{2.5em}
\renewcommand{\cftsecpresnum}{\S\ }
\renewcommand{\cftsecaftersnum}{.}
% ==> start patch
\usepackage{etoolbox}
\makeatletter
\def\chapter@CancelLeader#1{
\write\@auxout{%
\protect\@writefile{toc}{%
\protect\renewcommand{\protect\cftchapdotsep}{#1}%
}%
}%
}
\pretocmd{\@schapter}{\chapter@CancelLeader{10000}}{}{}
\pretocmd{\@chapter}{\chapter@CancelLeader{2}}{}{}
\makeatother
\begin{document}
\setlength{\parindent}{2em}
\pagenumbering{Roman}
\chapter*{前序}
\zhlipsum[1]
\addcontentsline{toc}{chapter}{前序}
\tableofcontents
\clearpage
\pagenumbering{arabic}
\chapter{概述}
\section{diyi}
\zhlipsum[2]
\chapter{Test I}
\section{sse I}
\section{sse II}
\chapter*{Test II}
\addcontentsline{toc}{chapter}{Test II}
\section{sse I}
\section{sse II}
\end{document}
对应的编译结果如下:
我觉得\chapter*
对应 ToC 项后面的 page number
后看起来并不是那么的美观, 但是既然你在问题里面要求了,我还是把对应的 patch 代码补充在这里吧。把以下的代码放到导言区即可:
%\usepackage{etoolbox}
\makeatletter
% 2. cancel page number
\newif\ifChapter@Num
\def\addcontentsline#1#2#3{%
\addtocontents{#1}{\protect\contentsline{#2}{#3}{\ifChapter@Num\thepage\fi}{}%
\protected@file@percent}
}
\pretocmd{\@schapter}{\Chapter@Numfalse}{}{}
\pretocmd{\section}{\Chapter@Numtrue}{}{}
\pretocmd{\@chapter}{\Chapter@Numtrue}{}{}
\makeatother
加上这个 patch 后的编译效果如下:
非常感谢Eureka的回复,可以实现未编号标题后面点和页码的取消显示的效果。您提出的一些的宏包或者文档我会仔细阅读的,努力提高水平。