微信读书项目(4)

本文详细介绍了微信读书项目的前端开发过程,包括字体设置弹窗、字号和字体的离线存储、标题国际化、阅读器主题设置和全局主题切换等功能的实现。通过Vue-i18n实现国际化,使用Local Storage进行数据存储,结合rendition处理字体和字号,同时解决了主题切换的动态加载和清除冗余CSS问题。此外,还涵盖了阅读进度、目录和全文搜索功能的开发,涉及进度面板和分页逻辑的实现。

3.8 字体设置弹窗功能实现

实现点击屏幕,字体设置面板消失:

toggleTitleAndMenu () {
  if (this.menuVisible) {
    //  隐藏字号设置面板
    this.setSettingVisible(-1)
    this.setFontFamilyVisible(false) // 实现点击屏幕,字体设置面板消失
  }
  // 显示标题和菜单栏
  this.setMenuVisible(!this.menuVisible)
},
hideTitleAndMenu () {
  this.setMenuVisible(false)
  this.setSettingVisible(-1)
  this.setFontFamilyVisible(false)// 实现点击屏幕,字体设置面板消失
},

实现字体被选中

给item绑定点击事件

<div class="ebook-popup-item" v-for="(item, index) in fontFamilyList" :key="index"
     @click="setFontFamily(item.font)">

定义setFontFamily函数

setFontFamily (font) {
    this.setDefaultFontFamily(font)
}

接下来实现,字体的切换的生效

与字号类似,在currentBook下面调用rendition

setFontFamily (font) {
    this.setDefaultFontFamily(font)
    this.currentBook.rendition.themes.font(font)
}

但这里没有生效,因为scss文件没有引入iframe

回到EbookReader.vue中,在initEpub函数中,使用rendition的钩子函数

this.rendition.hooks.content.register(contents => {
contents.addStylesheet(`...`)
})

根据contents.js源码,省略号这里必须传入一个url,那么我们利用nginx来实现。
我们把fonts文件放入resource文件夹,生成Http链接可以引用到钩子函数中

这是default字体未生效,通过改动setFontFamily方法来解决

setFontFamily (font) {
  this.setDefaultFontFamily(font)
  if (font === 'Default') {
      // 设置自己喜欢的字体
    this.currentBook.rendition.themes.font('Times New Roman')
  } else {
    this.currentBook.rendition.themes.font(font)
  }
}

到这里,基本功能实现,我们做一些改动。

在Vue-CLI3.0中环境变量和模式设置,为以后上线做准备

在根目录下创建一个文件.env.development,把我们本地的url抽象成一个变量下入该文件。
注意一点,只有以 VUE_APP_ 开头的变量会被 webpack.DefinePlugin 静态嵌入到客户端侧的包中。你可以在应用的代码中这样访问它们:

console.log(process.env.VUE_APP_SECRET)

所以我们的变量如下:

VUE_APP_RES_URL=http://192.168.0.102:8081

下面我们就可以使用了

this.rendition.hooks.content.register(contents => {
  Promise.all(
    [
  contents.addStylesheet(`${process.env.VUE_APP_RES_URL}/fonts/daysOne.css`),   contents.addStylesheet(`${process.env.VUE_APP_RES_URL}/fonts/cabin.css`),
 contents.addStylesheet(`${process.env.VUE_APP_RES_URL}/fonts/montserrat.css`,   contents.addStylesheet(`${process.env.VUE_APP_RES_URL}/fonts/tangerine.css`)
    ]
  )
})

!环境变量和配置变量的重新载入都需要重新启动服务器才能生效。

3.9实现字号和字体的离线存储

我们这里利用Local Storage进行离线缓存,首先,安装库npm i --save web-storage-cache
在utils下面引入这个库

创建一个localStorage.js文件,将安装的库引入。这个库可以将我们传入的字符串或对象转换成json存储,读取时又能转换成字符串或对象使用。随后创建一个实例化对象,写入基本方法。

import Storage from 'web-storage-cache'
const localStorage = new Storage()
export function getLocalStorage (key) {
  return localStorage.get(key)
}
export function setLocalStorage (key, value) {
  return localStorage.set(key, value)
}
export function removeLocalStorage (key) {
  return localStorage.delete(key)
}
export function clearLocalStorage () {
  return localStorage.clear()
}
export function getHome () {
  return getLocalStorage('home')
}
export function saveHome (home) {
  return setLocalStorage('home', home, 1800)
}
export function getLocale () {
  return getLocalStorage('locale')
}
export function saveLocale (locale) {
  return setLocalStorage('locale', locale)
}
export function getLocation (fileName) {
  return getBookObject(fileName, 'location')
}
export function saveLocation (fileName, location) {
  setBookObject(fileName, 'location', location)
}
export function getBookmark (fileName) {
  return getBookObject(fileName, 'bookmark')
}
export function saveBookmark (fileName, bookmark) {
  setBookObject(fileName, 'bookmark', bookmark)
}
export function getReadTime (fileName) {
  return getBookObject(fileName, 'time')
}
export function saveReadTime (fileName, theme) {
  setBookObject(fileName, 'time', theme)
}
export function getProgress (fileName) {
  return getBookObject(fileName, 'progress')
}
export function saveProgress (fileName, progress) {
  setBookObject(fileName, 'progress', progress)
}
export function getNavigation (fileName) {
  return getBookObject(fileName, 'navigation')
}
export function saveNavigation (fileName, navigation) {
  setBookObject(fileName, 'navigation', navigation)
}
export function getMetadata (fileName) {
  return getBookObject(fileName, 'metadata')
}
export function saveMetadata (fileName, metadata) {
  setBookObject(fileName, 'metadata', metadata)
}
export function getCover (fileName) {
  return getBookObject(fileName, 'cover')
}
export function saveCover (fileName, cover) {
  setBookObject(fileName, 'cover', cover)
}
export function getFontFamily (fileName) {
  return getBookObject(fileName, 'fontFamily')
}
export function saveFontFamily (fileName, fontFamily) {
  setBookObject(fileName, 'fontFamily', fontFamily)
}
export function getTheme (fileName) {
  return getBookObject(fileName, 'theme')
}
export function saveTheme (fileName, theme) {
  setBookObject(fileName, 'theme', theme)
}
export function getFontSize (fileName) {
  return getBookObject(fileName, 'fontSize')
}
export function saveFontSize (fileName, fontSize) {
  setBookObject(fileName, 'fontSize', fontSize)
}
export function getBookObject (fileName, key) {
  if (getLocalStorage(`${fileName}-info`)) {
    return getLocalStorage(`${fileName}-info`)[key]
  } else {
    return null
  }
}
export function setBookObject (fileName, key, value) {
  let book = {}
  if (getLocalStorage(`${fileName}-info`)) {
    book = getLocalStorage(`${fileName}-info`)
  }
  book[key] = value
  setLocalStorage(`${fileName}-info`, book)
}

接下来带入业务场景进行使用,我们分别实现字体和字号的存储。
字体存储:

首先我们要在setFontFamily函数中对字体进行保存

setFontSize (fontSize) {
  this.setDefaultFontSize(fontSize)
  // 字号的离线存储
  saveFontSize(this.fileName, fontSize)
  this.currentBook.rendition.themes.fontSize(fontSize)
}

再进行字体初始化操作,这里我们将其抽象为一个函数

initFontFamily () {
  let font = getFontFamily(this.fileName)
  if (!font) {
    saveFontFamily(this.fileName, this.defaultFontFamily)
  } else {
    this.rendition.themes.font(font)
    this.setDefaultFontFamily(font)
  }
}

this.rendition.display()返回的promise对象进行调用

this.rendition.display().then(() => {
  this.initFontFamily()
})

接下来字号设置,与字体类似:

先在setFontSize函数中对字号进行保存

setFontSize (fontSize) {
  this.setDefaultFontSize(fontSize)
  // 字号的离线存储
  saveFontSize(this.fileName, fontSize)
  this.currentBook.rendition.themes.fontSize(fontSize)
}

=>EbookReader.vue

initFontSize () {
  let fontSize = getFontSize(this.fileName)
  if (!fontSize) {
    saveFontSize(this.fileName, this.defaultFontSize)
  } else {
    this.rendition.themes.font(fontSize)
    this.setDefaultFontFamily(fontSize)
  }
}
...
this.rendition.display().then(() => {
          this.initFontSize()
        })

3.10标题国际化

这里我们需要使用Vue-i18n这个插件
首先我们准备好资源文件,在src目录下建立文件夹lang来管理语言,在lang中放入我们的en.js和cn.js。
接下来安装插件:cnpm i -save vue-i18n

在lang文件夹下创建Js文件index.js,在其中引入库和资源文件,

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

在项目中使用

<span class="ebook-popup-title-text">{{$t('book.selectFont')}}</span>

这是我们选择中文时,显示选择字体,选择英文时,显示Select Font

3.11 阅读器主题设置功能实现

首先建立相应的组件EbookSettingTheme.vue,在组件中完成结构和样式:

<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)">
        <div class="preview" :class="{'selected': item.name === defaultTheme}"
             :style="{background: item.style.body.background}"></div>
        <div class="text" :class="{'selected': item.name === defaultTheme}">{{item.alias}}</div>
      </div>
    </div>
  </div>
</transition>
...
<style lang="scss" rel="stylesheet/scss" scoped>
  @import "../../assets/styles/global.scss";

  .setting-wrapper {
    position: absolute;
    bottom: px2rem(48);
    left: 0;
    z-index: 101;
    width: 100%;
    height: px2rem(90);
    background: white;
    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;
          &.selected {
            box-shadow: 0 px2rem(4) px2rem(6) 0 rgba(0, 0, 0, .1);
          }
        }
        .text {
          flex: 0 0 px2rem(20);
          font-size: px2rem(14);
          color: #ccc;
          @include center;
          &.selected {
            color: #333;
          }
        }
      }
    }
  }
</style>

这里我们需要一个themeList的数据对象,老规矩,在book.js中创建

export function themeList (vue) {
  return [
    {
      alias: vue.$t('book.themeDefault'),
      name: 'Default',
      style: {
        body: {
          'color': '#4c5059',
          'background': '#cecece'
        },
        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'
        },
        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'
        },
        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'
        },
        img: {
          'width': '100%'
        },
        '.epubjs-hl': {
          'fill': 'red', 'fill-opacity': '0.3', 'mix-blend-mode': 'multiply'
        }
      }
    }
  ]
}

我们需要把组件放入menu中,所以在menu组件引入、注册加放坑

<template>
...
	<ebook-setting-theme></ebook-setting-theme>
	...
</template>
<script>
  ...
  import EbookSettingTheme from './EbookSettingTheme'
  ...
  components: {
      ...
      EbookSettingTheme
    },
        ...
</script>

接下来我们给主题绑定点击事件@click="setTheme(index)"

setTheme (index) {
  this.setDefaultTheme(theme.name)
}

为了方便管理,我们把themeList混入到mixin.js中

import { themeList } from './book'
...
export const ebookMixin = {
  computed: {
      ...
    themeList () {
      return themeList(this)
    }
},
    ...
}      

实现主题切换和缓存功能

// 前面需要引入getTheme、saveTheme,
initTheme () {
  let defaultTheme = getTheme(this.fileName)
  if (!defaultTheme) {
    defaultTheme = this.themeList[0].name
    // 设置到vuex中
    this.setDefaultTheme(defaultTheme)
    saveTheme(this.fileName, defaultTheme)
  }
  this.themeList.forEach(theme => {
    this.rendition.themes.register(theme.name, theme.style)
  })
  // 设置默认样式
  this.rendition.themes.select(this.defaultTheme)
}
// 后面将initTheme()在initEpub的display中异步调用

=>setTheme组件

setTheme (index) {
  const theme = this.themeList[index]
  // 异步调用
  this.setDefaultTheme(theme.name).then(() => {
    this.currentBook.rendition.themes.select(this.defaultTheme)
  })
  saveTheme(this.fileName, theme.name)
}

3.12 全局主体设置功能实现

动态全局主题设置的原理是为DOM动态添加删除css文件,
—找到head标签,添加我们自定义的head标签即可。

在Book.js中添加方法addCss实现动态添加css

export function addCss (href) {
  // 创建link标签
  const link = document.createElement('link')
  // 设置link标签属性
  link.setAttribute('rel', 'stylesheet')
  link.setAttribute('type', 'text/css')
  link.setAttribute('href', href)
  //  追加到head中
  document.getElementsByTagName('head')[0].appendChild(link)
}

将theme文件放入resource生成url链接。

在EbookReader.vue中添加一个方法,initGlobalStyle()初始化全局样式

 import { addCss } from '../../utils/book'
...
initGlobalStyle () {
  addCss(`${process.env.VUE_APP_RES_URL}/theme/theme_eye.css`)
}
...
this.rendition.display().then(() => {
          this.initTheme()
          this.initFontSize()
          this.initFontFamily()
          this.initGlobalStyle()
        })

实现主题的动态切换,通过switch函数,根据当前主题加载响应的css文件

initGlobalStyle () {
  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
  }
}

这时切换主题,存在两个问题
问题1:只有阅读器实现主题切换,而全局主题没有切换

initTheme () {
  let defaultTheme = getTheme(this.fileName)
  if (!defaultTheme) {
     // this.setDefaultTheme(defaultTheme)把这句放在括号外面?
    defaultTheme = this.themeList[0].name
    saveTheme(this.fileName, defaultTheme)
  }
  // 设置到vuex中
  this.setDefaultTheme(defaultTheme)
  this.themeList.forEach(theme => {
    this.rendition.themes.register(theme.name, theme.style)
  })
  // 设置默认样式
  this.rendition.themes.select(this.defaultTheme)
},

问题2:刷新页面,全局主题没有得到保存

首先,我们将initGlobalStyle方法放入到mixin中实现复用。

在EbookReader和setTheme组件中分别调用:

methods: {
  setTheme (index) {
    const theme = this.themeList[index]
    this.setDefaultTheme(theme.name).then(() => {
      this.currentBook.rendition.themes.select(this.defaultTheme)
      this.initGlobalStyle() // EbookSettingTheme.vue中调用
    })
    saveTheme(this.fileName, theme.name)
  }
}

这时可以实现模式切换了,但是用户每点击一次切换主题在head标签中就多一个css文件,接下来我们要对这些样式做一下清除。

首先,我们在book.js中添加removeCss方法和removeAllCss方法

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`)
}

在mixin.js中initGlobalStyle方法的最前面调用removeAllCss进行初始化。

四、阅读器–阅读进度、目录、全文搜索功能开发

4.1阅读进度功能实现(进度面板和分页逻辑)

首先我们创建阅读进度组件,EbookSettingProgress.vue,写入结构和样式,混入ebookMixin

<template>
  <transition name="slide-up">
    <div class="setting-wrapper" v-show="menuVisible && settingVisible ===2">
      <div class="setting-progress">
        <div class="progress-wrapper">
          <input class="progress" type="range"
                 max="100"
                 min="0"
                 step="1"
                 @change="onProgressChange($event.target.value)" @input="onProgressInput($event.target.value)"
                 :value="progress"
                 :disabled="!bookAvailable"
                 ref="progress">
        </div>
        <div class="text-wrapper">
          <span>{{bookAvailable ? progress + '%' : '加载中...'}}</span>
        </div>
      </div>
    </div>
  </transition>
</template>
<script>
  import { ebookMixin } from '../../utils/mixin'
  export default {
    mixins: [ebookMixin]
  }
</script>
<style lang="scss" rel="stylesheet/scss" scoped>
  @import "../../assets/styles/global.scss";

  .setting-wrapper {
    position: absolute;
    bottom: px2rem(48);
    left: 0;
    z-index: 101;
    width: 100%;
    height: px2rem(60);
    background: white;
    box-shadow: 0 px2rem(-8) px2rem(8) rgba(0, 0, 0, .15);
    .setting-progress {
      position: relative;
      width: 100%;
      height: 100%;
      .progress-wrapper {
        width: 100%;
        height: 100%;
        @include center;
        padding: 0 px2rem(30);
        box-sizing: border-box;
        .progress {
          width: 100%;
          -webkit-appearance: none;
          height: px2rem(2);
          background: -webkit-linear-gradient(#999, #999) no-repeat, #ddd;
          background-size: 0 100% !important;
          &:focus {
            outline: none;
          }
          &::-webkit-slider-thumb {
            -webkit-appearance: none;
            height: px2rem(20);
            width: px2rem(20);
            border-radius: 50%;
            background: white;
            box-shadow: 0 4px 4px 0 rgba(0, 0, 0, .15);
            border: px2rem(1) solid #ddd;
          }
        }
      }
      .text-wrapper {
        position: absolute;
        left: 0;
        bottom: 0;
        width: 100%;
        color: #333;
        font-size: px2rem(12);
        text-align: center;
      }
    }
  }
</style>

将新建的组件在EbookMenu中导入、注册、引用

<ebook-setting-progress></ebook-setting-progress>
...
import EbookSettingProgress from './EbookSettingProgress'
...
export default {
    mixins: [ebookMixin],
    components: {
      EbookSettingFont,
      EbookSettingFontPopup,
      EbookSettingTheme,
      EbookSettingProgress
    }
    ...
  }

完善布局,在左右加上图标,表示上一章节和下一章节,并加入样式

<div class="progress-wrapper">
  	<div class="progress-icon-wrapper">
    	<span class="icon-back" @click="prevSection()"></span>
 	 </div>
	<input ...>
	<div class="progress-icon-wrapper">
            <span class="icon-forward" @click="nextSection()"></span>
     </div>
  </div>  
...
.progress-wrapper {
       ...
        .progress-icon-wrapper{
          font-size: px2rem(20);
        }
}

在进度条上方布局–显示阅读时间

<div class="read-time-wrapper">
  <span class="read-time-text"></span>
  <span class="icon-forward"></span>
</div>
...
.read-time-wrapper{
        position: absolute;
        left: 0;
        top: 0;
        width: 100%;
        height: px2rem(40);
        font-size: px2rem(12);
        @include center;
      }

实现进度条的正常使用—设置分页逻辑

在实现分页逻辑之前,我们进行了代码重构,建立了initRendition()函数和初始化手势函数initGesture()函数,并在initEpub中进行调用

下面,编写简单的分页算法,实现分页,在initEpub中

this.book.ready.then(() => {
  return this.book.locations.generate(750 * (window.innerWidth / 375) * (getFontSize(this.fileName / 16)))
}).then(locations => {
  this.setBookAvailable(true)
})

4.2阅读进度功能实现(进度条拖动功能)

在之前的结构中,我们给进度条绑定了两个事件

<input 
//@change移除焦点触发事件
@change="onProgressChange($event.target.value)" 			   	@input="onProgressInput($event.target.value)">
// 进度条拖动松手以后调用的方法
  onProgressChange (progress) {
    this.setProgress(progress).then(() => {
      this.displayProgress()
      this.updateProgressBg()
    })
  },
  // 进度条拖动过程中调用的方法
  onProgressInput (progress) {
    this.setProgress(progress).then(() => {
      this.updateProgressBg()
    })
  },
  displayProgress () {
    const cfi = this.currentBook.locations.cfiFromPercentage(this.progress / 100)
    this.currentBook.rendition.display(cfi)
  },
  updateProgressBg () {
    // 拖动进度条,读过的部分进度条颜色加深
    this.$refs.progress.style.backgroundSize = `${this.progress}% 100%`
  }
  },
updated () {
  // 调用updated钩子函数实现进度条初始化
  this.updateProgressBg()
}

4.3阅读进度功能实现(上下章切换)

先来实现上一章功能
我们先前在vuex(book.js)中定义了一个变量section,用来指定当前章节的位置,0表示第一章…

prevSection () {
  // 章节不为负且书籍解析完成
  if (this.section > 0 && this.bookAvailable) {
    this.setSection(this.section - 1).then(() => {
      const sectionInfo = this.currentBook.section(this.section)
      if (sectionInfo && sectionInfo.href) {
        this.currentBook.rendition.display(sectionInfo.href)
      }
    })
  }
}

我们把display出来,因为下一章跳转也要用

displaySection () {
  const sectionInfo = this.currentBook.section(this.section)
  if (sectionInfo && sectionInfo.href) {
    this.currentBook.rendition.display(sectionInfo.href)
  }
}

那么,上下翻页的函数变为:

prevSection () {
  // 章节不为负且书籍解析完成
  if (this.section > 0 && this.bookAvailable) {
    this.setSection(this.section - 1).then(() => {
      this.displaySection()
    })
  }
},
nextSection () {
  // this.currentBook.spine.length表示章节数
  if (this.section < this.currentBook.spine.length - 1 && this.bookAvailable) {
    this.setSection(this.section + 1).then(() => {
      this.displaySection()
    })
  }
},
    ...

4.4阅读进度功能实现(章节切换和进步同步)

实现章节变化时,进度百分比同步变化

定义函数refreshLocation刷新当前位置,并在displaySection()中调用即可

refreshLocation () {
  // 刷新当前位置
  const currentLocation = this.currentBook.rendition.currentLocation()
// 获取当前进度百分比  
const progress = this.currentBook.locations.percentageFromCfi(currentLocation.start.cfi)
  this.setProgress(Math.floor(progress * 100))
}

下面来实现获取相应的章节名称,显示在百分比的左边,首先完成布局

<div class="text-wrapper">
  <span class="progress-section-text">{{getSectionName}}</span>
  <span>({{bookAvailable ? progress + '%' : '加载中...'}})</span>
</div>

这里我们用getSectionName函数来获取当前章节名称

computed: {
  getSectionName () {
    if (this.section) {
      const sectionInfo = this.currentBook.section(this.section)
      if (sectionInfo && sectionInfo.href) {
        return this.currentBook.navigation.get(sectionInfo.href).label
      }
    }
  }
},

这时可以实现功能,但样式需要继续优化,章节名称太长时实现一行显示,为了以后代码复用,我们把它写在mixin.scss中

@mixin ellipsis{
   //省略显示
  text-overflow:ellipsis;
  overflow: hidden;
  white-space: nowrap;
}

然后在章节显示的样式中调用

.progress-section-text {
  /*设置章节一行显示*/
  @include ellipsis;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值