主题设置功能开发(五)

效果
点击小太阳按钮,出现主题设置面板,点击切换不同的主题,整个界面的主题都发生变化

功能点
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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

echo忘川

谢谢老板们

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值