462 lines
10 KiB
Vue
462 lines
10 KiB
Vue
<template>
|
|
<view>
|
|
<view class="fixed menu" v-show="menuFlag" @touchend="hide">
|
|
<cus-navbar :style="{boxShadow: `0 2rpx 8rpx ${textColor}29`}" :bgColor="bgColor" :titleColor="textColor">
|
|
<block slot="right">
|
|
<text class="iconfont icon-gengduo" @tap.stop.prevent="moreHandle"></text>
|
|
</block>
|
|
</cus-navbar>
|
|
|
|
<view class="bottom"
|
|
:style="{backgroundColor:bgColor,color:textColor,boxShadow: `0 -2rpx 8rpx ${textColor}29`}">
|
|
<view class="item" @touchend.prevent.stop="catalogHandle">
|
|
<text class="iconfont icon-caidan1"></text>
|
|
<text>目录</text>
|
|
</view>
|
|
<view class="item" @touchend.prevent.stop="darkHandle">
|
|
<text class="iconfont" :class="isDark?'icon-rijian':'icon-yejian'"></text>
|
|
<text>{{isDark?'日间':'夜间'}}</text>
|
|
</view>
|
|
<view class="item" @touchend.prevent.stop="cacheHandle">
|
|
<text v-if="!isCacheing" class="iconfont icon-xiazai"></text>
|
|
<text v-else>{{curCaches.length}}/{{chapterData.length}}</text>
|
|
<text>{{curCaches.length!==chapterData.length?'缓存':'已缓存'}}</text>
|
|
</view>
|
|
<view class="item" @touchend.prevent.stop="settingHandle">
|
|
<text class="iconfont icon-shezhi"></text>
|
|
<text>设置</text>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 听书 -->
|
|
<view v-if="!settingFlag" class="listen" :style="{color:bgColor}" @touchend.prevent.stop="listenHandle">听
|
|
</view>
|
|
|
|
<!-- 设置 -->
|
|
<view class="setting" v-show="settingFlag"
|
|
:style="{backgroundColor:bgColor,color:textColor,boxShadow: `0 -2rpx 8rpx ${textColor}29`}"
|
|
@touchend.stop>
|
|
<view class="line">
|
|
<view class="title">字号</view>
|
|
<cus-button data-str="-" bgColor="rgba(0,0,0,.1)" :textColor="textColor" width="60px"
|
|
fontSize="14px" :disabled="fontSize<=minFontSize" :border="false" @click="changeFontSize(-2)">A
|
|
</cus-button>
|
|
<view style="margin: 0 8px;">{{fontSize}}</view>
|
|
<cus-button data-str="+" bgColor="rgba(0,0,0,.1)" :textColor="textColor" width="60px"
|
|
fontSize="14px" :disabled="fontSize>=maxFontSize" :border="false" @click="changeFontSize(2)">A
|
|
</cus-button>
|
|
</view>
|
|
<view class="line">
|
|
<view class="title">背景</view>
|
|
<cus-button class="background" v-for="(item,index) in bgColorList" :key="index" :bgColor="item"
|
|
:border="index===colorType" @click="changeBackground(index)">
|
|
</cus-button>
|
|
</view>
|
|
<view class="line">
|
|
<view class="title">翻页</view>
|
|
<cus-button v-for="(item,index) in turnTypeList" :key="index" :bgColor="bgColor" :border="true"
|
|
:textColor="textColor" width="60px" :hairLine="index!==turnType" @click="changeTurnType(index)">
|
|
{{item}}
|
|
</cus-button>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 侧边目录 -->
|
|
<view class="fixed catalog" v-show="catalogFlag">
|
|
<view class="mask" @tap="catalogFlag=false"></view>
|
|
<view class="catalog-content" :style="{backgroundColor:bgColor,color:textColor}">
|
|
<view class="order iconfont" :class="descFlag?'icon-paixu1':'icon-paixu'"
|
|
@touchend.prevent.stop="sortHandle">
|
|
</view>
|
|
<scroll-view class="scroll-view" scroll-y="true" :scroll-into-view="'siv'+sivId">
|
|
<view :class="{'reverse':descFlag}">
|
|
<view class="item" :id="'siv'+index"
|
|
:class="{'text-gray':curCaches.includes(item.index),'text-red':chapterIndex===index}"
|
|
v-for="(item,index) in chapterData" :key="item.index" @tap="clickCatalog(index)">
|
|
<view class="chapter-name">{{item.title}}</view>
|
|
<view v-if="curCaches.includes(item.index)">已缓存</view>
|
|
</view>
|
|
</view>
|
|
</scroll-view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<script>
|
|
import {
|
|
mapGetters,
|
|
mapMutations
|
|
}
|
|
from 'vuex'
|
|
export default {
|
|
return: {
|
|
// 背景色
|
|
bgColor: {
|
|
type: String,
|
|
default: '#cdeeda'
|
|
},
|
|
// 字体颜色
|
|
textColor: {
|
|
type: String,
|
|
default: '#000'
|
|
},
|
|
// 夜间模式背景色
|
|
darkBgColor: {
|
|
type: String,
|
|
default: '#000000'
|
|
},
|
|
// 夜间模式字体颜色
|
|
darkTextColor: {
|
|
type: String,
|
|
default: '#666666'
|
|
},
|
|
// 是否是夜间模式
|
|
isDark: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
// 字体大小
|
|
fontSize: {
|
|
type: Number,
|
|
default: 16
|
|
},
|
|
// 背景颜色列表
|
|
bgColorList: {
|
|
type: Array,
|
|
default: []
|
|
},
|
|
// 字体颜色列表
|
|
textColorList: {
|
|
type: Array,
|
|
default: []
|
|
},
|
|
// 翻页方式列表
|
|
turnTypeList: {
|
|
type: Array,
|
|
default: []
|
|
},
|
|
// 颜色类别,对应颜色列表的下标
|
|
colorType: {
|
|
type: Number,
|
|
default: 0
|
|
},
|
|
// 翻页方式类别,对应翻页方式列表的下标
|
|
turnType: {
|
|
type: Number,
|
|
default: 0
|
|
},
|
|
// 章节列表
|
|
chapterData: {
|
|
type: Array,
|
|
default: []
|
|
},
|
|
// 当前章节的下标
|
|
chapterIndex: {
|
|
type: Number,
|
|
default: 0
|
|
},
|
|
},
|
|
data() {
|
|
return {
|
|
menuFlag: false, // 控制菜单的显隐
|
|
settingFlag: false, // 控制设置的显隐
|
|
minFontSize: 15,
|
|
maxFontSize: 40,
|
|
|
|
catalogFlag: false, // 控制目录的显隐
|
|
descFlag: false, // 是否倒序排序
|
|
sivId: null, // 打开目录时跳转至位置
|
|
|
|
curCaches: [], // 缓存的章节id
|
|
isCacheing: false, // 是否缓存中
|
|
}
|
|
},
|
|
computed: {
|
|
...mapGetters({
|
|
setting: 'get_setting',
|
|
curSource: 'get_curSource',
|
|
}),
|
|
},
|
|
watch: {
|
|
curCaches: {
|
|
handler(nVal, oVal) {
|
|
if (nVal.length === this.chapterData.length) {
|
|
this.isCacheing = false
|
|
}
|
|
},
|
|
deep: true,
|
|
immediate: true
|
|
}
|
|
},
|
|
methods: {
|
|
...mapMutations(['set_setting']),
|
|
// 显示操作菜单
|
|
async show() {
|
|
this.menuFlag = true
|
|
|
|
if (this.chapterData && this.chapterData.length > 0) {
|
|
// 从缓存获取信息
|
|
// bookChapterCache
|
|
let bcc = await this.$fileReader(`_bcc_${this.curSource.value}_${this.chapterData[0].id}`)
|
|
this.curCaches = JSON.parse(bcc || '[]')
|
|
}
|
|
},
|
|
hide() {
|
|
this.menuFlag = false
|
|
this.settingFlag = false
|
|
this.$emit('whenHide')
|
|
},
|
|
// 章节目录的显示
|
|
catalogHandle() {
|
|
this.catalogFlag = true
|
|
this.settingFlag = false
|
|
this.hide()
|
|
|
|
this.$nextTick(function() {
|
|
this.sivId = this.chapterIndex === 0 ? 0 : this.chapterIndex - 5
|
|
})
|
|
},
|
|
// 夜间/日间
|
|
darkHandle() {
|
|
this.$emit('updateProps', [
|
|
['isDark', !this.isDark],
|
|
])
|
|
this.changeBackground(this.colorType, !this.isDark)
|
|
},
|
|
// 缓存
|
|
async cacheHandle() {
|
|
if (this.isCacheing) {
|
|
return
|
|
}
|
|
|
|
if (this.curCaches.length === this.chapterData.length) {
|
|
return
|
|
}
|
|
|
|
this.isCacheing = true
|
|
for (let chapter of this.chapterData) {
|
|
if (this.curCaches.includes(chapter.index)) {
|
|
continue
|
|
}
|
|
await this.doBookContent(chapter)
|
|
}
|
|
this.isCacheing = false
|
|
},
|
|
async doBookContent(params, num = 0) {
|
|
if (num === 20) {
|
|
return false
|
|
}
|
|
|
|
let res = await this.$store.dispatch('getBookContent', params)
|
|
if (res) {
|
|
this.curCaches.push(params.index)
|
|
return true
|
|
} else {
|
|
num += 1
|
|
await this.doBookContent(params, num)
|
|
}
|
|
},
|
|
// 设置
|
|
settingHandle() {
|
|
this.settingFlag = !this.settingFlag
|
|
},
|
|
// 听书
|
|
listenHandle() {
|
|
this.$emit('listenHandle')
|
|
},
|
|
changeFontSize(num) {
|
|
this.$emit('updateProps', [
|
|
['fontSize', this.fontSize + num],
|
|
])
|
|
this.$emit('updatePage')
|
|
},
|
|
changeBackground(index, isDark) {
|
|
if (isDark) {
|
|
this.$emit('updateProps', [
|
|
['bgColor', this.darkBgColor],
|
|
['textColor', this.darkTextColor]
|
|
])
|
|
} else {
|
|
this.$emit('updateProps', [
|
|
['bgColor', this.bgColorList[index], true],
|
|
['textColor', this.textColorList[index], true],
|
|
['colorType', index],
|
|
])
|
|
}
|
|
},
|
|
changeTurnType(index) {
|
|
this.$emit('updateProps', [
|
|
['turnType', index],
|
|
])
|
|
},
|
|
// 点击某一章节目录
|
|
async clickCatalog(index) {
|
|
this.catalogFlag = false
|
|
this.sivId = index
|
|
this.$emit('updateCatalog', index)
|
|
},
|
|
// 排序
|
|
sortHandle() {
|
|
this.descFlag = !this.descFlag
|
|
},
|
|
moreHandle() {
|
|
this.$emit('moreHandle')
|
|
},
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss">
|
|
.fixed {
|
|
position: fixed;
|
|
top: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
left: 0;
|
|
background-color: transparent;
|
|
z-index: 1024;
|
|
}
|
|
|
|
.menu {
|
|
|
|
.bottom {
|
|
position: absolute;
|
|
width: 100%;
|
|
height: 80px;
|
|
bottom: 0;
|
|
display: flex;
|
|
justify-content: space-around;
|
|
align-items: center;
|
|
font-size: 11px;
|
|
|
|
.item {
|
|
width: 100%;
|
|
height: 80px;
|
|
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: center;
|
|
align-items: center;
|
|
|
|
.iconfont {
|
|
font-size: 21px;
|
|
}
|
|
|
|
text {
|
|
line-height: 21px;
|
|
}
|
|
}
|
|
}
|
|
|
|
.setting {
|
|
position: absolute;
|
|
bottom: 80px;
|
|
width: 100%;
|
|
padding: 20px 0;
|
|
background-color: rgba($color: #000000, $alpha: 0.8);
|
|
font-size: 11px;
|
|
|
|
.line {
|
|
padding: 0 40rpx;
|
|
display: flex;
|
|
justify-content: flex-start;
|
|
align-items: center;
|
|
|
|
.title {
|
|
margin-right: 40rpx;
|
|
}
|
|
|
|
.background+.background {
|
|
margin-left: 30px;
|
|
}
|
|
}
|
|
|
|
.line+.line {
|
|
padding-top: 24px;
|
|
}
|
|
}
|
|
}
|
|
|
|
.catalog {
|
|
width: 600rpx;
|
|
|
|
.mask {
|
|
position: fixed;
|
|
width: 100%;
|
|
height: 100%;
|
|
background-color: #000000;
|
|
opacity: 0.5;
|
|
}
|
|
|
|
.catalog-content {
|
|
position: absolute;
|
|
width: 100%;
|
|
height: 100%;
|
|
padding-top: var(--status-bar-height);
|
|
|
|
.order {
|
|
position: sticky;
|
|
top: 0;
|
|
padding: 32rpx 40rpx;
|
|
text-align: right;
|
|
font-size: 50rpx;
|
|
line-height: 56rpx;
|
|
}
|
|
|
|
.scroll-view {
|
|
height: calc(100% - 120rpx);
|
|
box-sizing: border-box;
|
|
opacity: 1;
|
|
|
|
.item {
|
|
padding: 0 10px;
|
|
height: 36px;
|
|
line-height: 36px;
|
|
font-size: 12px;
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
|
|
.chapter-name {
|
|
width: 480rpx;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
.listen {
|
|
position: fixed;
|
|
bottom: 120px;
|
|
right: 20px;
|
|
width: 60px;
|
|
height: 60px;
|
|
line-height: 60px;
|
|
border-radius: 50%;
|
|
background-color: #6b6b6b;
|
|
text-align: center;
|
|
font-size: 30px;
|
|
z-index: 999;
|
|
}
|
|
|
|
.reverse {
|
|
display: flex;
|
|
flex-direction: column-reverse;
|
|
}
|
|
|
|
.text-gray {
|
|
color: #999999;
|
|
}
|
|
|
|
.text-red {
|
|
color: #ff0000;
|
|
}
|
|
</style>
|