在数字出版领域,EPUB 是一种广泛使用的电子书格式,支持多种设备和平台。为了方便地在网页中嵌入 EPUB 电子书阅读功能,我们可以使用开源库 epub.js 来快速构建一个功能齐全的阅读器。本文将介绍如何使用 HTML、CSS 和 JavaScript 搭建一个基础的 EPUB 阅读器。
效果演示
项目概述
本项目主要包含以下主要功能:
- 加载并展示 EPUB 文件
- 支持上一页 / 下一页翻页操作
- 显示书籍目录(TOC)
- 记录阅读进度
准备工作
准备一本 EPUB 格式的电子书文件,并将其放置在项目根目录下供加载使用。
引入必要的依赖文件,其中 jszip 是处理 EPUB 文件(本质上是 ZIP 压缩包)所必需的,epub.js 是主库文件,提供了完整的 EPUB 解析与渲染能力。
epub.js下载地址:github.com/futurepress…
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.1.5/jszip.min.js"></script>
<script src="./epub.js"></script>
页面结构与样式设计
创建 HTML 结构
<div class="controls">
<button onclick="toggleTOC()">目录</button>
<button onclick="prevPage()">上一页</button>
<button onclick="nextPage()">下一页</button>
</div>
<div id="toc-panel"></div>
<div id="viewer"></div>
<div class="progress" id="progress"></div>
设计 CSS 样式
body {
margin: 0;
padding: 20px;
font-family: Arial, sans-serif;
background-color: #f5f5f5;
transition: background-color 0.3s;
}
#viewer {
width: 90%;
height: 80vh;
margin: 20px auto;
box-shadow: 0 0 10px rgba(0,0,0,0.2);
background: white;
}
.controls {
display: flex;
gap: 10px;
justify-content: center;
margin: 20px 0;
}
button {
padding: 8px 16px;
cursor: pointer;
background: #007bff;
color: white;
border: none;
border-radius: 4px;
transition: background 0.3s;
}
button:hover {
background: #0056b3;
}
.progress {
text-align: center;
color: #666;
}
#toc-panel {
position: fixed;
left: -300px;
top: 0;
width: 280px;
height: 100vh;
background: white;
box-shadow: 2px 0 5px rgba(0,0,0,0.1);
transition: left 0.3s;
padding: 20px;
overflow-y: auto;
z-index: 10;
}
.toc-visible #toc-panel {
left: 0;
}
核心功能实现
初始化阅读器
let book;
let rendition;
let currentLocation;
function initReader(epubFile) {
if (rendition) rendition.destroy();
book = ePub(epubFile);
rendition = book.renderTo("viewer", {
width: "100%",
height: "100%",
spread: "auto"
});
book.ready
.then(() => book.locations.generate(1600))
.then(() => {
// 加载进度
const savedPosition = localStorage.getItem('epubProgress');
rendition.display(savedPosition || 0);
updateTOC();
})
.catch(error => console.error("EPUB初始化失败:", error));
// 初始化设置
rendition.themes.default({
body: { color: "inherit", background: "inherit" }
});
// 注册事件监听
rendition.on("locationChanged", updateProgress);
rendition.on("keyup", e => (e.key === "ArrowLeft") && prevPage());
rendition.on("keyup", e => (e.key === "ArrowRight") && nextPage());
}
更新阅读进度
function updateProgress(location) {
currentLocation = location.start;
const percentage = (location.percentage * 100).toFixed(1);
document.getElementById("progress").textContent = `进度:${percentage}%`;
localStorage.setItem('epubProgress', currentLocation);
}
翻页控制
function prevPage() {
rendition.prev();
}
function nextPage() {
rendition.next();
}
目录控制
function toggleTOC() {
document.body.classList.toggle("toc-visible");
}
生成目录
async function updateTOC() {
const toc = await book.loaded.navigation;
const tocPanel = document.getElementById("toc-panel");
tocPanel.innerHTML = "<h3>目录</h3>";
toc.forEach(chapter => {
const item = document.createElement("div");
item.style.padding = "5px 10px";
item.style.cursor = "pointer";
item.textContent = chapter.label;
item.onclick = () => {
rendition.display(chapter.href);
toggleTOC();
};
tocPanel.appendChild(item);
});
}
完整代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>EPUB电子书阅读器</title>
<style>
body {
margin: 0;
padding: 20px;
font-family: Arial, sans-serif;
background-color: #f5f5f5;
transition: background-color 0.3s;
}
#viewer {
width: 90%;
height: 80vh;
margin: 20px auto;
box-shadow: 0 0 10px rgba(0,0,0,0.2);
background: white;
}
.controls {
display: flex;
gap: 10px;
justify-content: center;
margin: 20px 0;
}
button {
padding: 8px 16px;
cursor: pointer;
background: #007bff;
color: white;
border: none;
border-radius: 4px;
transition: background 0.3s;
}
button:hover {
background: #0056b3;
}
.progress {
text-align: center;
color: #666;
}
#toc-panel {
position: fixed;
left: -300px;
top: 0;
width: 280px;
height: 100vh;
background: white;
box-shadow: 2px 0 5px rgba(0,0,0,0.1);
transition: left 0.3s;
padding: 20px;
overflow-y: auto;
z-index: 10;
}
.toc-visible #toc-panel {
left: 0;
}
</style>
</head>
<body>
<div class="controls">
<button onclick="toggleTOC()">目录</button>
<button onclick="prevPage()">上一页</button>
<button onclick="nextPage()">下一页</button>
</div>
<div id="toc-panel"></div>
<div id="viewer"></div>
<div class="progress" id="progress"></div>
<!-- 引入epub.js库 -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.1.5/jszip.min.js"></script>
<script src="./epub.js"></script>
<script>
let book;
let rendition;
let currentLocation;
// 初始化阅读器
function initReader(epubFile) {
if (rendition) rendition.destroy();
book = ePub(epubFile);
rendition = book.renderTo("viewer", {
width: "100%",
height: "100%",
spread: "auto"
});
book.ready
.then(() => book.locations.generate(1600))
.then(() => {
// 加载进度
const savedPosition = localStorage.getItem('epubProgress');
rendition.display(savedPosition || 0);
updateTOC();
})
.catch(error => console.error("EPUB初始化失败:", error));
// 初始化设置
rendition.themes.default({
body: { color: "inherit", background: "inherit" }
});
// 注册事件监听
rendition.on("locationChanged", updateProgress);
rendition.on("keyup", e => (e.key === "ArrowLeft") && prevPage());
rendition.on("keyup", e => (e.key === "ArrowRight") && nextPage());
}
// 更新阅读进度
function updateProgress(location) {
currentLocation = location.start;
const percentage = (location.percentage * 100).toFixed(1);
document.getElementById("progress").textContent = `进度:${percentage}%`;
localStorage.setItem('epubProgress', currentLocation);
}
// 翻页控制
function prevPage() {
rendition.prev();
}
function nextPage() {
rendition.next();
}
// 目录控制
function toggleTOC() {
document.body.classList.toggle("toc-visible");
}
// 生成目录
async function updateTOC() {
const toc = await book.loaded.navigation;
const tocPanel = document.getElementById("toc-panel");
tocPanel.innerHTML = "<h3>目录</h3>";
toc.forEach(chapter => {
const item = document.createElement("div");
item.style.padding = "5px 10px";
item.style.cursor = "pointer";
item.textContent = chapter.label;
item.onclick = () => {
rendition.display(chapter.href);
toggleTOC();
};
tocPanel.appendChild(item);
});
}
// 初始化示例书籍
initReader("./demo.epub"); // 替换为实际EPUB路径
</script>
</body>
</html>