|
@@ -7,6 +7,7 @@ export const EPUB_THEME_KEY = "epub-theme";
|
|
|
export const EPUB_FONT_KEY = "epub-font";
|
|
|
export const EPUB_FONTSIZE_KEY = "epub-fontsize";
|
|
|
export const EPUB_SIMPLIFIED = "epub-simplified";
|
|
|
+export const EPUB_LOCATION = "epub-location";
|
|
|
|
|
|
export const useEpubStore = defineStore("epub", () => {
|
|
|
let bodyNode = null;
|
|
@@ -16,6 +17,10 @@ export const useEpubStore = defineStore("epub", () => {
|
|
|
*/
|
|
|
const rendition = ref(null);
|
|
|
/**
|
|
|
+ * 当前主题
|
|
|
+ */
|
|
|
+ const curTheme = ref(localStorage.getItem(EPUB_THEME_KEY) ?? THEMES[0].key);
|
|
|
+ /**
|
|
|
* 是否简体
|
|
|
*/
|
|
|
const isSimplified = ref(
|
|
@@ -23,14 +28,29 @@ export const useEpubStore = defineStore("epub", () => {
|
|
|
? Boolean(Number(localStorage.getItem(EPUB_SIMPLIFIED)))
|
|
|
: true
|
|
|
);
|
|
|
+ /**
|
|
|
+ * 目录
|
|
|
+ * @type { id: string;
|
|
|
+ * href: string;
|
|
|
+ * label: string;
|
|
|
+ * }[]
|
|
|
+ */
|
|
|
+ const navigation = ref([]);
|
|
|
+ const metadata = ref(null);
|
|
|
|
|
|
const init = (url) => {
|
|
|
+ initEpub(url);
|
|
|
+ initTheme();
|
|
|
+ goToChapter(localStorage.getItem(`${EPUB_LOCATION}-1`));
|
|
|
+ };
|
|
|
+
|
|
|
+ const initEpub = (url) => {
|
|
|
const _book = ePub(url);
|
|
|
const _rendition = _book.renderTo("reader", {
|
|
|
width: "100%",
|
|
|
height: "100%",
|
|
|
});
|
|
|
- console.log(_rendition);
|
|
|
+ console.log(_book, _rendition);
|
|
|
|
|
|
_rendition.hooks.render.register((v) => {
|
|
|
bodyNode = v.document.body;
|
|
@@ -39,14 +59,23 @@ export const useEpubStore = defineStore("epub", () => {
|
|
|
|
|
|
_book.loaded.metadata.then((res) => {
|
|
|
console.log("metadata: ", res);
|
|
|
+ metadata.value = res;
|
|
|
});
|
|
|
|
|
|
_book.loaded.navigation.then((res) => {
|
|
|
- console.log("navigation: ", res);
|
|
|
+ navigation.value = res.toc.map((item) => ({
|
|
|
+ ...item,
|
|
|
+ label: item.label.replace(/\s+/g, ""),
|
|
|
+ }));
|
|
|
});
|
|
|
|
|
|
+ book.value = _book;
|
|
|
+ rendition.value = _rendition;
|
|
|
+ };
|
|
|
+
|
|
|
+ const initTheme = () => {
|
|
|
THEMES.forEach((theme) => {
|
|
|
- _rendition.themes.register(theme.key, {
|
|
|
+ rendition.value.themes.register(theme.key, {
|
|
|
body: {
|
|
|
color: theme.textColor,
|
|
|
background: theme.color,
|
|
@@ -54,18 +83,16 @@ export const useEpubStore = defineStore("epub", () => {
|
|
|
});
|
|
|
});
|
|
|
|
|
|
- _rendition.themes.font(
|
|
|
+ rendition.value.themes.font(
|
|
|
localStorage.getItem(EPUB_FONT_KEY) ?? FONT_FAMILYS[0].value
|
|
|
);
|
|
|
|
|
|
- _rendition.themes.fontSize(
|
|
|
+ rendition.value.themes.fontSize(
|
|
|
(localStorage.getItem(EPUB_FONTSIZE_KEY) ?? EPUB_FONTSIZE_KEY[0].value) +
|
|
|
"px"
|
|
|
);
|
|
|
|
|
|
- _rendition.display();
|
|
|
- book.value = _book;
|
|
|
- rendition.value = _rendition;
|
|
|
+ toggleTheme(curTheme.value);
|
|
|
};
|
|
|
|
|
|
const convertText = (node = bodyNode) => {
|
|
@@ -78,6 +105,12 @@ export const useEpubStore = defineStore("epub", () => {
|
|
|
}
|
|
|
};
|
|
|
|
|
|
+ const refreshLocation = async () => {
|
|
|
+ const curLocation = rendition.value.currentLocation();
|
|
|
+ const startCfi = curLocation.start.cfi;
|
|
|
+ localStorage.setItem(`${EPUB_LOCATION}-1`, startCfi);
|
|
|
+ };
|
|
|
+
|
|
|
/**
|
|
|
* 简/繁体转换
|
|
|
*/
|
|
@@ -89,16 +122,17 @@ export const useEpubStore = defineStore("epub", () => {
|
|
|
|
|
|
/**
|
|
|
* 修改主题色
|
|
|
- * @param theme {String}
|
|
|
+ * @param {String} theme
|
|
|
*/
|
|
|
const toggleTheme = (theme) => {
|
|
|
rendition.value.themes.select(theme);
|
|
|
+ curTheme.value = theme;
|
|
|
localStorage.setItem(EPUB_THEME_KEY, theme);
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* 修改字体
|
|
|
- * @param font {String}
|
|
|
+ * @param {String} font
|
|
|
*/
|
|
|
const toggleFont = (font) => {
|
|
|
rendition.value.themes.font(font);
|
|
@@ -107,22 +141,67 @@ export const useEpubStore = defineStore("epub", () => {
|
|
|
|
|
|
/**
|
|
|
* 修改字体大小
|
|
|
- * @param size {String | Number}
|
|
|
+ * @param {String | Number} size
|
|
|
*/
|
|
|
const toggleFontSize = (size) => {
|
|
|
rendition.value.themes.fontSize(size + "px");
|
|
|
localStorage.setItem(EPUB_FONTSIZE_KEY, size);
|
|
|
};
|
|
|
|
|
|
+ /**
|
|
|
+ * 跳转目录
|
|
|
+ * @param {String} cfi
|
|
|
+ */
|
|
|
+ const goToChapter = (cfi) => {
|
|
|
+ rendition.value.display(cfi).then(() => {
|
|
|
+ refreshLocation();
|
|
|
+ });
|
|
|
+ };
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 搜索关键字
|
|
|
+ * @param {String} keyword
|
|
|
+ * @returns {Array}
|
|
|
+ */
|
|
|
+ const searchKeyword = async (keyword) => {
|
|
|
+ const res = await Promise.all(
|
|
|
+ book.value.spine.spineItems.map((section) =>
|
|
|
+ section
|
|
|
+ .load(book.value.load.bind(book.value))
|
|
|
+ .then(section.find.bind(section, keyword))
|
|
|
+ .finally(section.unload.bind(section))
|
|
|
+ )
|
|
|
+ );
|
|
|
+
|
|
|
+ return res.flat();
|
|
|
+ };
|
|
|
+
|
|
|
+ const prePage = () => {
|
|
|
+ rendition.value.prev().then(() => {
|
|
|
+ refreshLocation();
|
|
|
+ });
|
|
|
+ };
|
|
|
+ const nextPage = () => {
|
|
|
+ rendition.value.next().then(() => {
|
|
|
+ refreshLocation();
|
|
|
+ });
|
|
|
+ };
|
|
|
+
|
|
|
return {
|
|
|
book,
|
|
|
+ curTheme,
|
|
|
rendition,
|
|
|
isSimplified,
|
|
|
+ navigation,
|
|
|
init,
|
|
|
convertText,
|
|
|
toggleText,
|
|
|
toggleTheme,
|
|
|
toggleFont,
|
|
|
toggleFontSize,
|
|
|
+ goToChapter,
|
|
|
+ searchKeyword,
|
|
|
+ prePage,
|
|
|
+ nextPage,
|
|
|
};
|
|
|
});
|