在main.js中引入
$ import "./assets/styles/icon.css"
$ npm install --save epubjs
**在这里需要注意的是,有两种方法引入文本字体,一种是上述所示的方法,另一种是把fonts放到assets中,这时,就不能在index.html中引入,而应该在main 中以import的形式引入
**
在index.html中
在App.vue中编写script代码
在main中引入
import “./assets/styles/global.scss”
下载方法,及使用方法可参考 博客一文
,主要的命令 就是结束 nginx -s stop;接下来,在D盘的根目录下创建资源文件夹 resource
,然后修改 nginx.conf文件
添加这段代码,自起一个服务端口
server {
listen 8081;
server_name resource;
root D:/resource;
autoindex on;
location / {
add_header Access-Control-Allow-Origin *;
}
add_header Cache-Control "no-cache,must-revalidate";
}
主要技术难点
把epub文件夹(放有所有epub电子书的文件夹)放到resource当中
由于访问资源每一本书的url是 http://localhost:8080/#/ebook/education/202yalishanda
这种方式,可见要用动态路由的方式来访问资源
什么是动态路由?听我说来
这种就是动态路由
,然后我们在浏览器上输入
http://localhost:8080/#/ebook/asasd
在EBook Reader中
{{$route.params.fileName}}
到了这这里想要获取nginx上的电子书时出现了跨域问题,暂时解决不了,先用 本地资源
当屏幕向左划时,向上翻页,反之翻下一页。
//监听滑动翻页事件
this.rendition.on("touchstart",event=>{
this.touchStartX = event.changedTouches[0].clientX;
this.touchStartTime = event.timeStamp;
});
this.rendition.on("touchend",event=>{
const offsetX = event.changedTouches[0].clientX-this.touchStartX;
const time = event.timeStamp - this.touchStartTime;
if(time<500 && offsetX>40){
this.prevPage();
}else if (time<500 && offsetX<-40) {
this.nextPage();
}else{
this.toggleTitleAndMenu()
}
})
prevPage(){
if (this.rendition){
this.rendition.prev();
// this.$store.dispatch("setMenuVisible",false)
this.setMenuVisible(false);
}
},
nextPage(){
if (this.rendition){
this.rendition.next();
// this.$store.dispatch("setMenuVisible",false)
this.setMenuVisible(false);
}
},
在这里,值得注意的一点,需要修改epubjs的版本,修改为 “epubjs”: “0.3.71”,因为0.38以上的都不支持滑动
先创建标题栏和菜单栏组件
//EbookTitle
<template>
<transition name="slide-down">
<div class="title-wrapper" v-show="menuVisible">
<div class="left">
<span class="icon-back">span>
div>
<div class="right">
<div class="icon-wrapper">
<span class="icon-book">span>
div>
<div class="icon-wrapper">
<span class="icon-cart">span>
div>
<div class="icon-wrapper">
<span class="icon-more">span>
div>
div>
div>
transition>
template>
<script>
// import {mapGetters} from "vuex"
import { ebookMixin } from "./../../utils/mixin"
export default {
name: "EbookTitle",
mixins:[ebookMixin],
// computed:{
// ...mapGetters(["menuVisible"])
// }
}
script>
<style lang='scss' scoped>
@import './../../assets/styles/global';
.title-wrapper {
position: absolute;
top: 0;
left: 0;
z-index: 101;
display: flex;
width: 100%;
height: px2rem(48);
background: white;
box-shadow: 0 px2rem(8) px2rem(8) rgba(0, 0, 0, .15);
font-size: px2rem(20);
.left {
flex: 0 0 px2rem(60);
@include center;
}
.right {
flex: 1;
display: flex;
justify-content: flex-end;
.icon-wrapper {
flex: 0 0 px2rem(40);
@include center;
.icon-cart {
font-size: px2rem(22);
}
}
}
}
style>
//EbookMenu
<template>
<div>
<transition name="slide-up">
<div class="menu-wrapper" :class="{'hide-box-shadow':!menuVisible}" v-show="menuVisible">
<div class="icon-wrapper">
<span class="icon-menu icon" @click="showSetting(3)">span>
div>
<div class="icon-wrapper">
<span class="icon-progress icon" @click="showSetting(2)">span>
div>
<div class="icon-wrapper">
<span class="icon-bright icon" @click="showSetting(1)">span>
div>
<div class="icon-wrapper">
<span class="icon-a icon" @click="showSetting(0)">Aspan>
div>
div>
transition>
div>
template>
<script>
// import {mapGetters} from "vuex";
import { ebookMixin } from "../../utils/mixin.js"
export default {
name: "EbookMenu",
mixins:[ebookMixin],
// computed:{
// ...mapGetters(["menuVisible"])
// },
methods:{
showSetting(){
}
}
}
script>
<style lang='scss' scoped>
@import './../../assets/styles/global';
.menu-wrapper {
position: absolute;
bottom: 0;
left: 0;
z-index: 102;
display: flex;
width: 100%;
height: px2rem(48);
background: white;
box-shadow: 0 px2rem(-8) px2rem(8) rgba(0, 0, 0, .15);
font-size: px2rem(20);
&.hide-box-shadow {
box-shadow: none;
}
.icon-wrapper {
flex: 1;
@include center;
.icon-progress {
font-size: px2rem(28);
}
.icon-bright {
font-size: px2rem(24);
}
}
}
style>
用 menuvisible来控制标题栏和菜单栏是否显示
。
到这里,容易发现
methods:{
...mapActions(['setMenuVisible','setFileName']),
}
这里再很多组件中都是共有的,这样,可以把这些共有的放在一起,在通过vue的一个勾子mixins 调用出来
<template>
<transition name="slide-up">
<div class="setting-wrapper" v-show="menuVisible && settingVisible===0">
<div class="setting-font-size">
<div class="preview" :style="{fontSize: fontSizeList[0].fontSize + 'px'}">Adiv>
<div class="select">
<div class="select-wrapper" v-for="(item, index) in fontSizeList" :key="index" @click="setFontSize(item.fontSize)">
<div class="line">div>
<div class="point-wrapper">
<div class="point" v-show="defaultFontSize === item.fontSize">
<div class="small-point">div>
div>
div>
<div class="line">div>
div>
div>
<div class="preview" :style="{fontSize: fontSizeList[fontSizeList.length - 1].fontSize + 'px'}">Adiv>
div>
div>
transition>
template>
<script>
import {ebookMixin} from "./../../utils/mixin"
import {FONT_SIZE_LIST} from "./../../utils/book"
export default {
name: "EbookSettingFont",
mixins:[ebookMixin],
data(){
return{
fontSizeList:FONT_SIZE_LIST,
}
},
methods:{
setFontSize(fontSize){
this.setDefaultFontSize(fontSize);
this.currentBook.rendition.themes.fontSize(fontSize);
}
}
}
script>
<style lang="scss" rel="stylesheet/scss" scoped>
@import "../../assets/styles/global";
div{
/*width: 100%;*/
/*height: 200px;*/
/*margin-top: 100px;*/
/*margin-bottom: 0px;*/
/*z-index: 999;*/
/*background-color: red;*/
}
.setting-wrapper {
background-color: #fff;
position: absolute;
bottom: px2rem(48);
left: 0;
z-index: 190;
display: flex;
flex-direction: column;
width: 100%;
height: px2rem(90);
box-shadow: 0 px2rem(-8) px2rem(8) rgba(0, 0, 0, .15);
.setting-font-size {
flex: 2;
display: flex;
height: 100%;
.preview {
flex: 0 0 px2rem(40);
@include center;
}
.select {
display: flex;
flex: 1;
.select-wrapper {
flex: 1;
display: flex;
align-items: center;
&:first-child {
.line {
&:first-child {
border-top: none;
}
}
}
&:last-child {
.line {
&:last-child {
border-top: none;
}
}
}
.line {
flex: 1;
height: 0;
border-bottom: 1px solid #000;
}
.point-wrapper {
position: relative;
flex: 0 0 0;
width: 0;
height: px2rem(7);
.point {
background-color: lightpink;
position: absolute;
top: px2rem(-8);
left: px2rem(-10);
width: px2rem(20);
height: px2rem(20);
border-radius: 50%;
box-shadow: 0 px2rem(4) px2rem(4) rgba(0, 0, 0, .15);
@include center;
.small-point {
width: px2rem(5);
height: px2rem(5);
border-radius: 50%;
}
}
}
}
}
}
.setting-font-family {
flex: 1;
font-size: px2rem(14);
@include center;
.setting-font-family-text-wrapper {
@include center;
}
.setting-font-family-icon-wrapper {
@include center;
}
}
}
style>
通过更改 defautFontSize来更改字体大小
defautFontSize 选
export const FONT_SIZE_LIST =[
{fontSize:12},
{fontSize:14},
{fontSize:16},
{fontSize:18},
{fontSize:20},
{fontSize:22},
{fontSize:24},
];
之中的一个值
设置电子书的字号如下实现
setFontSize(fontSize){
this.setDefaultFontSize(fontSize);
this.currentBook.rendition.themes.fontSize(fontSize);
}
在字号设置界面当中,我们把 这整个wrapper的布局设置为flex,上面flex:2,下面flex:1
分为两部分,这部分较大的难题,就是使选中部分高亮+√
<template>
<transition name="popup-slide-up">
<div class="ebook-popup-list" v-show="fontFamilyVisible">
<div class="ebook-popup-title">
<div class="ebook-popup-title-icon">
<span class="icon-down2">span>
div>
<span class="ebook-popup-title-text">选择字体span>
div>
<div class="ebook-popup-list-wrapper">
<div class="ebook-popup-item" v-for="(item,index) in fontFamilyList" :key="index">
<div class="ebook-popup-item-text" :class="{'selected':isSelected(item)}">{{item.font}}div>
<div class="ebook-popup-item-check" v-if="isSelected(item)">
<span class="icon-check">span>
div>
div>
div>
div>
transition>
template>
<script>
import {ebookMixin} from "./../../utils/mixin"
import {FONT_FAMILY} from "./../../utils/book"
export default {
name: "EbookSettingFontPopup",
mixins:[ebookMixin],
data(){
return{
fontFamilyList:FONT_FAMILY
}
},
methods:{
isSelected(item){
return this.defaultFontFamily===item.font;
}
}
}
script>
<style lang="scss" rel="stylesheet/scss" scoped>
@import "../../assets/styles/global";
.ebook-popup-list{
position: absolute;
bottom: 0;
left: 0;
z-index: 300;
width: 100%;
/*background-color: red;*/
background-color: white;
box-shadow: 0 px2rem(-4) px2rem(6) rgba(0,0,0,1);
.ebook-popup-title{
position: relative;
padding: px2rem(15);
box-sizing: border-box;
border-bottom: px2rem(1) solid #b8b9bb;
text-align: center;
@include center;
.ebook-popup-title-icon{
position: absolute;
left: px2rem(15);
top: 0;
height: 100%;
@include center;
font-size: px2rem(16);
}
.ebook-popup-title-text{
font-size: px2rem(14);
font-weight: bold;
}
}
.ebook-popup-list-wrapper{
.ebook-popup-item{
display: flex;
padding: px2rem(15);
text-align: center;
/*justify-content: space-between;*/
.ebook-popup-item-text{
flex: 1;
font-size: px2rem(14);
text-align: left;
&.selected{
color: #346c69;
font-weight: bold;
}
}
.ebook-popup-item-check{
flex: 1;
font-size: px2rem(14);
font-weight: bold;
.icon-check{
color: #346c69;
}
}
}
}
}
style>
看代码,很巧妙,用一行就解决了这个问题
{{item.font}}
如何判断选中呢?其实就是靠defaultFontFamily这个值来判断,看这个方法的实现!粗俗易懂
isSelected(item){
return this.defaultFontFamily===item.font;
}
通过上面一节,容易发现,只要改变defaultFontFamily就能改变选中高亮的选项
因此,可以绑定一个方法
setFontFamily(font){
this.setDefaultFontFamily(font);
}
接着也要记得改变电子书的字体,语句和改变电子书字号类似
setFontFamily(font){
this.setDefaultFontFamily(font);
this.currentBook.rendition.themes.font(font);
}
但发现这样并不能实现,这是虽然,我们把样式文件虽然 放到项目当中了,但是并不能直接加载到电子书,因此,我们需要在电子书初次被渲染的时候就要把样式加载给电子书,这样在后面才有了选择的权力
在电子书.display()之后
//加载字体样式到电子书
this.rendition.hooks.content.register(contents=>{
contents.addStylesheet("./../../assets/fonts/daysOne.css")
})
但这并不难成功达到目的,因为
这里传入的必须是个url,而不是一个路径,所以把font样式资源放到 搭建好的nginx服务器上
改成这样:
//加载字体样式到电子书
this.rendition.hooks.content.register(contents=>{
contents.addStylesheet("http://localhost:8081/fonts/daysOne.css")
})
发现功能已经实现
为了方便,引入依赖 web-storage-cache
这个插件的用处是可以把传进来的json转化为对象存到 本地,读取时 将对象转化为json
为了方便管理本地存储 把关于ebook相关的都放进book的对象当中,这样以后扩展其他功能是,例如添加音乐时,可以把音乐相关的都放进music对象
import Storage from "web-storage-cache";
const localStorage = new Storage();
export function setLocalStorage(key,value) {
return localStorage.set(key,value);
}
export function getLocalStorage(key) {
return localStorage.get(key);
}
export function removeLocalStorage(key) {
return localStorage.delete(key);
}
export function clearLocalStorage() {
return localStorage.clear();
}
export function setBookObject(fileName,key,value) {
console.log(fileName);
let book = getLocalStorage(`${fileName}-info`);
if(!book){
book = {}
}
book[key] = value;
setLocalStorage(`${fileName}-info`,book)
}
export function getBookObject(fileName,key) {
let book = getLocalStorage(`${fileName}-info`)
if(book){
return book[key]
}else {
return null
}
}
export function getFontFamily(fileName) {
return getBookObject(fileName,'fontFamily')
}
export function saveFontFamily(fileName,font) {
return setBookObject(fileName,'fontFamily',font);
}
调用其中的方法就可以了,是不是超鸡方便
‘
不信可以看看使用,
我们在已渲染完电子书后中就获取本地 fontFamily,如果不存在,则,默认添加为defaut
this.rendition.display().then(()=>{
let font = getFontFamily(this.fileName);
if(!font){
saveFontFamily(this.fileName,this.defaultFontFamily)
}else{
this.rendition.themes.font(font);
this.setDefaultFontFamily(getFontFamily(this.fileName));
}
});
每次更改完后也要存储到本地
为了跟上时代,必须使用国际化,这国际化以后搬到别处应用也是可以装一把。
创建这几个文件
中文包
const messages = {
home: {
title: '书城',
hint: '计算机科学和软件工程',
guessYouLike: '猜你喜欢',
change: '换一批',
clear: '清空',
hotSearch: '热门搜索',
historySearch: '搜索历史',
sameAuthor: '与$1同作者',
sameReader: '对$1感兴趣的人也在读',
readPercent: '阅读$2的人,$1都在读',
recommend: '热门推荐',
seeAll: '查看全部',
readers: '$1人同时在读',
featured: '精选',
category: '分类',
books: '本书',
readNow: '立即阅读',
allBook: '共 $1 本图书'
},
category: {
computerScience: '计算机科学',
socialSciences: '社会科学',
economics: '经济学',
education: '教育学',
engineering: '工程学',
environment: '环境学',
geography: '地理学',
history: '历史学',
laws: '法学',
lifeSciences: '生命科学',
literature: '文学',
biomedicine: '生物医学',
businessandManagement: '工商管理',
earthSciences: '地球科学',
materialsScience: '材料科学',
mathematics: '数学',
medicineAndPublicHealth: '公共卫生',
philosophy: '哲学',
physics: '物理',
politicalScienceAndInternationalRelations: '国际关系',
psychology: '心理学',
statistics: '统计学'
},
shelf: {
title: '书架',
edit: '编辑',
cancel: '取消',
search: '搜索',
private: '私密阅读',
noPrivate: '关闭私密阅读',
download: '开启离线',
move: '移动到...',
remove: '移出书架',
setPrivateTitle: '开启后,所选书籍的阅读记录将不会对外公开',
open: '开启',
closePrivateTitle: '是否关闭所选书籍的私密阅读?',
close: '关闭',
setPrivateSuccess: '已开启私密阅读
阅读记录将不再公开',
closePrivateSuccess: '已关闭私密阅读',
setDownloadTitle: '开启后,将自动缓存所选书籍内容',
setDownloadSuccess: '已开启,将自动离线已购内容',
setDownloadError: '离线下载异常,请重新尝试',
removeDownloadTitle: '确认后,将删除所选书籍的离线内容',
removeDownloadSuccess: '已选书籍的离线内容已删除',
delete: '删除',
clearCache: '清除缓存',
clearCacheSuccess: '缓存已清空',
removeBookTitle: '是否将$1移出书架?',
removeBook: '移出',
selectedBooks: '所选书籍',
default: '默认',
progress: '按进度',
purchase: '按购买',
bought: '已购买',
notPurchased: '未购买',
selectBook: '选择书籍',
haveSelectedBook: '已选择$1本',
haveSelectedBooks: '已选择$1本',
moveBook: '移动书籍',
newGroup: '新建分组',
groupOut: '移出分组',
editGroup: '修改分组',
editGroupName: '修改分组名',
deleteGroup: '删除分组',
deleteGroupTitle: '删除分组后,分组内的书籍将会自动移出分组',
groupNone: '当前分组暂无书籍',
groupName: '分组名',
confirm: '确定',
moveBookInSuccess: '成功移入$1',
moveBookOutSuccess: '成功移出分组',
statistic: '$1本公开阅读 • $2本私密阅读',
startDownload: '开始下载...',
progressDownload: '正在下载:$1',
downloadFirst: '请先缓存图书',
welcome: '欢迎访问慕课网
学习《实战微信读书——媲美原生APP的企业级Web书城》
-------- 作者:Sam --------',
find: '去找书',
changeLanguage: '切换语言',
studyNow: '去慕课网学习'
},
detail: {
copyright: '版权',
navigation: '目录',
publisher: '出版社',
category: '分类',
ISBN: 'ISBN',
trial: '试读',
lang: '语言',
loading: '加载中...',
read: '阅读',
listen: '听书',
addOrRemoveShelf: '加入书架',
isAddedToShelf: '已加入书架'
},
speak: {
voice: '语音朗读',
read: '查看原文',
settings: '设置',
timing: '定时',
current: '当前章节',
requestFailed: '请求失败!',
apply: '语义解析核心技术由科大讯飞提供'
},
book: {
pulldownAddMark: '下拉添加书签',
releaseAddMark: '松手添加书签',
pulldownDeleteMark: '下拉删除书签',
releaseDeleteMark: '松手删除书签',
selectFont: '选择字体',
haveRead: '已读$1分钟',
themeDefault: '默认',
themeGold: '雅致',
themeEye: '护眼',
themeNight: '夜间',
loading: '加载中...',
navigation: '目录',
bookmark: '书签',
searchHint: '搜索全书内容',
haveRead2: '已读',
minutes: '分钟',
cancel: '取消'
}
}
export default messages
英文包
const messages = {
home: {
title: 'Book Store',
hint: 'Computer Science And Software Engineering',
guessYouLike: 'Guess You Like',
change: 'Change',
clear: 'Clear',
hotSearch: 'Hot Search',
historySearch: 'History Search',
sameAuthor: 'Same author with $1',
sameReader: 'Same reader with $1',
readPercent: '$1 is reading $2',
recommend: 'Recommend',
seeAll: 'See all',
readers: '$1 is reading',
featured: 'Featured',
category: 'Category',
books: 'books',
readNow: 'Read Now',
allBook: '$1 books'
},
category: {
computerScience: 'Computer Science',
socialSciences: 'Social Sciences',
economics: 'Economics',
education: 'Eductation',
engineering: 'Engineering',
environment: 'Environment',
geography: 'Geography',
history: 'History',
laws: 'Laws',
lifeSciences: 'LifeSciences',
literature: 'Literature',
biomedicine: 'Biomedicine',
businessandManagement: 'Business and Management',
earthSciences: 'Earth Sciences',
materialsScience: 'Materials Science',
mathematics: 'Mathematics',
medicineAndPublicHealth: 'Medicine And Public Health',
philosophy: 'Philosophy',
physics: 'Physics',
politicalScienceAndInternationalRelations: 'Political Science And International Relations',
psychology: 'Psychology',
statistics: 'Statistics'
},
shelf: {
title: 'Book Shelf',
edit: 'Edit',
cancel: 'Cancel',
search: 'Search',
private: 'Private',
noPrivate: 'Close Private',
download: 'Download',
move: 'Move...',
remove: 'Remove',
setPrivateTitle: 'When opened, the reading history of selected books will not be made public',
open: 'Open',
closePrivateTitle: 'Whether to close the private reading of selected books?',
close: 'Close',
setPrivateSuccess: 'Private reading has been open and reading history will no longer be published',
closePrivateSuccess: 'Private reading has been closed',
setDownloadTitle: 'When opened, selected books will automatically download',
setDownloadSuccess: 'Opened, will automatically download purchased books',
setDownloadError: 'Offline download exception, please try again',
removeDownloadTitle: 'Once confirmed, the offline books of selected will be remove',
removeDownloadSuccess: 'Offline books of selected has been remove',
delete: 'Remove',
clearCache: 'Clear Cache',
clearCacheSuccess: 'Clear cache successfully, cache is empty',
removeBookTitle: 'Whether to remove $1 out of the bookshelf?',
removeBook: 'Remove',
selectedBooks: 'selected books',
default: 'Default',
progress: 'By Progress',
purchase: 'By Purchase',
bought: 'Bought',
notPurchased: 'Not Purchased',
selectBook: 'Select Book',
haveSelectedBook: '$1 book has been selected',
haveSelectedBooks: '$1 books have been selected',
moveBook: 'Move Book',
newGroup: 'New Group',
groupOut: 'Move Out of Group',
editGroup: 'Edit Group',
editGroupName: 'Edit Group Name',
deleteGroup: 'Delete Group',
deleteGroupTitle: 'After deleting a group, the books in the group will be automatically moved out of the group',
groupNone: 'There are no books in the current group',
groupName: 'Group Name',
confirm: 'Confirm',
moveBookInSuccess: 'Move book(s) into $1 successfully',
moveBookOutSuccess: 'Move book(s) out of the group successfully',
statistic: '$1 public reading • $2 private reading',
startDownload: 'Start download...',
progressDownload: 'Downloading:$1',
downloadFirst: 'Please download book first',
welcome: 'Welcome to visit iMooc
Learning "Practical WeChat Reading - Enterprise Web Book Store of Amami Native APP"
-------- Author: Sam --------',
find: 'Go to book store',
changeLanguage: 'Change Language',
studyNow: 'Learn on imooc.com'
},
detail: {
copyright: 'Copyright',
navigation: 'Table of Contents',
publisher: 'Publisher',
category: 'Category',
ISBN: 'ISBN',
trial: 'Trial Reading',
lang: 'Language',
loading: 'Loading...',
read: 'Read',
listen: 'Listen',
addOrRemoveShelf: 'Add to Book Shelf',
isAddedToShelf: 'Added to BookShelf'
},
speak: {
voice: 'Voice Reading',
read: 'Read Originial',
settings: 'Settings',
timing: 'Timing',
current: 'Current Section',
requestFailed: 'Request failed!',
apply: 'The core technology of semantic analysis is provided by iFLY TEK'
},
book: {
pulldownAddMark: 'Pull down to add bookmark',
releaseAddMark: 'Release to add bookmark',
pulldownDeleteMark: 'Pull down to delete bookmark',
releaseDeleteMark: 'Release to add bookmark',
selectFont: 'Select Font',
haveRead: 'Already read $1 minutes',
themeDefault: 'Default',
themeGold: 'Grace',
themeEye: 'Eye',
themeNight: 'Night',
loading: 'Loading...',
navigation: 'Contents',
bookmark: 'Bookmark',
searchHint: 'Search from the entire book',
haveRead2: 'already read',
minutes: 'minutes',
cancel: 'Cancel'
}
}
export default messages
最后把这两个引入index
import Vue from 'vue'
import VueI18n from 'vue-i18n'
import en from './en'
import cn from './cn'
import { getLocale, saveLocale } from '../utils/localStorage'
Vue.use(VueI18n)
const messages = {
en, cn
}
let locale = getLocale()
if (!locale) {
locale = 'cn';
saveLocale(locale)
}
const i18n = new VueI18n({
locale,
messages
})
export default i18n
同样,记得把index 引入main中
通过这种方法使用,就能实现国际化了
<template>
<transition name="slide-up">
<div class="setting-wrapper" v-show="menuVisible && settingVisible ===1">
<div class="setting-theme">
<div class="setting-theme-item" v-for="(item, index) in themeList" :key="index" @click="setTheme(index,item)">
<div class="preview" :style="{background: item.style.body.background}" :class="{'no-border': item.style.body.background !== '#fff'}">div>
<div class="text" :class="{'selected': item.name === defaultTheme}">{{item.alias}}div>
div>
div>
div>
transition>
template>
<script>
import {ebookMixin} from "./../../utils/mixin"
// import {themeList} from "./../../utils/book"
export default {
name: "EbookSettingTheme",
mixins:[ebookMixin],
computed:{
},
data(){
return{
}
},
methods:{
setTheme(index,item){
const theme = this.themeList[index];
this.setDefaultTheme(theme.name).then(()=>{
this.currentBook.rendition.themes.select(this.defaultTheme)
});
},
}
}
script>
<style lang="scss" rel="stylesheet/scss" scoped>
@import "../../assets/styles/global";
.setting-wrapper {
color: gray;
background-color: white;
position: absolute;
bottom: px2rem(48);
left: 0;
z-index: 190;
width: 100%;
height: px2rem(90);
box-shadow: 0 px2rem(-8) px2rem(8) rgba(0, 0, 0, .15);
.setting-theme {
height: 100%;
display: flex;
.setting-theme-item {
flex: 1;
display: flex;
flex-direction: column;
padding: px2rem(5);
box-sizing: border-box;
.preview {
flex: 1;
/*border: px2rem(1) solid #ccc;*/
box-sizing: border-box;
border: none;
}
.text {
flex: 0 0 px2rem(20);
font-size: px2rem(14);
@include center;
&.selected {
/*box-shadow: 0 px2rem(4) px2rem(6) 0 rgba(0, 0, 0, .1)!important;*/
/*border: px2rem(2) solid #5e6369;*/
font-weight: bolder;
/*color: black!important;*/
}
}
}
}
}
style>
既然实现额国际化,那肯定出现的文字也要已国际化的格式出现,看上述代码,用到的主题列表themeList,其实是放到util/book中的
export function themeList(vue) {
return [
{
alias: vue.$t('book.themeDefault'),
name: 'Default',
style: {
body: {
'color': '#4c5059',
'background': '#cecece',
// 'padding-top': `${realPx(48)}px!important`,
// 'padding-bottom': `${realPx(48)}px!important`
},
img: {
'width': '100%'
},
'.epubjs-hl': {
'fill': 'red', 'fill-opacity': '0.3', 'mix-blend-mode': 'multiply'
}
}
},
{
alias: vue.$t('book.themeGold'),
name: 'Gold',
style: {
body: {
'color': '#5c5b56',
'background': '#c6c2b6',
// 'padding-top': `${realPx(48)}px!important`,
// 'padding-bottom': `${realPx(48)}px!important`
},
img: {
'width': '100%'
},
'.epubjs-hl': {
'fill': 'red', 'fill-opacity': '0.3', 'mix-blend-mode': 'multiply'
}
}
},
{
alias: vue.$t('book.themeEye'),
name: 'Eye',
style: {
body: {
'color': '#404c42',
'background': '#a9c1a9',
// 'padding-top': `${realPx(48)}px!important`,
// 'padding-bottom': `${realPx(48)}px!important`
},
img: {
'width': '100%'
},
'.epubjs-hl': {
'fill': 'red', 'fill-opacity': '0.3', 'mix-blend-mode': 'multiply'
}
}
},
{
alias: vue.$t('book.themeNight'),
name: 'Night',
style: {
body: {
'color': '#cecece',
'background': '#000000',
// 'padding-top': `${realPx(48)}px!important`,
// 'padding-bottom': `${realPx(48)}px!important`
},
img: {
'width': '100%'
},
'.epubjs-hl': {
'fill': 'red', 'fill-opacity': '0.3', 'mix-blend-mode': 'multiply'
}
}
}
]
}
setTime就是切换主题的方法了。不过有一点,我们必须注意,就是,这主题啊,是我们自己创建出来的,而不是电子书本身带有的,就像字体一样,需要电子书初始化时,加载
动态添加的方法如下所示
export function addCss(href) {
const link = document.createElement('link');
link.setAttribute('rel','stylesheet')
link.setAttribute('type','text/css')
link.setAttribute('href',href)
document.getElementsByTagName('head')[0].appendChild(link);
}
通过这句就可以设置全局样式了,很巧妙,有没有
,里面那个地址是搭好的nginx服务器里的资源
接下来就要通过获取当前电子书的主题,来反应到全局主题
setGlobalTheme(theme) {
// removeAllCss()
switch (theme) {
case 'Default':
addCss('http://localhost:8081/theme/theme_default.css')
break
case 'Eye':
addCss('http://localhost:8081/theme/theme_eye.css')
break
case 'Gold':
addCss('http://localhost:8081/theme/theme_gold.css')
break
case 'Night':
addCss('http://localhost:8081/theme/theme_night.css')
break
default:
this.setDefaultTheme('Default')
addCss('http://localhost:8081/theme/theme_default.css')
break
}
},
这真是一个漂亮的方法,
当是发现一个很大的问题
当我们频繁切换主题的时候,引入的链接会添加到dom树上,而我们需要的只有最后一条,所以非常有必要把之前的移除掉
因此,我们创建了一个方法,在每次切换全局主题之前,也就是引入link之前,先把之前的link删了
export function removeCss(href) {
const links = document.getElementsByTagName('link');
for (let i = links.length;i>=0;i--){
const link = links[i];
if(link && link.getAttribute('href')&&link.getAttribute('href')===href){
link.parentNode.removeChild(link);
}
}
}
export function removeAllCss() {
removeCss('http://localhost:8081/theme/theme_default.css')
removeCss('http://localhost:8081/theme/theme_eye.css')
removeCss('http://localhost:8081/theme/theme_gold.css')
removeCss('http://localhost:8081/theme/theme_night.css')
}