123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250 |
- import React, { useState, useEffect, useRef } from 'react';
- import { View, Text, ScrollView } from '@tarojs/components';
- import { observer, inject } from 'mobx-react';
- import './index.less';
- import TopNavBar from '@src/components/TopNavBar/index';
- import Taro from '@tarojs/taro';
- import BookConfigPuP from '@src/components/bookConfigPup';
- import { BookStore } from '@src/store/book';
- import useApi from '@src/Hook/useApi';
- import { getReadLog, setReadLog } from '@src/utils/loginSto';
- interface Config {
- size: 'pre_15' | 'pre_17' | 'pre_19' | 'pre_21' | 'pre_23' | 'pre_25' | 'pre_27' | 'pre_29' | any;
- off_on: boolean;
- bg: 'bg_b' | 'bg_h' | 'bg_l' | 'bg_hh';
- lh: 'lh_72' | 'lh_84' | 'lh_96';
- }
- type PageStateProps = {
- store: {
- bookStore: BookStore,
- indexStore,
- appInfoStore
- }
- };
- interface BookArticleProps extends PageStateProps { }
- const BookArticle: React.FC<BookArticleProps> = ({ store }) => {
- const [isLoad, setIsLoad] = useState(false)
- const { bookStore, indexStore, appInfoStore } = store
- const { openBookData } = bookStore
- const [bookConfig, setBookConfig] = useState<Config>({ size: 'pre_21', off_on: true, bg: 'bg_b', lh: 'lh_72' });
- const [pup, setPup] = useState(false);
- const { getBookContent,readingBook } = useApi(appInfoStore)
- const [currentScrollId, setCurrentScrollId] = useState('');
- const newReadLogIdRef = useRef("");
- const readLogInterval = useRef<NodeJS.Timeout>()
- // 页面显示的操作请求
- useEffect(() => {
- // ComponentDidMount
- try {
- Taro.getStorage({
- key: 'bookConfig',
- success: (res) => {
- setBookConfig(JSON.parse(res.data));
- },
- fail: () => {
- setConfig({ size: 'pre_21', off_on: true, bg: 'bg_b', lh: 'lh_72' });
- }
- });
- } catch (e) {
- console.error('Error loading book config:', e);
- }
- //假如存在阅读记录获取对应章节的条数
- let readLogId = getReadLog(openBookData?.bookId)
- getBookContent({ pageNum: 1, pageSize: readLogId ? Number(readLogId?.split('-')[1]) : 2 }).then(res => {
- //继续阅读时跳转到上次阅读的段落
- console.log("上次阅读到readLogId", readLogId)
- setCurrentScrollId(readLogId)
- })
- }, []);
- // 页面卸载的操作
- useEffect(() => {
- reportRead()
- return () => {
- console.log("卸载", newReadLogIdRef.current);
- openBookData && setReadLog({ [openBookData.bookId]: newReadLogIdRef.current })//离开时存放当前位置
- clearInterval(readLogInterval.current)//清除上报心跳
- };
- }, [])
- // 这里可以填写上报逻辑
- const reportRead = () => {
- console.log("上报", newReadLogIdRef.current)
- openBookData && setReadLog({ [openBookData.bookId]: newReadLogIdRef.current })
- if(readLogInterval.current){
- clearInterval(readLogInterval.current)
- }
- // 定时上报心跳
- readLogInterval.current = setInterval(() => {
- readingBook(bookStore.readId)
- console.log("上报阅读心跳",newReadLogIdRef.current,bookStore.readId)
- }, 3000);
- };
- //设置配置
- const setConfig = (data: Config) => {
- if (data) {
- setBookConfig(data);
- Taro.setStorage({
- key: 'bookConfig',
- data: JSON.stringify(data),
- success: (res: any) => {
- console.log('添加bookConfig===>成功!', res);
- },
- fail: (err) => {
- console.log('添加bookConfig===>失败', err);
- }
- });
- // 控制自义定头部背景
- store.bookStore.setData({ bookConfig: data });
- }
- };
- /**计算字体 */
- const setSize = (parms: number) => {
- let num = bookConfig.size.split('_');
- if (num[1] && parms) {
- setConfig({ ...bookConfig, size: num[0] + '_' + (Number(num[1]) + 2) });
- } else {
- setConfig({ ...bookConfig, size: num[0] + '_' + (Number(num[1]) - 2) });
- }
- };
- /**设置背景 */
- const setBg = (bg: 'bg_b' | 'bg_h' | 'bg_l' | 'bg_hh') => {
- setConfig({ ...bookConfig, bg });
- if (!bookConfig.off_on) {
- setOff(bg);
- }
- };
- /**设置行高*/
- const setLh = (lh: 'lh_72' | 'lh_84' | 'lh_96') => {
- setConfig({ ...bookConfig, lh });
- };
- /**关灯 */
- const setOff = (bg?: 'bg_b' | 'bg_h' | 'bg_l' | 'bg_hh') => {
- const newOffOn = !bookConfig.off_on;
- const newConfig = bg ? { ...bookConfig, bg, off_on: newOffOn } : { ...bookConfig, off_on: newOffOn };
- setConfig(newConfig);
- Taro.setNavigationBarColor({
- frontColor: newOffOn ? '#000000' : '#ffffff',
- backgroundColor: newOffOn ? '#fff' : '#111111'
- });
- };
- /**菜单 */
- const togglePup = () => {
- setPup(!pup);
- };
- //设置setNavigationBarColor
- useEffect(() => {
- Taro.setNavigationBarColor({
- frontColor: bookConfig.off_on ? '#000000' : '#ffffff',
- backgroundColor: bookConfig.off_on ? '#fff' : '#111'
- });
- }, [bookConfig.off_on]);
- const onLoad = async () => {
- if (openBookData?.contentData) {
- let { size, current, total, records } = openBookData.contentData
- if (records.length < total) {
- console.log("加载")
- setIsLoad(true)
- await getBookContent({ pageNum: 1, pageSize: size + 2 }).then(res => {
- setIsLoad(false)
- })
- } else {
- Taro.showToast({
- title: '没有更多了~~',
- duration: 1000,
- icon: 'none'
- })
- }
- }
- }
- // 计算阅读的位置,存放以备下次阅读的时候跳转到对应位置
- const handleScroll = () => {
- const query = Taro.createSelectorQuery();
- query.selectAll('.shrot-text').boundingClientRect(); // 选择所有子元素
- query.selectViewport().scrollOffset(); // 获取视口的滚动位置
- query.exec(res => {
- const items = res[0]; // 子元素的位置信息
- const scrollTop = res[1].scrollTop + indexStore.navHeight; // 视口的滚动距离
- // 遍历所有子元素,判断哪个子元素在可视区域
- for (let item of items) {
- if (item.top <= scrollTop && item.bottom >= scrollTop) {
- if (openBookData?.bookId) {
- newReadLogIdRef.current = item.id//存放当前可视的段落ID
- }
- break;
- }
- }
- });
- };
- const { size, bg, off_on, lh } = bookConfig;
- return (
- <ScrollView
- lowerThreshold={indexStore.navHeight}
- // refresherTriggered={isLoad}//加载状态
- onScrollToLower={onLoad}
- style={{ height: `calc(100vh - ${indexStore.navHeight}px)` }}
- scrollY={true}
- refresherDefaultStyle='black'
- scrollWithAnimation={false}
- scrollIntoView={currentScrollId}
- onScroll={handleScroll}
- >
- <View className={`book_article ${off_on ? bg : 'bg_hh'} ${off_on ? 'cl_h' : 'cl_b'}`} >
- {/* 顶部设置 */}
- <View className='header'>
- <View className='btns'>
- <View className='left'>
- <Text
- onClick={() => { size !== 'pre_15' && setSize(0) }}
- className={!off_on ? size === 'pre_15' ? 'cl_e5' : '' : size === 'pre_15' ? 'cl_d6' : ''}
- >字小</Text>
- <Text
- onClick={() => { size !== 'pre_29' && setSize(1) }}
- className={!off_on ? size === 'pre_29' ? 'cl_e5' : '' : size === 'pre_29' ? 'cl_d6' : ''}
- >字大</Text>
- </View>
- <View className='right'>
- <Text onClick={() => { setOff() }}>{off_on ? '关灯' : '开灯'}</Text>
- {isLoad && <Text onClick={togglePup}>菜单</Text>}
- </View>
- </View>
- </View>
- {/* 正文内容 */}
- <View onClick={togglePup}>
- {
- openBookData?.contentData?.records?.map(item => {
- let arr = item.paragraphInfo.content?.match(/[^\n]*\n?/g);
- return <View
- id={'paragraphNo-' + item.paragraphInfo.paragraphNo}
- key={item.paragraphInfo.paragraphNo}
- className={`pre ${size} ${lh}`}
- >
- {
- arr?.map((str, index) => {
- // let strArr = str?.match(/[^。]*。/g)
- return <Text className='shrot-text' id={'paragraphNo-' + item.paragraphInfo.paragraphNo + '-' + index} key={index}>{
- str
- }</Text>
- })
- }
- </View>
- })
- }
- </View>
- {/* 设置弹窗 */}
- {pup && <BookConfigPuP {...bookConfig} off_on={off_on} setOff={setOff} setSize={setSize} setBg={setBg} setLh={setLh} />}
- </View>
- {/* 底部下来加载 */}
- {/* {
- isLoad && <UpLoading />
- } */}
- </ScrollView>
- );
- };
- export default inject('store')(observer(TopNavBar(BookArticle, { isToBack: true, isReloadBook: true })));
|