100 在elegantbook.cls的现有框架中,添加「cleveref」功能的最佳实践?

发布于 2025-12-14 14:39:31

众所周知,在默认的fancy模式下的「定理类」环境基于tcolorbox实现:

具体代码可见:https://github.com/ElegantLaTeX/ElegantBook/blob/master/elegantbook.cls#L911-L1037

本问题的需求是:在不改变现有的frozen版本elegantbook.cls的前提下,希望给其增加「cleveref」功能。


一点探索:

既然elegantbook.cls是基于tcolorbox的,因此首先一定要先在tcolorbox里实现cleveref的功能。查阅文档得知,大约有两套方案:

  • 基于cleveref(2018年以来不再更新,经常与hyperref的功能起冲突)
  • 基于zref-clever

对于方案一:

一个最小例子如下:

\documentclass[12pt]{article} 
\usepackage[
    noheadfoot,
    margin=8mm,
    papersize={10cm,10cm},
]{geometry} 
\usepackage{cleveref}
\usepackage{tcolorbox}
\newtcolorbox[
    auto counter,
    number within=section,
    crefname={bluebox}{blueboxes}
]{mybluebox}[2][]{
    % label is label,% default value
    colback=blue!5!white,
    colframe=blue!75!black,
    fonttitle=\bfseries,
    title=Bluebox \thetcbcounter: #2,#1
}
\begin{document} 
\section{Blue}

\begin{mybluebox}[label={myreference}]{My title} 
This is an example.
\end{mybluebox}

\begin{mybluebox}[label={myreference2}]{My titletitle} 
This is an example.
\end{mybluebox}

\noindent
\Cref{myreference}, \cref{myreference}.\\ 
\Cpageref{myreference}, \cpageref{myreference}.\\ 
\nameCref{myreference}, \namecref{myreference}.\\ 
\labelcref{myreference}, \labelcpageref{myreference}.\\ 
\Cref{myreference2}, \cref{myreference2}\\
\Cref{myreference,myreference2}, \cref{myreference,myreference2}\\

\end{document}

image.png

对于方案二:

\documentclass[12pt]{article} 
\usepackage[
    noheadfoot,
    margin=8mm,
    papersize={10cm,10cm},
]{geometry} 
\usepackage{zref-clever}
\zcRefTypeSetup{mybluebox}{
    Name-sg = Bluebox , 
    name-sg = bluebox , 
    Name-pl = Blueboxes ,
    name-pl = blueboxes ,
}
\usepackage{tcolorbox}
\newtcolorbox[
    auto counter,
    number within=section,
]{mybluebox}[2][]{
    label type=mybluebox,
    colback=blue!5!white,
    colframe=blue!75!black,
    fonttitle=\bfseries,
    title=Bluebox \thetcbcounter: #2,#1
}
\begin{document} 
\section{Blue}

\begin{mybluebox}[label={myreference}]{My title} 
This is an example.
\end{mybluebox}

\begin{mybluebox}[label={myreference2}]{My titletitle} 
This is an example.
\end{mybluebox}

\noindent
\zcref{myreference}.\\ 
\zcpageref{myreference}.\\ 
\zcref[S]{myreference}.\\
\zcref[S]{myreference,myreference2}.\\
\zcref{myreference,myreference2}.\\

\end{document}

image.png


现在的核心问题是,由于elegantbook已经停止维护了,最好是在不改变elegantbook.cls(v4.5)当前架构的大前提下,在main.tex下通过类似/.append style或者覆盖现有配置等方式实现对「定理类环境」的「cleveref」功能。

image.png

由于在这里使用了共同的接口\ELEGANT@newtheorem,我个人感觉无论是:

image.png

  • 想在init options里传入cleverefcrefname选项
  • 或者想在类似thmstyle样式里加入label typezref-clever方案

都不太轻松...


一个可供测试的MWE如下:

注意这里的\documentclass{elegantbook}用的就是这个官方唯一指定的v4.5文件,不允许对.cls文件做任何修改

\documentclass[lang=cn,fontset=fandol]{elegantbook}
\geometry{paperheight=12cm}
\usepackage{cleveref}
% \usepackage{zref-clever}
% \zcRefTypeSetup{mytheorem}{Name-sg={定理},Name-pl={定理}}
% \zcRefTypeSetup{mylemma}{Name-sg={引理},Name-pl={引理}}

\begin{document}
\chapter{111}

\begin{theorem}{欧拉定理}{Euler}
    这是一个定理。
\end{theorem}

\cref{lem:Osbert} 

\cref{lem:Wong}

\cref{lem:Osbert,lem:Wong}

% \zcref{lem:Osbert} 

% \zcref{lem:Wong}

% \zcref{lem:Osbert,lem:Wong}

\chapter{222}

\begin{lemma}{Osbert引理}{Osbert}
    这是一个引理。
\end{lemma}

\begin{theorem}{欧几里得公理}{Euclide}
    这是另一个定理。
\end{theorem}

\cref{thm:Euler}

\cref{thm:Euclide} 

\cref{thm:Euler,thm:Euclide}

% \zcref{thm:Euler}

% \zcref{thm:Euclide} 

% \zcref{thm:Euler,thm:Euclide}

\chapter{333}
\begin{lemma}{Wong引理}{Wong}
    这是一个引理。
\end{lemma}

\end{document}

当然,也希望该功能可以加入2026年可能有希望短暂(复活)的elegantbook更新中....

查看更多

关注者
0
被浏览
150
3 个回答
LaTeXer
LaTeXer 1天前
这家伙很懒,什么也没写!

✅✅✅ 大大大的 赞👍

Sagittarius Rover
这家伙很懒,什么也没写!

基于cleveref方案的一个处理方案

感谢@听风看雨 的提示:

初始选项

crefname={bluebox}{blueboxes}

实际上只是

\crefname{tcb@cnt@mybluebox}{bluebox}{blueboxes}

换言之上述的第一个mwe可以有另一个「更内部」的实现:

\documentclass[12pt]{article} 
\usepackage[
    noheadfoot,
    margin=8mm,
    papersize={10cm,10cm},
]{geometry} 
\usepackage{cleveref}
\usepackage{tcolorbox}
\newtcolorbox[
    auto counter,
    number within=section,
    % crefname={bluebox}{blueboxes}
]{mybluebox}[2][]{
    % label is label,% default value
    colback=blue!5!white,
    colframe=blue!75!black,
    fonttitle=\bfseries,
    title=Bluebox \thetcbcounter: #2,#1
}
% add here<-
\makeatletter
\crefname{tcb@cnt@mybluebox}{bluebox}{blueboxes}
\makeatother
\begin{document} 
\section{Blue}

\begin{mybluebox}[label={myreference}]{My title} 
This is an example.
\end{mybluebox}

\begin{mybluebox}[label={myreference2}]{My titletitle} 
This is an example.
\end{mybluebox}

\noindent
\Cref{myreference}, \cref{myreference}\\ 
\Cpageref{myreference}, \cpageref{myreference}\\ 
\nameCref{myreference}, \namecref{myreference}\\ 
\labelcref{myreference}, \labelcpageref{myreference}\\ 
\Cref{myreference2}, \cref{myreference2}\\
\Cref{myreference,myreference2}, \cref{myreference,myreference2}\\

\end{document}

同样可以得到:

image.png

这意味着我们在elegantlatex框架下,对于基于tcolorboxfancy模式也只需要对相应的环境做如下的patchcref设置即可:

% \usepackage{cleveref}
\makeatletter
\crefname{tcb@cnt@theorem}{\theoremname}{\theoremname}
\crefformat{tcb@cnt@theorem}{\theoremname~#2#1#3}
\crefmultiformat{tcb@cnt@theorem}{\theoremname~#2#1#3}{~和~#2#1#3}{,#2#1#3}{~和~#2#1#3}
\crefrangeformat{tcb@cnt@theorem}{\theoremname~#3#1#4~至~#5#2#6}
\crefname{tcb@cnt@definition}{\definitionname}{\definitionname}
\crefformat{tcb@cnt@definition}{\definitionname~#2#1#3}
\crefmultiformat{tcb@cnt@definition}{\definitionname~#2#1#3}{~和~#2#1#3}{,#2#1#3}{~和~#2#1#3}
\crefrangeformat{tcb@cnt@definition}{\definitionname~#3#1#4~至~#5#2#6}
\makeatother

Code

\documentclass[lang=cn,fontset=fandol]{elegantbook}
\geometry{paperheight=12cm}
\usepackage{cleveref}
\makeatletter
\crefname{tcb@cnt@theorem}{\theoremname}{\theoremname}
\crefformat{tcb@cnt@theorem}{\theoremname~#2#1#3}
\crefmultiformat{tcb@cnt@theorem}{\theoremname~#2#1#3}{~和~#2#1#3}{,#2#1#3}{~和~#2#1#3}
\crefrangeformat{tcb@cnt@theorem}{\theoremname~#3#1#4~至~#5#2#6}

\crefname{tcb@cnt@definition}{\definitionname}{\definitionname}
\crefformat{tcb@cnt@definition}{\definitionname~#2#1#3}
\crefmultiformat{tcb@cnt@definition}{\definitionname~#2#1#3}{~和~#2#1#3}{,#2#1#3}{~和~#2#1#3}
\crefrangeformat{tcb@cnt@definition}{\definitionname~#3#1#4~至~#5#2#6}
\makeatother

\begin{document}
\chapter{111}

\begin{definition}{\LaTeX 定义}{LaTeX}
    这是\LaTeX{}的定义
\end{definition}

\begin{theorem}{欧拉定理}{Euler}
    这是一个定理。
\end{theorem}

\begin{theorem}{毕达哥拉斯定理}{Bachagoras}
    这是一个定理。
\end{theorem}

\cref{def:Osbert} 

\cref{def:Wong,def:LaTeX,def:Wang}

\cref{def:Osbert,def:Wong,def:LaTeX,def:Wang}

\chapter{222}

\begin{definition}{Osbert定义}{Osbert}
    这是一个定义。
\end{definition}

\begin{theorem}{欧几里得公理}{Euclide}
    这是另一个定理。
\end{theorem}

\cref{thm:Euclide} 

\cref{thm:Euler,thm:Bachagoras}

\cref{thm:Euler,thm:Bachagoras,thm:Euclide}


\chapter{333}
\begin{definition}{Wong定义}{Wong}
    这是一个定义。
\end{definition}

\begin{definition}{Wang定义}{Wang}
    这是一个定义。
\end{definition}

\end{document}

这将得到:

image.png

Sagittarius Rover
Sagittarius Rover 22小时前
这家伙很懒,什么也没写!

基于zref-clever的一个处理方案...

目前最简便的方案还是需要修改elegantbook.cls...这对于已经frozen的项目是不友好的❗

一旦修改了.cls,则该模板已经不再是公开意义上的官方模板不能再被叫做「elegantbook模板」,而只能是「myelegantbook模板」,且模板的使用者必须对该模板的修改负完全责任❗❗❗

不太妥当的方案,将这里的这段代码修改为:

%   elegantbook.cls#L1001-L1016
    \DeclareTColorBox[auto counter,number within=\ELEGANT@thmcnt,usesamecnt,usecnt]{#1}{ g o t\label g }{
        common,#3,
        label type=#1,%<-add label type key here
        IfValueTF={##1}
          {ELEGANT@title={#1}{##1}}
          {
            IfValueTF={##2}
            {ELEGANT@title={#1}{##2}}
            {ELEGANT@title={#1}{}}
          },
        IfValueT={##4}
          {
            IfBooleanTF={##3}
              {label={##4}}
              {ELEGANT@label={#2}{##4}}
          }
      }

若如此做,对于下面的MWE文件main.tex

\documentclass[lang=cn,fontset=fandol]{elegantbook}
\geometry{paperheight=14cm}
\usepackage{zref-clever}
\zcRefTypeSetup{theorem}{
    Name-sg={定理},name-sg={定理},
    Name-pl={定理},name-pl={定理},
}
\zcRefTypeSetup{definition}{
    Name-sg={定义},name-sg={定义},
    Name-pl={定义},name-pl={定义},
}

\begin{document}
\chapter{111}

\begin{definition}{Wang定义}{Wang}
    这是一个定义。
\end{definition}

\begin{theorem}{欧拉定理}{Euler}
    这是一个定理。
\end{theorem}

\zcref{def:Osbert} 

\zcref{def:Wong}

\zcref{def:Wang}

\chapter{222}

\begin{definition}{Wong定义}{Wong}
    这是一个定义。
\end{definition}

\begin{definition}{Osbert定义}{Osbert}
    这是一个定义。
\end{definition}

\begin{theorem}{欧几里得公理}{Euclide}
    这是另一个定理。
\end{theorem}

\zcref{thm:Euler}

\zcref{thm:Euclide} 

\end{document}

将得到:

image.png

要想「不修改.cls文件」,关键在于在已经写死的\DeclareTColorBox{env}中,是否有简单的方法对每个env添加一个新的键值对...

不过要添加的label type恰好其值为#1,也不能说上面的实现是坏的。

Noted that:

  • tcolorbox在2023年才加入对zref-clever的支持
  • elegantbook已经在2022-12-31停止维护...

这个锅不太应该由本修改(改的不好)来背,算是「2025年」的今天需要为了一些版本更迭造成的时间摩擦付出一些小小的代价吧...如果有朝一日elegantbook能增加新的feature,本post也许可能提供些许帮助...

Hope it helps!

撰写答案

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

发布
问题

分享
好友

手机
浏览

扫码手机浏览