ReedenReeden
阅读与排版内容编辑

EPUB 模板写法速查

EPUB 编辑器片段模板能写的全部内容:片段源码、样式、占位符和取值方式、查找规则,以及「用 AI 写模板」从剪贴板导入用的 JSON 格式。

适用版本:Reeden 2.0.0 及以上。这里没列出的写法不支持。

片段模板是一段带占位符的 HTML,加上它自己的样式。在 EPUB 编辑器里可以插入到光标处、套到选中的几段上,或者按查找规则批量套到全书。

用 AI 写模板

  1. 打开 EPUB 编辑器的模板库,点右上角的菜单,选「用 AI 写模板」,提示词会复制到剪贴板。
  2. 把提示词发给任意 AI 助手,在末尾写上想要的样式,比如「网友评论卡片,头像、昵称、楼层号和时间排一行,下面是评论内容;昵称从几个网名里随机,楼层从 3 楼开始往上加」。
  3. 复制 AI 的完整回复,回到模板库菜单,选「从剪贴板导入」。
  4. 导入前会列出每个模板的效果预览。有错误的模板不能勾选,有提示的可以照常导入。

1. 导入格式

从剪贴板导入时,内容是一个 JSON 对象(可以包在 ```json 代码块里):

{
  "reedenTemplates": 1,
  "templates": [
    {
      "name": "模板名",
      "html": "<div class=\"rd-card\"><p>{{正文}}</p></div>",
      "css": ".rd-card { border: 1px solid #ccc; }",
      "fields": [
        { "id": "正文", "isBody": true }
      ]
    }
  ]
}

每个模板的字段:

字段必填说明
name是模板名,简短说清用途
html是片段源码,见第 2 节
css否样式,见第 3 节
fields否占位符的设置,见第 4 节。不写时按源码里的占位符自动生成
rule否查找规则,见第 6 节。不写表示只能手动插入或套用

一次可以导入多个模板。名字、源码和样式都相同的模板已经存在时跳过。

2. 片段源码(html 字段)

  • 写成 XHTML:标签必须配对闭合,空元素写成 <br/>、<img .../>,属性值加引号。
  • 用 {{名字}} 标出要填的内容。名字可以是中文,它同时是填写表单里的标签。
  • 结构只写 class,样式放在 css 里,不要写 style="…"、<style>。
  • 不能有 <script>,也不要引用书外的图片、字体或链接。需要图形时用边框、背景色、圆角这些 CSS 画;确实要用图片、音频,在模板编辑框里加「资源」,见下文 模板带图片和音频。
  • 最外层只放一个元素(比如一个 <div>)。套用时会给它加一个用来识别的 class,不影响样式。
  • 正文占位符只写一处。想让几条内容样式各不相同,模板里只写一条,在样式里用 .名字 + .名字 区分第 2、3 条(见第 7 节)。
  • JSON 里的双引号要转义:class="x" 写成 class=\"x\"。

3. 样式(css 字段)

  • 普通 CSS 规则,套用时写进书里的 reeden-custom.css,同一个模板套多少处都只有一份。
  • class 名加一个前缀(比如 rd-),避免和书里原有的样式重名。
  • 选择器写成 .rd-card .rd-title 这样,限定在模板自己的元素里,不要写 p { }、div { } 这种会影响全书的规则。
  • 尺寸用 em,跟着阅读字号缩放;不要写死很大的 px 宽度,手机上一行只有 18–20 个字。
  • 颜色写具体的值(#c8336a、rgba(0, 0, 0, 0.06))。浅色背景用半透明,深色主题下也不会太亮。
  • 能用的:边框、圆角、背景色和渐变、内外边距、字体字号颜色、行高、text-indent、display: block / inline-block、float、::before / ::after 和 content、计数器、box-shadow。
  • 不要用:grid、position: fixed、动画、@import、@font-face。flex 在 Reeden 里能用,但部分阅读器不支持,书要拿到别的阅读器看时优先用 inline-block 和 float。
  • 段落默认有首行缩进,卡片里的段落一般要写 text-indent: 0。

4. 占位符(fields 字段)

每个占位符一项,id 和源码里 {{}} 中的名字一致:

字段说明
id占位符名字
label填写表单里显示的名字,不写时用 id
default预填值
isBody正文占位符:套到选中段落时放段落内容。一个模板只设一个
multiline填写时允许多行
value取值方式,见第 5 节。不写就是固定值,每条都填 default

没写 isBody 时,叫 body 的占位符、或者第一个名字里带「正文」「内容」的占位符会当作正文。

5. 取值方式(value 字段)

套到几段上、或者按规则套到全书时,每条现算一个值,适合评论区的昵称、楼层号这类每条不一样的内容。算出来的值作为普通文字写进书里。

{ "id": "昵称", "value": { "mode": "pick", "choices": ["路人甲", "匿名网友", "吃瓜群众"] } }
{ "id": "楼层", "value": { "mode": "sequence", "start": 3, "stepMin": 1, "stepMax": 8 } }
{ "id": "点赞", "value": { "mode": "number", "min": 1, "max": 999 } }
mode设置效果
pickchoices:候选列表;noRepeat:相邻两条不重复,默认 true每条从候选里挑一个
sequencestart:起始值;stepMin、stepMax:每次加多少第一条是起始值,之后每条加一个范围里的随机数。两个数相同就是固定步长
numbermin、max每条取范围里的一个整数
  • 数字只填数字本身,前后的符号写在源码里:楼层写成 #{{楼层}}、{{楼层}} 楼。
  • 每次套用从起始值重新数;按规则套到全书时每章各自从起始值数。
  • 正文占位符不能设取值方式。

6. 查找规则(rule 字段)

按正则在章节源码里找,找到的每一处都套一次模板:

"rule": { "pattern": "<p>【(?<text>[^】]*)】</p>", "mode": "replace", "firstMatchOnly": false }
字段说明
pattern正则,匹配章节的 HTML 源码(不是纯文字)。. 能跨行,不区分大小写
modereplace(默认,替换找到的内容)、insertBefore(插到前面)、insertAfter(插到后面)
firstMatchOnly每章只处理第一处,默认 false
  • 在占位符的 default 里写 $1、$text 引用捕获到的内容,比如正文的 default 写 "$text"。
  • JSON 里的反斜杠要转义:\s 写成 "\\s"。
  • 一段一段地匹配(<p>…</p>),不要写能跨很多段的贪婪匹配。

7. 示例

网友评论:昵称随机、楼层递增,几条连着的评论用 + 选择器换颜色。

{
  "reedenTemplates": 1,
  "templates": [
    {
      "name": "网友评论",
      "html": "<div class=\"rd-cmt\"><p class=\"rd-cmt-head\"><span class=\"rd-cmt-name\">{{昵称}}</span><span class=\"rd-cmt-meta\">#{{楼层}} · {{时间}}</span></p><p class=\"rd-cmt-body\">{{正文}}</p></div>",
      "css": ".rd-cmt { margin: 0.4em 0; padding: 0.5em 0.9em; border: 1px solid rgba(127, 127, 127, 0.25); border-radius: 10px; background-color: rgba(59, 130, 246, 0.06); }\n.rd-cmt + .rd-cmt { background-color: rgba(236, 72, 153, 0.06); }\n.rd-cmt + .rd-cmt + .rd-cmt { background-color: rgba(34, 197, 94, 0.06); }\n.rd-cmt p { text-indent: 0; margin: 0; }\n.rd-cmt-head { font-size: 0.85em; }\n.rd-cmt-name { font-weight: bold; }\n.rd-cmt-meta { float: right; color: rgba(127, 127, 127, 0.9); }\n.rd-cmt-body { margin-top: 0.3em; line-height: 1.6; }",
      "fields": [
        { "id": "正文", "isBody": true },
        { "id": "昵称", "value": { "mode": "pick", "choices": ["路人甲", "匿名网友", "吃瓜群众", "深夜潜水员"] } },
        { "id": "楼层", "value": { "mode": "sequence", "start": 3, "stepMin": 1, "stepMax": 8 } },
        { "id": "时间", "value": { "mode": "pick", "choices": ["刚刚", "1 分钟前", "3 分钟前"] } }
      ]
    },
    {
      "name": "作者有话说",
      "html": "<div class=\"rd-note\"><p class=\"rd-note-title\">{{标题}}</p><p class=\"rd-note-body\">{{正文}}</p></div>",
      "css": ".rd-note { margin: 1.2em 0; padding: 0.7em 1em; border: 1px dashed rgba(127, 127, 127, 0.5); border-radius: 8px; }\n.rd-note p { text-indent: 0; margin: 0; }\n.rd-note-title { font-weight: bold; font-size: 0.9em; margin-bottom: 0.4em; }",
      "fields": [
        { "id": "标题", "default": "作者有话说" },
        { "id": "正文", "isBody": true, "default": "$note" }
      ],
      "rule": { "pattern": "<p\\b[^>]*>\\s*作者有话说[::]\\s*(?<note>[^<]*)</p>" }
    }
  ]
}

模板带图片和音频

AI 写的模板和剪贴板导入只能写源码和样式。需要图片、音频时,导入后在模板库里打开这个模板的编辑框,在「资源」里「添加文件」:

  • 在源码或样式里用 local:/ 引用,/ 指书的 OPF 所在目录,比如 <img src="local:/Images/star.png"/>、<audio src="local:/Audio/bell.mp3"></audio>、background: url(local:/Images/bg.png)。每个文件旁边的复制按钮可以直接拿到写法,「修改路径」改它在书里的位置
  • 套用模板时,书里没有这个文件就写进去,同路径已有就用书里那份;引用会换成相对路径
  • 单个文件不超过 2 MB,一个模板合计不超过 5 MB。没被引用的文件会标「未引用」

8. 常见错误

  • 标签没闭合(<br>、<img ...>),导入时报「标签没有配对闭合」。
  • 正文占位符写了好几处,套用时只有第一处有内容。
  • 样式写在 style="…" 或 <style> 里,换模板、改样式都要一处处改。
  • 选择器没加前缀(.card、p),和书里原有的样式互相影响。
  • 宽度写死成 px,手机上挤成一列或者超出屏幕。