(有点相关为链接和索引部分标题定义命令)。
我试图让章节标题链接到目录中的条目,以便获得“双向”导航,例如:用户在目录中查找章节标题,跳转到那里,阅读几行,再次单击章节标题并再次被带到目录中该章节的条目。
我原来的问题是这里,从那里的讨论中我得到了以下代码:
\newcounter{tocBackrefCount}
\newcommand{\Chapter}[3]{%
\chapter%
(#1)%
[\protect\raisebox{\baselineskip}{\protect\hypertarget{toc:backref:\thetocBackrefCount}{}}#2]%
{\hyperlink{toc:backref:\thetocBackrefCount}{#3}}\stepcounter{tocBackrefCount}%
}
(注:括号中的论据\chapter
是由hypbmsec
包裹) 这个宏的调用方式如下\Chapter{bookmark}{short}{long}
,其中bookmark
是您希望它出现在查看器中的书签名称,short
是目录条目,long
是实际的章节标题(在文本中,将被链接的标题)。
我目前使用此方法面临三个问题:
- 需要 3 到 5 次编译才能将所有引用放到位(也许hypdestopt 包与此有关系……?)。
- 它是丑陋的,我宁愿重新定义标准
\chapter
和\chapter*
命令,或者至少让它采用像标准一样默认的可选参数。
您愿意分享您在这个问题上的专业知识吗?
PS:该\raisebox
命令是为了避免hyperref
将目标的锚点设置为 ToC 条目的左下角(试一试不用它,你就会明白我的意思)。
PPS:这里有一个 MWE 供您欣赏:
\documentclass{book}
\usepackage[colorlinks,linktocpage]{hyperref}
\usepackage{hypbmsec}
\newcounter{tocBackrefCount}
\newcommand{\Chapter}[3]{%
\chapter(#1)%
[\protect\raisebox{\baselineskip}{\protect\hypertarget{toc:backref:\thetocBackrefCount}{}}#2]%
{\hyperlink{toc:backref:\thetocBackrefCount}{#3}}%
\stepcounter{tocBackrefCount}}
\begin{document}
\tableofcontents
\Chapter{Bookmark 1}{Short 1}{Long 1}
\noindent\ldots
\Chapter{Bookmark 2}{Short 2}{Long 2}
\noindent\ldots
\Chapter{Bookmark 3}{Short 3}{Long 3}
\noindent\ldots
\Chapter{Bookmark 4}{Short 4}{Long 4}
\noindent\ldots
\Chapter{Bookmark 5}{Short 5}{Long 5}
\noindent\ldots
\Chapter{Bookmark 6}{Short 6}{Long 6}
\noindent\ldots
\Chapter{Bookmark 7}{Short 7}{Long 7}
\noindent\ldots
\end{document}
可能的好的解决方案
在周末的大部分时间里,我都在摆弄这个问题,得到了@egreg代码的以下“最终”版本:
\documentclass{book}
\usepackage{xparse}
\usepackage{etoolbox}
\usepackage[colorlinks,linktocpage,plainpages=false,pdfpagelabels]{hyperref}
\usepackage{bookmark}
\usepackage{hypbmsec}
\usepackage{hypdestopt}
\makeatletter
\newcounter{tocBackrefCount}
\def\MPR@command#1{%
\AtBeginDocument{\csletcs{HYPBMSEC@#1}{#1}\csletcs{#1}{MPR@#1}}%
\expandafter\DeclareDocumentCommand\csname MPR@#1\endcsname{s d() o m}{
\stepcounter{tocBackrefCount}
\IfBooleanTF{##1}
{\IfNoValueTF{##2}
{\IfNoValueTF{##3}
{\addtocounter{tocBackrefCount}{-1}\@nameuse{HYPBMSEC@#1}*{##4}}
{\@nameuse{HYPBMSEC@#1}*{\phantomsection{}\mpr@mand{##4}%
\addcontentsline{toc}{#1}{\texorpdfstring{\mpr@opt{##3}}{##3}}}}
}
{\IfNoValueTF{##3}
{\@nameuse{HYPBMSEC@#1}*{\phantomsection{}\mpr@mand{##4}%
\addcontentsline{toc}{#1}{\texorpdfstring{\mpr@opt{##4}}{##2}}}}
{\@nameuse{HYPBMSEC@#1}*{\phantomsection{}\mpr@mand{##4}%
\addcontentsline{toc}{#1}{\texorpdfstring{\mpr@opt{##3}}{##2}}}}
}
}
{\IfNoValueTF{##2}
{\IfNoValueTF{##3}
{\@nameuse{HYPBMSEC@#1}(##4)[\mpr@opt{##4}]{\mpr@mand{##4}}}
{\@nameuse{HYPBMSEC@#1}(##3)[\mpr@opt{##3}]{\mpr@mand{##4}}}
}
{\IfNoValueTF{##3}
{\@nameuse{HYPBMSEC@#1}(##2)[\mpr@opt{##4}]{\mpr@mand{##4}}}
{\@nameuse{HYPBMSEC@#1}(##2)[\mpr@opt{##3}]{\mpr@mand{##4}}}
}
}
}
}
\def\mpr@opt#1{\protect\raisebox{1.6ex}{%
\protect\hypertarget{toc:backref:\thetocBackrefCount}{}}#1}
\def\mpr@mand#1{\hyperlink{toc:backref:\thetocBackrefCount}{#1}}
\MPR@command{chapter}
\MPR@command{section}
\makeatother
\begin{document}
\tableofcontents
\chapter{No optional argument}
\noindent\ldots
\section{ABC}
\noindent\ldots
\chapter[opt]{Optional argument}
\noindent\ldots
\chapter(book){No optional argument + bookmark}
\noindent\ldots
\chapter(book)[opt]{Both optional arguments}
\noindent\ldots
\chapter*{No optional argument}
\noindent\ldots
\section*{ABC}
\noindent\ldots
\chapter*[opt]{Optional argument}
\noindent\ldots
\chapter*(book){No optional argument + bookmark}
\noindent\ldots
\chapter*(book)[opt]{Both optional arguments}
\noindent\ldots
\end{document}
这很好地处理了带星号的分段命令版本。请注意添加hypdestopt
包裹:如果没有它,您会收到有关重复hyperref
目标的虚假警告。
请注意,我们不再\reisebox
使用整体\bsaelineskip
:这会在 ToC 中产生某些不良影响;相反,1.6ex
使用经验合理的值。我敢打赌,这将不是是一个万无一失的解决方案,我愿意听取有关此事的建议。
这个解决方案对我来说最有效,但我也想听听您的想法,我相信在这个问题上还有更多可以说的!
答案1
\documentclass{book}
\usepackage{xparse}
\usepackage[colorlinks,linktocpage]{hyperref}
\usepackage{bookmark}
\usepackage{hypbmsec}
\newcounter{tocBackrefCount}
\makeatletter
\def\MPR@chapter{\@ifstar{\HYPBMSEC@chapter*}\MPR@chapter@}
\DeclareDocumentCommand{\MPR@chapter@}{d() o m}{
\stepcounter{tocBackrefCount}
\IfNoValueTF{#1}
{\IfNoValueTF{#2}
{\HYPBMSEC@chapter(#3)[\mpr@opt{#3}]{\mpr@mand{#3}}}
{\HYPBMSEC@chapter(#2)[\mpr@opt{#2}]{\mpr@mand{#3}}}
}
{\IfNoValueTF{#2}
{\HYPBMSEC@chapter(#1)[\mpr@opt{#3}]{\mpr@mand{#3}}}
{\HYPBMSEC@chapter(#1)[\mpr@opt{#2}]{\mpr@mand{#3}}}
}
}
\def\mpr@opt#1{\protect\raisebox{\baselineskip}{%
\protect\hypertarget{toc:backref:\thetocBackrefCount}{}}#1}
\def\mpr@mand#1{\hyperlink{toc:backref:\thetocBackrefCount}{#1}}
\AtBeginDocument{
\let\HYPBMSEC@chapter\chapter
\let\chapter\MPR@chapter
}
\makeatother
\begin{document}
\tableofcontents
\chapter{No optional argument}
\noindent\ldots
\chapter[opt]{Optional argument}
\noindent\ldots
\chapter(book){No optional argument + bookmark}
\noindent\ldots
\chapter(book)[opt]{Both optional arguments}
\noindent\ldots
\end{document}
加载中书签通常会节省 LaTeX 运行的次数。
通用定义
以下是如何扩展以前的方法来重新定义所有所需的分段命令
\documentclass{book}
\usepackage{xparse,etoolbox}
\usepackage[colorlinks,linktocpage]{hyperref}
\usepackage{bookmark}
\usepackage{hypbmsec}
\makeatletter
\newcounter{tocBackrefCount}
\def\MPR@command#1{%
\AtBeginDocument{\csletcs{HYPBMSEC@#1}{#1}\csletcs{#1}{MPR@#1}}%
\@namedef{MPR@#1}{\@ifstar{\@nameuse{HYPBMSEC@#1}*}{\@nameuse{MPR@#1@}}}%
% define \MPR@<command>@
\expandafter\DeclareDocumentCommand\csname MPR@#1@\endcsname{d() o m}{
\stepcounter{tocBackrefCount}
\IfNoValueTF{##1}
{\IfNoValueTF{##2}
{\@nameuse{HYPBMSEC@#1}(##3)[\mpr@opt{##3}]{\mpr@mand{##3}}}
{\@nameuse{HYPBMSEC@#1}(##2)[\mpr@opt{##2}]{\mpr@mand{##3}}}
}
{\IfNoValueTF{##2}
{\@nameuse{HYPBMSEC@#1}(##1)[\mpr@opt{##3}]{\mpr@mand{##3}}}
{\@nameuse{HYPBMSEC@#1}(##1)[\mpr@opt{##2}]{\mpr@mand{##3}}}
}
}
}
\def\mpr@opt#1{\protect\raisebox{\baselineskip}{%
\protect\hypertarget{toc:backref:\thetocBackrefCount}{}}#1}
\def\mpr@mand#1{\hyperlink{toc:backref:\thetocBackrefCount}{#1}}
\MPR@command{chapter}
\MPR@command{section}
\makeatother
\begin{document}
\tableofcontents
\chapter{No optional argument}
\noindent\ldots
\section{ABC}
\noindent\ldots
\chapter[opt]{Optional argument}
\noindent\ldots
\chapter(book){No optional argument + bookmark}
\noindent\ldots
\chapter(book)[opt]{Both optional arguments}
\noindent\ldots
\end{document}
现在只需列出要重新定义的命令,在此示例中仅为\chapter
和\section
,通过\MPR@command{<section level>}
。
我未能成功重新定义方便\chapter*
和类似以允许可选参数。仍在考虑。
答案2
以下是将某个命令包装到另一个命令中的常用模式。以本章为例:
\let\chapterOriginal\chapter
\renewcommand{\chapter}{...\chapterOriginal ...}
“let”为原始命令创建了另一个名称,当原始命令被重新定义时,该名称仍然有效。