uniapp开发epub阅读器保姆级教程

时间:2025-01-28 08:42:38

前言

阅读器的基本功能:翻页、字体大小设置、切换背景主题色、进度条功能、目录与跳转、添加书签、获取电子书信息、获取当前章节总页码和页数等

功能的实现

 1.引入epubjs

使用命令安装0.3.71版本 epubjs

npm i epubjs@0.3.71

注:这里之前踩过坑,其他版本进行切换主题时,每一个背景颜色只能切换一次,再次选择其他主题不生效。

解决方法:将版本更换到 0.3.71

2.为电子书准备容器

添加一个 id read view 标签。

<view  />

3.渲染电子书

onLoad 生命周期中对电子书进行渲染。

通过 new 一个 Epub 对电子书进行初始化解析,生成 book

onLoad() {
    ();
},

methods:{
    showEpub(){
        // 对电子书进行初始化解析,路径可以是相对路径或者绝对路径
         = new Epub("/cloudstorage/"
       );
    }
}

有了电子书的路径后,对电子书进行渲染。

  •  book 通过 renderTo 方法对电子书进行渲染,生成 rendition 对象。
  •  renderTo 有两个参数:第一个参数是 view 标签的 id ,将生成的 dom 挂在该 id 的容器上;第二个参数是用来指定电子书的样式和属性,包括宽高,翻页方式等。
  •  rendition 再通过 display 方法渲染完成, display 支持两种参数:①章节目录中的 href 链接,可以跳转至指定章节;② cfi 值,为 epubcfi 规范的一个值,不用细究他的构成,能获取到就行。 display 后面不传参数时默认为 0 ,渲染到首页。
showEpub(){
    // 通过new一个Epub对电子书进行初始化解析,生成book,路径可以是相对路径或者绝对路径
     = new Epub("/cloudstorage/");

    // book通过renderTo方法对电子书进行渲染,生成rendition对象
     = ("read",{
        allowScriptedContent: true,
        snap: true,
        restore: false,
        width: "100vw",
        height: "100vh",
        manager: "continuous",
        spread: "none",
        flow:
           === 0
            ? "scrolled-doc"
            :  === 1
            ? "paginated"
            : "", //scrolled-doc滚动 paginated分页
    })   

    // 通过display方法进行渲染
    ()
}

4.翻页功能

此处为点击翻页功能,可以为点击屏幕左侧 25% ,或者点击屏幕右侧 25% 进行翻上一页和下一页操作。

翻页方法是异步的,会返回一个 promise ,进行后续的操作。

// 上一页
prevPage() {
    if () {
        ().then(() => {
          // 其他逻辑代码
        });
    }
},

// 下一页
nextPage() {
    if () {
        ().then(() => {
          // 其他逻辑代码
        });
    }
},

5.字体大小设置

定义一个 theme ,通过 rendition 中的 Theme 对象属性进行字号主题等功能设置。

在这里可以用一个进度条控件,动态设置 fontsize 大小,并且保存到缓存中,以便下次进入电子书时获取字体大小。字体大小单位为 "px"

 = 
( + "px")

 6.切换背景主题色

与字体大小设置一样,切换主题时用的也是 theme 对象属性。

通过 () 为电子书添加主题,通过 (name) 选择已经添加好的主题。

// data中定义好主题数组
themeList:[
    {
        name: "default", // 主题名字
        style: { // 主题样式
            body: {
              color: "#494948", // 文字颜色
              background: "#F4F3EF", // 背景颜色
              lineColor: "#E4E3DF", // 主题中并无该属性,该属性为自定义目录下划线颜色
            },
        },
    },
    {
        name: "twoTheme",
        style: {
            body: {
              color: "#39342B",
              background: "#D5C6A9",
              lineColor: "#C6B89B",
            },
        },
    },
    {
        name: "threeTheme",
        style: {
            body: {
              color: "#94938F",
              background: "#3A3031",
              lineColor: "#3F3939",
            },
        },
    },
    {
        name: "fourTheme",
        style: {
            body: {
              color: "#313635",
              background: "#CCE8D1",
              lineColor: "#BCD8C1",
            },
        },
    },
    {
        name: "fiveTheme",
        style: {
            body: {
              color: "rgb(100,110,119)",
              background: "#051827",
              lineColor: "#0C1E2D",
            },
        },
    },
]


methods:{
    // 渲染电子书后调用
    registerTheme() {
      ((item) => {
        (, );
      });
    },
    // 触发改变电子书背景主题时调用
    setTheme(index) {
      ([index].name);
    },
}

7.进度条功能

  1. 进度条功能需要获取 locations 对象,由于 locations 对象的生成比较消耗性能,所以默认是不会生成 locations 对象的。
  2. 通过 epubjs 的钩子函数来实现。借助 book 解析完成之后回调的 ready 方法来生成。
  3. 通过 book () 方法获取当前百分比所对应的 epubcfi ,通过 (epubcfi) 渲染即可跳到相应位置。

注:在进度条可操作之前,必须是分页执行完之后得到 location 对象才可对进度条进行操作。(可添加一标识,判断 locations 对象是否得到,未得到时提示进度条加载中,完成后显示在操作)。

showEpub(){
    // 通过new一个Epub对电子书进行初始化解析,生成book,路径可以是相对路径或者绝对路径
     = new Epub("/cloudstorage/");

    // book通过renderTo方法对电子书进行渲染,生成rendition对象
     = ("read",{
        allowScriptedContent: true,
        snap: true,
        restore: false,
        width: "100vw",
        height: "100vh",
        manager: "continuous",
        spread: "none",
        flow:
           === 0
            ? "scrolled-doc"
            :  === 1
            ? "paginated"
            : "", //scrolled-doc滚动 paginated分页
    })   

    // 通过display方法进行渲染
    ()

    
        .then(() => {
          return ();
        })
        .then((result) => {
          // result为book生成电子书的cfi的一个数组。与下面中的_locations属性一致
           = ;
          ("locations", );
          // bookAvailable标识,默认为false,为true时代表进度条可操作
           = true;
        })
}

调整进度条跳转至对应页面。

onProgressChange(e) {
    // e为进度条保留两位小数点的数字
    const percentage = e / 100;
    // location为根据进度生成的cfi值
    const location =
        percentage > 0 ? (percentage) : 0;
    ("location", location);
    (location);
},

8.目录与跳转

  1. 通过 book navigation 对象,可以获取到电子书的目录。
  2. 通过 epubjs 的钩子函数来实现。借助 book 解析完成之后回调的 ready 方法来生成。
  3. 由于目录为一个 tree 类型,所以页面上需用 tree 组件来渲染。

    .then(() => {
         = ;
        // toc为总目录,目录可分级
         = ;
        return ();
     })
     .then((result) => {
          // result为book生成电子书的cfi的一个数组。与下面中的_locations属性一致
           = ;
          ("locations", );
          // bookAvailable标识,默认为false,为true时代表进度条可操作
           = true;
      })

  表示电子书的目录结构,是一个数组, toc 下的每一个元素对应一个目录, toc[n].href 表示目录路径(链接), toc[n].label 是当前目录的名字, toc[n].subitems 里面包含的是该目录下还有其他的二级(三级)目录,可根据需要使用几级目录。

获取到目录后,可以通过点击树组件中的章节获取到该章节对应的数据( toc 数组中某一项),再根据该项中的 href 属性进行跳转。

jumpTo(item){
    ()
}

9.添加书签

添加书签功能需要使用到 rendition 对象中的 currentLocation 方法。

  为当前页的 cfi 值,可根据该 cfi 值进行跳转。

// 获取当前页cfi值并保存到数组中
handleMark() {
    const currentLocation = ();
    ();
},
// 点击,根据cfi值跳转
toMark(cfi) {
    (cfi)
},

 10.获取电子书信息

通过 book 中的 package 对象获取电子书信息:

  •  manifest 用来获取电子书的所有用到的文件信息;
  •  metadata 用来获取电子书的出版信息,其中 titile 为电子书的名字;
  •  ncxPath 为目录的路径;
  •  spine 为阅读顺序。
((meta) => {
    ("meta", meta);
    = meta;
});

11.获取当前章节页码和总页数

获取当前章节页码和总页数与添加书签功能一样需要用到 rendition 对象中的 currentLocation 方法。

total:当前章节总页数;

page:当前页在当前章节页码。

showPage(page) {
    const currentLocation = ();
    ("当前位置", {
        ...,
    });
     = {
        total: page?.total || ,
        page: page?.page || ,
    };
},

总结

以上就完成了基于 epubjs 开发的基本的阅读器功能,样式和点击事件部分可以由各位根据需求来添加,如有问题和错误之处欢迎指出~

有宝子说 URL 未定义报错,我这里看了一下,可以通过使用 fetch 获取资源,然后将其转为 Blob 对象再使用。

 = "/cloudstorage/";
const blob = await fetch().then((res) => ());
 = new Epub(blob);