效果
点击小太阳按钮,出现主题设置面板,点击切换不同的主题,整个界面的主题都发生变化
功能点
1.内层的阅读器嵌入在iframe中,改变时内层需要通过设置theme对象来改变,外层通过样式表的方式来改变(动态加载css)
2.动态切换全局样式:
原理:dom动态添加删除css文件
实现步骤一
1.在utils文件夹下的book.js中添加themeList数组,生成主题列表
export function themeList(vue) {
return [
{
alias: vue.$t('book.themeDefault'),
name: 'Default',
style: {
body: {
'color': '#4c5059',
'background': '#cecece'
}
}
},
{
alias: vue.$t('book.themeGold'),
name: 'Gold',
style: {
body: {
'color': '#5c5b56',
'background': '#c6c2b6'
}
}
},
{
alias: vue.$t('book.themeEye'),
name: 'Eye',
style: {
body: {
'color': '#404c42',
'background': '#a9c1a9'
}
}
},
{
alias: vue.$t('book.themeNight'),
name: 'Night',
style: {
body: {
'color': '#cecece',
'background': '#000000'
}
}
}
]
}
alias是有含义的别名,不可以更换成其他的字段,更换后不会报错,但是没有对应的效果。在本项目中使用alias是为了完成国际化设置,由于设计的选择主题样式部分,如图:
所以需要使用v-for来遍历主题样式的数组v-for="(item, index) in themeList"
,但是,由于主题设置下面对应的文字不同,而需要对应的国际化文字,所以themeList不能跟之前的字体大小一样写成const FONTSIZELIST = []的形式,而要在book.js中export一个方法,方法传入vue实例,再将alias别名设置为预先定义的字段名,alias: vue.$t('book.themeGold'),
这样就可以直接{{item.alias}}
来获取对应的国际化文字。
关于在vue中使用alias可以参考参考链接(侵删)
2.新建EbookSettingTheme.vue组件,设置v-show="titleShow&&SettingFontSize===1"来控制是否显示主题,(src/store/modules/book中,SettingFontSize:-1, //-1不显示 3目录 2进度条 1主题 0字体
),EbookSettingTheme.vue内容如下:
<template>
<transition name="slide-up">
<div class="setting-wrapper" v-show="titleShow&&SettingFontSize===1">
<div class="setting-theme">
<div
class="setting-theme-item"
v-for="(item, index) in themeList"
:key="index"
@click="setTheme(index)"
>
<div
class="preview"
:style="{background: item.style.body.background}"
></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 {
mixins: [ebookMixin],
computed: {
themeList() {
return themeList(this);
}
},
methods: {
// 设置主题
setTheme(index) {
// console.log(index)
const theme=this.themeList[index];
this.setDefaultTheme(theme.name);
}
}
};
</script>
<style lang='scss' scoped>
@import "./../../assets/styles/global";
.setting-wrapper {
position: absolute;
bottom: px2rem(45);
left: 0;
z-index: 101;
width: 100%;
height: px2rem(90);
background: white;
box-shadow: 0 px2rem(-8) px2rem(8) rgba(0, 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;
&.selected {
box-shadow: 0 px2rem(4) px2rem(6) rgba(0, 0, 0, 0.15);
}
}
.text {
flex: 0 0 px2rem(20);
font-size: px2rem(14);
color: #ccc;
@include center;
&.selected {
color: #333;
}
}
}
}
}
</style>
3.EbookMenu.vue中添加EbookSettingTheme子组件:
<ebook-setting-theme></ebook-setting-theme>
import EbookSettingTheme from "./EbookSettingTheme";
components: {
EbookSettingFont,
EbookSettingFontPopup,
EbookSettingTheme
},
此时页面已经有对应的主题设置的面板,也有点击时已选中的样式,需要再添加上选中时改变的事件即可
tip:在以上步骤中,出现了一个小问题,就是点击主题时,没有默认的选项,默认的选项
:class="{'selected': item.name === defaultTheme}"
可见当item.name与defaultTheme相等时才显示勾选,而defaultTheme中为default,item.name为Default,不相等,修改defaultTheme中为Default即可。
实现步骤二
1.在EbookReader.vue中也需要使用themeList,因此,将以下段代码
computed: {
themeList() {
return themeList(this);
}
},
提取出来放入mixin.js中,然后直接引入mixin.js来使用
2.初始化主题在EbookReader组件中
//初始化主题
initTheme() {
let theme = getTheme(this.filename);
if (!theme) {
theme = this.themeList[0].name;
}
saveTheme(this.filename, theme);
//将读取到的主题 或是默认的主题 存储到vuex中
this.setDefaultTheme(theme);
this.themeList.forEach(theme => {
this.rendition.themes.register(theme.name, theme.style);
});
this.rendition.themes.select(theme);
}
},
this.rendition.display().then(() => {
this.initFont();
this.initTheme();
});
localstorage:
//保存主题
export function saveTheme(filename,theme) {
return setBookObject(filename,'theme',theme);
}
//获取主题
export function getTheme(filename) {
return getBookObject(filename, 'theme');
}
3.修改EbookSettingTheme.vue组件中添加切换主题的方法
setTheme(index) {
// console.log(index)
const theme = this.themeList[index];
this.setDefaultTheme(theme.name).then(()=>{
this.currentBook.rendition.themes.select(this.defaultTheme);
});
saveTheme(this.filename, theme.name);
}
此时页面已经在vuex和localStorage中存储了对应的主题样式,点击后内层样式会发生改变,也会存储对应的内层样式到vuex和localStorage中。接下来需要对应的改变内层的主题样式。
实现步骤三
全局样式的改变:动态改变css样式,创建link节点,将样式表放入nginx服务器下,然后append进去。
1.在utils文件夹下创建utils.js文件
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);
}
2.在mixin中加入initAllTheme方法,然后在EbookReader和EbookSettingTheme中调用
//加载外层样式表
initAllTheme() {
switch (this.defaultTheme) {
case "Default":
addCss(`${process.env.VUE_APP_RES_URL}/theme/theme_default.css`);
break;
case "Eye":
addCss(`${process.env.VUE_APP_RES_URL}/theme/theme_eye.css`);
break;
case "Gold":
addCss(`${process.env.VUE_APP_RES_URL}/theme/theme_gold.css`);
break;
case "Night":
addCss(`${process.env.VUE_APP_RES_URL}/theme/theme_night.css`);
break;
default:
addCss(`${process.env.VUE_APP_RES_URL}/theme/theme_default.css`);
break;
}
}
在EbookReader中调用initAllTheme这个方法
this.rendition.display().then(() => {
this.initFont();
this.initTheme();
this.initAllTheme();
});
在EbookSettingTheme中调用initAllTheme这个方法
// 设置主题
setTheme(index) {
// console.log(index)
const theme = this.themeList[index];
this.setDefaultTheme(theme.name).then(()=>{
this.currentBook.rendition.themes.select(this.defaultTheme);
this.initAllTheme();
});
saveTheme(this.filename, theme.name);
}
3.如图,会出现加载很多重复的样式表
在utils.js文件中加入清除样式表的方法
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(`${process.env.VUE_APP_RES_URL}/theme/theme_default.css`);
removeCss(`${process.env.VUE_APP_RES_URL}/theme/theme_eye.css`);
removeCss(`${process.env.VUE_APP_RES_URL}/theme/theme_gold.css`);
removeCss(`${process.env.VUE_APP_RES_URL}/theme/theme_night.css`);
}
接下来在initAllTheme初始化主题时进行清除样式,调用方法removeAllCss