[yishen] 小慕读书web端学习笔记
课程常用链接
【前奏-课程】快速入门Web阅读器开发
【小慕读书web端】Vue 实战商业级读书Web APP 全面提升技能
【epub图书免费下载站点 · 中文书】http://www.ziliaoh.com/epub.html
【项目代码gitee】https://gitee.com/yishen_yishen/vue-ebook 如果对你有帮助欢迎点个 star
【md格式 源文档下载】下载链接 在线阅读可能会乱码(我知道是编码问题,但在七牛云里不知道怎么修改),请下载后查看
阅读器原理课程-免费课
概览
知识点脑图
阅读器工作原理
- epubjs文档
环境搭建
vue-cli环境
- 环境准备
iMac-Pro:code yishen$ node -v
v14.0.0
iMac-Pro:code yishen$ npm -v
6.14.5
iMac-Pro:code yishen$ vue -V
2.9.6
离线版安装
- GitHub下载webpack 下载到桌面,然后解压
cd ~ cd .vue-templates/ cp -R ~/Desktop/webpack-develop webpack # -R 是将目录下所有文件复制到新目录webpack下 cd ~/Desktop # 项目路径,后面会在此路径下新建项目文件夹 vue init webpack --offline ebook-read # 新建ebook-read项目,并初始化
启动vue项目
npm run dev
sass支持
npm install node-sass sass-loader --save-dev
epubjs扩展
npm install epubjs --save
项目配置
viewport配置
viewport用来设置用户在手机上的可视区域
width=device-width:指定viewport宽度为设备宽度;inital-scale=1.0:指定默认缩放比例为1:1
通过maximum-scale和minimun-scale限定屏幕缩放比例为1:1,通过user-scalable限制用户对屏幕进行缩放
项目根目录Index.html文件,内部
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0,user-scalable=no">
rem配置
rem是css3新增的一个相对长度单位
rem相当于根元素font-size值的倍数
- 2rem = 根元素font-size *2
DOMCotentLoaded事件动态设置根元素font-size
html.style.fontSize = window.innerWidth / 10 + 'px'
/src/App.vue文件,<script>内部
document.addEventListener('DOMContentLoaded', () => {const html = document.querySelector('html')let fontSize = window.innerWidth / 10fontSize = fontSize > 50 ? 50 : fontSizehtml.style.fontSize = fontSize + 'px' })
reset.scss和global.scss
- Reset.scss是为了消除不同浏览器默认样式的不一致性
- Global.scss规定整个站点的公共样式,公共方法和公共参数
- 实现px2rem方法,将px转化为rem
- Reset.scss代码 参考链接
/* http://meyerweb.com/eric/tools/css/reset/ v2.0 | 20110126License: none (public domain)
*/html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {margin: 0;padding: 0;border: 0;font-size: 100%;font: inherit;vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {display: block;
}
body {line-height: 1;
}
ol, ul {list-style: none;
}
blockquote, q {quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {content: '';content: none;
}
table {border-collapse: collapse;border-spacing: 0;
}
html,body{width: 100%;height: 100%;font-family: 'PingFangSC-Light','PingFang SC','StheitiSC-Light','Helvetica-Light','Arial','sans-serif';
}
- global.scss代码
@import 'reset';// 1rem = fontSize px
// 1px = (1 / fontSize)rem
$fontSize:37.5;@function px2rem($px) {@return ($px / $fontSize)+rem;
}@mixin center() {display: flex;justify-content: center;align-items: center;
}
web端小慕读书-付费课
环境搭建
Node.js环境
nvm工具的使用
nvm作用:node version manger,node版本管理工具
nvm github地址https://github.com/nvm-sh/nvm
nvm安装
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.3/install.sh | bash
nvm常用命令
- 换淘宝源
export NVM_NODEJS_ORG_MIRROR=https://npm.taobao.org/mirrors/node
- 其他
nvm install node // 安装最新版nodejs
nvm install 10.10.0 // 安装指定版本
nvm use 10.10.0 // 切换到指定版本
Vue CLI 3.0环境搭建
- 卸载老版本
npm unistall vue-cli -g
- 安装新版本
npm install -g @vue/cli
- 原型开发
npm install -g@vue/cli-service-global
npm i -g @vue/cli-service-global
vue.config.js文件配置
作用:解决production模式下路径问题(虽然我没看懂代码╮( ̄▽ ̄)╭)
注意:baseUrl在Vue CLI 3.3被废弃,新版本使用publicPath
module.exports = {publicPath: process.env.NODE_ENV === 'production'? './': '/'
}
Vue-remote-devtools调试工具
此工具与Chrome插件功能相同,一个是浏览器扩展,一个独立分离出来,可以不安装
GitHub地址
安装
npm install -g @vue/devtools
添加--verbose
可以查看安装进度,以及请求地址npm 配置
Electron,安装上述工具时,可能会需要安装这个Electron,不过由于网络的原因,会下载失败。
修改 ~/.npmrc 文件,添加一行ELECTRON_MIRROR=“https://cdn.npm.taobao.org/dist/electron/”
- 添加
<script src="http://localhost:8098"></script>
到/public/index.html- 项目上线时,要删除掉这句话
epubjs扩展
npm i --save epubjs
sass扩展
npm i --save-dev node-sass sass-loader
sass报错:this.getResolve is not a function
版本过高引起的,或其他低版本的不适用高版本sass
可降低sass版本解决
npm uninstall sass-loader npm i -D sass-loader@7.3.1
web字体引入
谷歌字体api
- 谷歌字体api https://developers.google.com/fonts/docs/css2
使用方法
[三方汉化]谷歌字体api
- 谷歌中文字体api(第三方汉化):地址
font-family: 'Hanalei Fill', cursive;
font-family: 'Kirang Haerang', cursive;
font-family: 'Merriweather', serif;
font-family: 'MedievalSharp', cursive;
font-family: 'Ranga', cursive;
Nignx搭建静态服务器
Nginx.org
mac上安装Nignx需要先安装brew
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
一般来说会由于网络原因,安装失败(挂代理也不能使用:git默认不走代理,即使能正常访问GitHub,clone仓库时也非常慢,所以需要为git配置代理)
国内下载方式
/bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)"
参考链接,知乎 , gitee
brew 安装nginx
brew install nginx
运行nginx
sudo nginx
配置文件地址:
/usr/local/etc/nginx/nginx.conf
停止运行
sudo nginx -s stop
重新加载
sudo nginx -s reload
外链配置
项目根目录新建.env.development
文件和 .env.production
文件
VUE_APP_RES_URL=http://127.0.0.1:9001/
外部引用举例
initGlobalStyle () {console.log(this.defaultTheme)addCss(`${process.env.VUE_APP_RES_URL}/themes/theme_eye.css`)},
nginx配置相关
- 需将
autoindex on;
才可以访问目录
nodejs环境接口搭建、相关知识点
新建node-imooc-ebook文件夹,app.js入口文件
npm init
初始化npm项目,生成package.json文件安装express,
npm i express -S
;api参考手册安装mysql操作库
npm i mysql -S
Nodemon 插件
每次修改完文件,需要重新node app.js 才能执行
Nodemon app.js 在项目保存后自动重新运行项目
cors-跨域问题
什么是跨域:链接
npm i -S cors
app.js中
const cors = require('cors') app.use(cors())
知识点
vue
vue引用中的@符号
地址中的@符
当引用文件时
import '@/assets/styles/global.scss'
@代表/src
- 可以在
build/webpack.base.conf.js
中设置
- 可以在
import前面的@符
script中的import是js的语法, 是在js中去引用css文件
style中的@import是stylus的语法,是在css中引用css文件
参考链接:详解vue中常用的几种import引入方式
备用链接
transition动画原理
- 使用v-show动态显示或隐藏元素时,会触发过渡动画
- transition需要指定name,并包裹一个包含v-show的div
- vue会为transition包裹的div动态添加class,公6种
transition
代码实现
html部分。src/Ebook.vue,外围使用包裹,带上name属性,被包裹的部分要有vshow或者vif
<transition name="slide-down"><!-- 下面就是要展示动画的部分 --><divclass="title-wrapper"v-show="isTitleAndMenuShow"><div class="left"><span class="iconfont iconbackarrow"></span></div><div class="right"><div class="icon-wrapper"><span class="iconfont iconbooks"></span></div><div class="icon-wrapper"><span class="iconfont iconiconfontcart-copy"></span></div><div class="icon-wrapper"><span class="iconfont iconi-more"></span></div></div></div></transition>
* css 部分~~~scss.slide-down-enter-to,.slide-down-leave {transform: translate3d(0, 0, 0);}.slide-down-enter-active,.slide-down-leave-active {transition: all 0.3s linear;}.slide-down-enter,.slide-down-leave-to {transform: translate3d(0, -100%, 0);}
- 更多关于过渡、动画 官方说明
transition-group
参考链接-vue.js
作为多个元素/组件的过渡效果。 渲染一个真实的 DOM 元素(通过tag指定)
- 代码演示 src/components/shelf/ShelfList.vue
<template><div class="shelf-list"><transition-groupname="list"tag="div" // tag='div',这该元素渲染文divid="shelf-list"><divclass="shelf-list-item"v-for="(item, index) in shelfList":key="index">......</div></transition-group></div>
</template>
- :key引发的bug
bug描述:动画没有效果,动画的类没有加到dom上面
// 原始代码,没有任何效果,dom上没有添加.list-move,.list-leave-active等类名
<transition-groupname="list"tag="div"id="shelf-list"><divclass="shelf-list-item"v-for="(item, index) in shelfList":key="index">......</div>
</transition-group>// 修改后代码,效果正常
<transition-groupname="list"tag="div"id="shelf-list"><divclass="shelf-list-item"v-for="(item) in shelfList":key="item.id" // 修改了这里>......</div>
</transition-group>
只是把:key由原先的index修改为了item.id,我也不知道什么原因
官网中关于key的说明:内部元素总是需要提供唯一的
key
attribute 值 index不唯一吗?搜到了一个比较靠谱的答案:
交换位置后(对应到我的项目,就是删除某个),元素的key发生了变化
解决:给key值设置一个不会因为位置变化而变化的值
vue中的mixin混入
- 分发组件中的可复用功能
代码举例:
- 定义混入对象
import { mapGetters } from 'vuex'
export const ebookMixin = {computed: {...mapGetters(['fileName', 'menuVisible'])}
}
- 使用混入对象
<script>
import { ebookMixin } from '../../utils/mixin'
export default {mixins: [ebookMixin]
}
</script>
Vuex(仅代表个人理解)
概念
一句话简介:解决组件非常多时,组件之间传参的问题(个人理解) 官方地址
核心概念:state、mutations、getters、actions、module
State:相当于父组件中的props:{},定义一些子组件需要使用的变量(布尔、数组、对象、数值、字符串等)
props: { isTitleAndMenuShow: {type: Boolean,default: false},fontSizeList: Array,defaultFontSize: Number,defaultTheme: Number,themesList: Array,// 图书是否加载完毕bookAvailable: Boolean,navigation: Object},
使用举例
src/store/modules/book.js
const book = {state: {fileName: '',menuVisible: false,// 底部的菜单项,倒数第二条,-1:不显示,0:字号,1:主题、2:进度条、3:目录settingVisible: -1,},mutations: {SET_FILENAME: (state, fileName) => {state.fileName = fileName},SET_MENU_VISIBLE: (state, visible) => {state.menuVisible = visible},SET_SETTING_VISIBLE: (state, visible) => {state.settingVisible = visible}}
}
export default book
src/store/getters.js
const getters = {fileName: state => state.book.fileName,menuVisible: state => state.book.menuVisible,settingVisible: state => state.book.settingVisible
}
export default getters
src/store/actions.js
const actions = {setFontFamilyVisible: ({ commit }, visible) => {return commit('SET_FONT_FAMILY_VISIBLE', visible)},setDefaultFontFamily: ({ commit }, font) => {return commit('SET_DEFAULT_FONT_FAMILY', font)},setDefaultFontSize: ({ commit }, fontSize) => {return commit('SET_DEFAULT_FONT_SIZE', fontSize)}
}
export default actions
src/store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import book from './modules/book'
import getters from './getters'
import actions from './actions'Vue.use(Vuex)
export default new Vuex.Store({state: {},mutations: {},actions,getters,modules: {book}
})
使用
使用了混入技术,…mapGetters作用
src/utils/mixin.js
import { mapGetters, mapActions } from 'vuex'export const ebookMixin = {computed: {...mapGetters(['fileName','menuVisible','settingVisible'])},methods: {// 下面的方法用来设置上面变量的值...mapActions(['setMenuVisible','setFileName','setSettingVisible'])}
}
具体页面内使用
<script>
import { ebookMixin } from '../../utils/mixin'
export default {methods: {hideTitleAndMenu () {this.setSettingVisible(-1) // 调用setSettingVisible方法将settingVisible的值修改为-1this.setMenuVisible(false) // 可以直接this.调用}}
}
</script>
vue-i18n实现国际化
vue-i18n说明文档
- 安装插件
npm i --save vue-i18n
- 初始化i18n对象
src/lang/index.js
import Vue from 'vue'
import VueI18N from 'vue-i18n'
import en from './en'
import cn from './cn'
import { getLocale, setLocale } from '../utils/localStorage'Vue.use(VueI18N)const messages = {en, cn
}
// 通过读取缓存获取,默认语言,缓存中无数据,默认设置为cn
let locale = getLocale()
if (!locale) {locale = 'cn'setLocale('locale', locale)
}const i18n = new VueI18N({locale,messages,// 下面这项,是为了消除过多的警告silentFallbackWarn: true
})
export default i18n
silentFallbackWarn: true的作用
- vue-html中解析对应文本
<span>{{$t('book.selectFont')}}</span>
vue中alias别名的使用
解决循环渲染,需要国际化的问题
实例:设置主题 EbookSettingTheme src/utils/book.js
<div class="setting-theme"><divclass="setting-theme-item"v-for="(item, index) in themesList":key="index"@click="setTheme(index)"><divclass="preview":style="{background: item.style.body.background}":class="{'no-border':item.style.body.background !== '#fff'}"></div><divclass="text":class="{'seleted':item.name===defaultTheme}">{{item.alias}}</div></div>
</div>
export function themeList (vue) {return [{alias: vue.$t('book.themeDefault'),name: 'Default',style: {body: {color: '#000', background: '#fff'}}}]
Vue中的updated钩子
由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。无论是组件本身的数据变更,还是从父组件接收到的 props 或者从vuex里面拿到的数据有变更,都会触发虚拟 DOM重新渲染和打补丁,并在之后调用 updated。官网介绍
updateProgress(){this.$refs.progress.style.backgroundSize = `${this.progress}% 100%`;},
动态组件component
- component,动态组件
- 代码示例 src/components/ebook/EbookSlide.vue
<template><div><component :is="currentTab === 1 ? content : bookmart"></component></div>
</template>
<script>
data () {return {currentTab: 1, // 通过改变currentTab的值,就能分别渲染、切换不同组件content: EbookSlideContents, // 这是组件,记得引入,这里省略引入bookmart: EbookSlideBookMark}},
</script>
事件修饰符
.passive
参考链接-vuejs官网
这个
.passive
修饰符尤其能够提升移动端的性能。代码示例 src/components/common/Scroll.vue
<divclass="scroll-wrapper":class="{'no-scroll':ifNoScroll}"@scroll.passive="handleScroll()"ref="scrollWrapper"><slot></slot></div>
.stop,阻止点击事件向下冒泡
代码描述 [src/components/shelf/ShelfItem.vue](# TODO)
描述:避免上层的点击事件触发后,还会触发下层的点击事件
OnItemSelected触发之后不会在触发onItemClick
<template><divclass="shelf-item shelf-item-shadow":class="{'hide-shadow':data.type===3}"@click="onItemClick"><component:is="item":data="data"></component><divclass="shelf-item-selected"v-show="isEditMode && data.type ===1"@click.stop="OnItemSelected"><span class="iconfont iconselected"></span></div></div>
</template>
插槽slot标签
单插槽
- 业务描述,定义一个组件里面需要接受一些标签(父组件传递过来的)
- 子组件代码 src/components/common/Scroll.vue
<template><divclass="scroll-wrapper":class="{'no-scroll':ifNoScroll}"@scroll.passive="handleScroll"ref="scrollWrapper"><!-- 预留插槽,用来替换传递过来的内容 --><slot></slot></div>
</template>
参考链接-官网插槽最基础,深入了解插槽
- 父组件代码 src/components/ebook/EbookSlideContents.vue
<template><Scrollclass="slide-search-list":top="66":bottom="49"v-show="searchVisible"><!-- 这中间的内容都会被子组件中<slot>标签替换 --><div>我是内容</div></Scroll>
</template>
多插槽
- 子组件 src/components/common/Dialog.vue,好像叫子组件不合适呢?
<div class="dialog-wrapper"><div class="dialog-title-wrapper"><span class="dialog-title-text">{{title}}</span></div><slot><!-- 插槽一 --></slot><div class="dialog-btn-wrapper"><slot name="btn"><!-- 插槽二,中间有默认内容,父组件不传递内容,就使用默认内容 --><divclass="dialog-btn"@click="hide">{{$t('shelf.cancel')}}</div><div class="dialog-btn">{{$t('shelf.confirm')}}</div></slot></div>
</div>
- 父组件 src/components/shelf/ShelfGroupDialog.vue
<ebook-dialog:title="title"ref="dialog"><!-- 这里是插槽一的内容,省略了,没粘进来 --><!-- 下方div有slot="btn"与子组件<slot name="btn">匹配 --><divslot="btn"class="group-dialog-btn-wrapper">......</div>
</ebook-dialog>
ref指向性问题
- Ref:给元素或子组件注册引用信息
// 指向dom元素
<div ref="div"></div>// 指向组件对象
<Button ref="btn"></Button>// this.refs.btnList是一个列表,列表里的每一项是一个组件对象
<Button v-for="xx in xx" ref="btnList">
当指向dom元素时获取样式:this.$refs.scroll.style.height
当执行组件对象,获取样式:this.refs.scroll.refs.scroll.refs.scroll.el.style.height
参考链接
$nextTick
- 在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM
- 我理解的太浅,不懂vue的dom更新,以及响应式序列啥的
代码示例 src/components/home/SearchBar.vue
showHotSearch () {if (this.hotSearchOffsetY === 0) {this.hideShadow()} else if (this.hotSearchOffsetY > 0) {this.showShadow()}this.hideTitle()this.hotSearchVisible = true// TODO 重置阅读进度this.$nextTick(() => {this.$refs.hotSearch.reset()})}
参考链接
代码示例 src/views/store/StoreShelf.vue
watch: {isEditMode (isEditMode) {this.scrollBottom = isEditMode ? 48 : 0this.$nextTick(() => {// 等所有dom结构更新完后,在计算scroll的高度this.$refs.scroll.refresh()})}},
vue-create-api
一个能够让Vue组件通过API方式调用的插件
- 可以大幅度降低引用组件的代码
- 传统父组件使用子组件,需要js中引入,components中声明,html中写入DOM
- 使用此插件,可以很简单的简化
- 此插件是在body下创建dom,与vue在#app下不同,通常全屏的消息提示框,选择框使用它
GitHub文档地址
安装
npm i -S vue-create-api
代码演示
- 初始化、create-api.js(mian.js中需要引入这个文件)
import CreateAPI from 'vue-create-api'
import Vue from 'vue'
import Toast from '../components/common/Toast.vue'Vue.use(CreateAPI)
Vue.createAPI(Toast, true)
- Toast.vue组件src/components/common/Toast.vue
<script>
// 省略了很多无关代码
export default {// 必须有name,否则create-api无法使用此组件name: 'Toast',props: {text: [String, Number],timeout: {type: Number,default: 1500}},methods:{show(){this.visible = true},hide(){this.visible = false}}
}
</script>
// 其他组件的methods中使用
this.$createToast({$props: {// 这里就相当于Toase组件中的propstext: 'hello imooc'}
}).show()
- 更一步的简化
create-api.js文件
// 新增混入全局方法
Vue.mixin({methods: {toast (settings) {return this.$createToast({$props: settings})}}
})
- 使用
this.toast({ text: 'hello' }).show()
v-for和v-if一起使用
可能会报错:The ‘undefined’ variable inside ‘v-for’ directive should be replaced with a computed property that returns filtered array instead. You should not mix ‘v-for’ with ‘v-if’
原因:v-for的优先级会高于v-if,因此v-if会重复运行在每个v-for中
- 解决方法,新加一个外层()使用vfor或者vif
参考链接-vue.js
- 代码实例 src/components/shelf/ShelfGroupDialog.vue
<template v-for="(item, index) in categoryList"><divclass="dialog-list-item":class="{'is-add': item.edit ? item.edit === 1 : false}":key="index"@click="onGroupClick(item)"v-if="(item.edit === 2 && isInGroup) || item.edit !== 2 || !item.edit"></div>
</template>
样式问题以及scss
样式
绝对定位子元素居中父元素
- 父元素css
position: relative;
- 子元素css
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%); // 向左向上偏移自身的50%
超出部分用省略号代替
// 超出的部分用省略号...代替
text-overflow: ellipsis;
// 超出的部分隐藏
overflow: hidden;
// 不换行
white-space: nowrap;
显示两行,多余省略号
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
white-space: normal;
text-overflow: ellipsis;
// 允许打断单词进行换行
word-break: break-all;
// 不允许打断单词,进行换行
word-break: keep-all;
Position:absolute的其他用法
标题起的可能不合适
还可以做居中效果
@mixin absCenter {position: absolute;top: 0;bottom: 0;left: 0;right: 0;margin: auto; }
效果演示
scss语法
@mixin:混入
- 定义
// 定义一段垂直居中,水平居中的代码段
@mixin center() {display: flex;justify-content: center;align-items: center;
}
// 混入允许带参数
@mixin ellipsis2($line) {display: -webkit-box;-webkit-box-orient: vertical;// 要显示多少行-webkit-line-clamp: $line;white-space: normal;text-overflow: ellipsis;// 允许打断单词进行换行word-break: break-all;
}
- 使用
// 是left类,垂直居中,水平居中
.left{@include center;
}
.text{// 带参数的形式@include ellipsis2(2);
}
- 更多关于@mixin
&符号
- 作用:引用父元素
.dashboard {&-container {margin: 30px;}&-text {font-size: 30px;line-height: 46px;}
}
- 编译为css
.dashboard-container {margin: 30px;
}
.dashboard-text {font-size: 300px;line-height: 46px;
}
animation
动画属性,将动画绑定到一个div元素,css提供的属性,非scss
代码演示src/components/home/FlapCard.vue
.flap-card-bg {// scale:缩放transform: scale(0);opacity: 0;&.animation {// both 是动画完成后,保持在100%的效果(替代上面两行)animation: flap-card-move 0.3s ease-in both;}// 刚开始进入翻转加载的动画效果@keyframes flap-card-move {0% {transform: scale(0);opacity: 0;}50% {transform: scale(1.2);opacity: 1;}70% {transform: scale(0.9);opacity: 1;}100% {transform: scale(1);opacity: 1;}}
epubjs
epubjs原理及常用方法
原理图
- 文档地址
常用方法
api地址(网站比较慢,开全局代理)
this.rendition.prev() // 后退翻页
this.rendition.next() // 下一页
this.rendition.themes.fontSize(16px) // 设置字号// 主题
this.themeList.forEach(theme => {// 注册主题this.rendition.themes.register(theme.name, theme.style)})
this.rendition.themes.select(theme.name) // 选择主题
项目中的问题
HTML5、input实现进度条效果
- 成品展示
- 代码实现
<inputclass="progress"type="range"max="100"min="0"step="1"@change="onProgressChange($event.target.value)"@input="onProgressChange($event.target.value)":value="progress":disabled="!bookAvailable"ref="progress">
.progress {width: 100%;// 清除默认样式-webkit-appearance: none;height: px2rem(2);background: -webkit-linear-gradient(#53575d, #53575d) no-repeat, #abacae;// 下面代表已读 总的。前45%background:#53575d,其余#abacaebackground-size: 45% 100%;&:focus {outline: none;}&::-webkit-slider-thumb {// 滑块的样式-webkit-appearance: none;height: px2rem(15);width: px2rem(15);border-radius: 50%;background: #fff;box-shadow: 0 4px 4px 0 rgba($color: #000000, $alpha: 0.15);border: px2rem(1) solid #ddd;}}
项目中设置字体
- 引入选好的字体API api地址 (此api是英文字体,对中文不起作用,没找到中文字体的Api)
由于epub解析图书,是依赖于iframe的,外层的字体文件无法直接传递到内层的iframe(大概是这个意思,不太懂),所以需要使用epub提供的一个register()方法,来使内层iframe获取到字体样式
src/components/ebook/EbookReader.vue
this.rendition.hooks.content.register(contents => {Promise.all([contents.addStylesheet('https://fonts.font.im/css?family=Hanalei+Fill|Kirang+Haerang|Merriweather|MedievalSharp|Ranga')]).then(() => {// console.log('字体全部加载完毕。。。')})})
src/components/ebook/EbookSettingFontPopup.vue
- 调用themes下的font()方法设置字体
setFontFamily (font) {// font 是字体名称this.setDefaultFontFamily(font)this.currentBook.rendition.themes.font(font)}
缓存问题,相当于小程序中的storage
- 安装包
npm i --save web-storage-cache
- 使用,封装常用函数
import Storage from 'web-storage-cache'const localStorage = new Storage()export function setLocalStorage (key, value) {return localStorage.set(key, value)
}
export function getLocalStorage (key) {return localStorage.get(key)
}
export function removeLocalStorage (key) {return localStorage.delete(key)
}
export function clearLocalStorage (key) {return localStorage.deleteAllExpires(key)
}
- 可在以下位置查看缓存,可以手动修改
cssText设置属性!important
- 说明:需要为一个属性设置!important
src/components/ebook/EbookSettingProgress.vue
updateProgressBg () {// 背景色变化,样式已经写好,更改background-size即可// ASK 标记,浪费了老子贼多时间,搞这个问题,不知道哪里冲突不加!important就是不行this.$refs.progress.style.cssText = `background-size:${this.progress}% 100% !important;`// this.$refs.progress.style.backgroundSize = `${this.progress}% 100%`},
常用js操作css方法
// 方法一
var obj = document.getElementById('no');
function setStyle(obj, css) {
for(var attr in obj){
obj.style[attr] = css[attr];
}
}
setStyle(obj,{width:"400px",height:"300px"});
// 方法二,个人感觉此方法简单,还可以设置!important,方法一不知道可不可以
var obj = document.getElementById('no');
obj.style.cssText = "width:400px; height:300px;";
font-size=0消除空行
- 代码举例 src/components/ebook/EbookSlideContents.vue
.slide-contents-book-progress {font-size: 0;.progress {font-size: px2rem(14);}.progress-text {font-size: px2rem(12);}
}
其他知识点
blob链接
- 参考链接 简书-通俗一些 官网-MDN 维基百科-blob
业务代码:src/components/ebook/EbookReader.vue
// 解析电子书内容,获取封面,标题,作者等信息
parseBook () {// 获取coverthis.book.loaded.cover.then(cover => {this.book.archive.createUrl(cover).then(url => {// url----blob:http://localhost:8080/ecf9934c-1313-4b3d-9647-caa7acafb152this.setCover(url)})})
}
js语法二维数组变一维数组.concat.apply用法
// .concat()用法:连接两个数组
a=[1,2,3,4,5]
b=[2,3,4,5,6,7]
[].concat(a,b) --> [1, 2, 3, 4, 5, 2, 3, 4, 5, 6, 7]
// .apply()用法,使用apply将他们([],c)作为形参传入,将数组中的对象逐一的传入到concat中(老师原话,不太理解)
c=[[1,2,3],[9,9,9]]
[].concat.apply([],c) -->[1, 2, 3, 9, 9, 9]
apply()用法:能改变this的指向(个人理解),参考链接-w3school,菜鸟教程
数组常用方法
filter()
创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素;
不会对空数组进行检测;
不会改变原始数组;
项目实例:src/components/ebook/EbookBookmark.vue
removeBookmark () {console.log('删除书签')const currentLocation = this.currentBook.rendition.currentLocation()const cfi = currentLocation.start.cfithis.bookmark = getBookmark(this.fileName)if (this.bookmark) {// 保留缓存中,cfi项与要删除的cfi不相同的----> 删除与cif相同的saveBookmark(this.fileName, this.bookmark.filter(item => item.cfi !== cfi))}}
参考链接 菜鸟教程
Array.some()
检测数组中国的元素是否满足指定条件
有一个满足条件的元素,即返回true,剩余的元素不在执行检测
Array.every()
every() 方法用于检测数组所有元素是否都符合指定条件(通过函数提供)。
every() 方法使用指定函数检测数组中的所有元素:
- 如果数组中检测到有一个元素不满足,则整个表达式返回 false ,且剩余的元素不会再进行检测。
- 如果所有元素都满足条件,则返回 true。
Array.map()
map()方法返回一个新数组,数组中的元素为原始数组元素调用函数处理后的值
map()方法按照原始数组元素顺序依次处理元素
注意: map() 不会对空数组进行检测。
注意: map() 不会改变原始数组
mock.js–生成随机数据,拦截Ajax请求
官网地址
- 安装
npm i mockjs --D/--save-dev
,安装axios-发送网络请求用的npm - axios --save
indexDB
localforage
- 安装
npm i -S localforage
- 对indexDB进行操作的一个库
项目构建、发布
修改到线上地址
根目录的.env.production文件是线上版本的一些接口路径
.env.development 是开发版本的一些接口路径
.env.production文件内容
# nginx跟地址,不知道能不能加注释,反正没报错 VUE_APP_RES_URL=http://127.0.0.1:9001 # nginxepub目录 # VUE_APP_EPUB_URL=http://127.0.0.1:9001/epub VUE_APP_EPUB_URL=http://47.99.166.157/epub # api请求的根地址 VUE_APP_BASE_URL=http://localhost:8080 # 线上的api接口地址(老师的) VUE_APP_BOOK_URL=http://47.99.166.157:3000 # 所有的电子书,相当于nginx的资源目录 VUE_APP_EPUB_OPF_URL=http://47.99.166.157/epub2 # 老师的封装好的讯飞文字转语音api地址 VUE_APP_VOICE_URL=http://47.99.166.157:3000
构建生产版本
npm run build
构建过程中警告处理
文件大小超出
// vue.config.js文件内,与devServer同级,扩大资源限制到512 * 1024 (根据自己的项目来)
configureWebpack: {performance: {hints: 'warning',maxAssetSize: 524288,maxEntrypointSize: 524288}}
- 将引用的一些库,替换成线上cdn版本
例如:将本项目中占用资源最大的epubjs换成线上cdn版本(引用的版本应与本地版本一致,不要盲目最新版)
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.1.5/jszip.min.js"></script>
添加到public/index.html的内部
console.log警告
- 少的化,搜索全部注释或者删除
- 多的化,https://blog.csdn.net/u013611033/article/details/104152300
需要注意的地方
驼峰命名&’-'命名
vue html部分,类名尽量使用"-",不要使用驼峰命名法(好像是因为不识别大小写的原因)
在有些地方,驼峰和’-'好像是一样的,例如fileName 和 file-name是表示同一个东西;
css中font-size、js操作css属性可以写作fontSize;
项目中各组件z-index
read阅读器页面
- #slide-content-wrapper,目录的侧边栏300
- #title-wrapper,上面的菜单栏201
- #menu-wrapper,下面的菜单栏201
- EbookSettingProgress中的#setting-wrapper,阅读进度200
- EbookSettingTheme中的#setting-wrapper,设置主题200
- EbookSettingFont中的#setting-wrapper,设置字体字号200
- #ebook-reader-mask,主页的蒙版(用来触发点击事件)150
StoreHome页面
searchBar组件
- .search-bar ,标题行,和输入框行 z-index:150
- .title-icon-back-wrapper ,左上方的返回图标,要大于.search-bar。z-index:200
FlapCard组件
- .flap-card-wrapper,用来显示推荐图书(伴有动画),浮在最上层:z-index:1000
- class=“flap-card”,展示动画变化用的,是动态变化的,范围是100-96
- .read-btn,推荐图书的立即阅读按钮,要在.flap-card-wrapper(1000)之上,zIndex:1100
StoreShelf页面
shelfTitle组件
- .shelf-title,zindex-130,要在当前页面的最上层
主页面内
- .store-shelf-scroll-wrapper,zindex:101
shelfFooter组件
- .shelf-footer,编辑状态下,下面的菜单栏,zindex:120
- .popup,点击下方的tab弹出的菜单框,zindex:2080
git的使用
首次使用,配置公钥。。。
- 留白,以后补充 //TODO
初始化,首次push
git init
touch README.md
git add README.md
git commit -m "提交显示的信息"
git remote add origin git地址
git push -u origin master
第二次push
git add .
git commit "第二次push"
git push
git表状态字符
字符状态
A: 工作区新增的文件
C: 文件的一个新拷贝
D: 你本地删除的文件,服务器上还在
M: 文件的内容或者mode被修改
R: 文件名被修改了
T: 文件的类型被修改了
U: 文件没有被合并,需要完成合并才能进行提交
X: 未知状态
颜色状态
绿色:新增文件
黑色:别删除文件
蓝色:之前已经存在,被修改文件
红色:新增,但是没有增加到git中
为git设置代理
- 修改 ~/.gitconfig 文件
- 注意:ssr走的是socks5
参考链接 参考链接
已知的BUG&优化
已知的BUG
- 当使用主题时,章节翻页时,会闪一下白色(老师的也会闪一下,但底色与主题颜色相同-背景色修改为了灰色不是白色不那么显眼-算是解决了吧)
- 点击屏幕中央,呼出上下菜单栏,会出现滚动条(老师的不会)(猜测:动画过渡导致页面宽高发生变化)–已解决
// 解决办法,隐藏进度条
html::-webkit-scrollbar{width:0px
}
- 图书主题切换,短时间切换过多次,会没反应(主题已经调过来了,前端没有渲染)
- 切换不同的菜单选项(下面的)没有过度动画**—已解决**
- 点击目录蒙版区域隐藏目录,下面的菜单条没有被隐藏**—已解决**
- 目录跳转有问题**—已解决**
- 切换字体,有时会没有效果
- 清完缓存,第一次进入,字体大小会没效果(缓存中有)
原因:第一次初始化,这两个值没有定义(刷新一下就有了,定位不到出错位置)
- 上下章,能跳转的比目录上的多,有的图书会导致章节的选中效果选择了错误的章节**—严重性BUG**
- 应该验证章节跳转的逻辑,是依据什么进行跳转的(猜测是section的值有问题)
- this.navigation有问题
Scroll组件没有滚动条,当内容有很多屏时,不知道滑到哪里了(对 目录非常多的书 不友好)
- 理想效果:高度小于两屏时,隐藏滚动条,高于两屏时显示滚动条
- src/components/common/Scroll.vue----webkit-scrollbar
高度异常:很多地方都高度异常,可能是scroll组件问题 http://localhost:8080/#/store/home,滚动部分的高度没有变化,初试时,mounted中调用了refresh重新计算高度,没有问题,后面高度没有变化了
toast组件还是有问题,当切换页面时,toast不会自动消失
- 例如:删除分组时
store/detail页面底部加入书架:已解决
假设一本书已经在书架中,进入图书详情页detail底部的加入书架会变成已加入书架
初次进入底部的加入书架,会变成 已加入书架,但刷新一下,就变成了 加入书架
computed中inBookShelf变量的问题
解决方法:刷新进入bookdatail页面是,shelfList中值为空,重新获取即可
可以优化的地方
http://localhost:8080/#/store/shelf页面
pc端可以监听esc按键,调用取消的方法,移动端暂时不知道
[yishen] 小慕读书web端学习笔记相关推荐
- 小慕读书后台管理平台笔记
setTimeout用法: 错误用法: 正确用法:
- web前端学习笔记(最新)
web前端学习笔记 大家好,我是链表哥,新的学期,新的学习,我会为您展示我的学习进程. 一:什么是WEB前端? 所谓的Web前端指的是用户所能接触到的,并服务于用户的前沿端口,经我们程序员编辑修饰后展 ...
- vue3小兔鲜商城项目学习笔记+资料分享06
建议大家先去看我第一篇小兔鲜的文章,强烈建议,非常建议,十分建议,从头开始看更完整. 最近正在学习vue3小兔鲜 下面是学习笔记 购物车模块 购物车功能分析 [外链图片转存失败,源站可能有防盗链机制, ...
- Java web与web gis学习笔记(二)——百度地图API调用
系列链接: Java web与web gis学习笔记(一)--Tomcat环境搭建 Java web与web gis学习笔记(二)--百度地图API调用 JavaWeb和WebGIS学习笔记(三)-- ...
- java webpack web项目_官方出品,微信小程序和 Web 端同构解决方案——kbone
介绍 最近在琢磨一些小程序开发和移动web开发,偶然间在Github上看到了这样一个项目--kbone,一个致力于微信小程序和 Web 端同构的解决方案.微信小程序的底层模型和 Web 端不同,我们想 ...
- 【Python-pywt】 小波变化库—Pywavelets 学习笔记
(转载) [Python ]小波变化库--Pywavelets 学习笔记_nanbei2463776506的博客-CSDN博客 https://blog.csdn.net/nanbei24637765 ...
- Web Components 学习笔记一: Web Components是什么?解决了什么问题?
公众号:妙蛙种子前端 文章原文地址:Web Components笔记一: Web Components是什么?解决了什么问题? | 妙蛙种子 - 记录WEB前端技术学习成长过程的博客 Web Comp ...
- vue3小兔鲜商城项目学习笔记+资料分享08
建议大家先去看我第一篇小兔鲜的文章,强烈建议,非常建议,十分建议,从头开始看更完整. 最近正在学习vue3小兔鲜 下面是学习笔记 支付模块 路由和组件 任务目标: 完成支付页路由和组件 [外链图片转存 ...
- web安全学习笔记--sql语句(sql注入基础上)
一.基础知和表内操作语法 1.sql语句对大小写不敏感!!! SELECT - 从数据库表中获取数据:select * from (columns/tables/databases); UPDATE ...
最新文章
- ES6 对象的新功能与解构赋值介绍
- 从VS2008+QT4到VS2015+QT5迁移过程中遇到的问题及解决方法
- 链表学习(一)静态链表的构造
- LNMP架构环境搭建之PHP、Nginx源码编译安装及其简单配置应用
- python_45_目录编程
- python xlrd xlwt pandas 模块 区别_python如何读写excel文件|python教程|python入门|python教程...
- 过磅系统更换服务器,无人值守过磅系统改造方案
- Altium Designer之Preferences
- 容器编排技术 -- AWS EC2快速入门
- 解密初、中、高级程序员的进化之路(前端)
- Spring Security OAuth2.0_实现分布式认证授权_网关资源服务配置_Spring Security OAuth2.0认证授权---springcloud工作笔记152
- 拦截器RetryAndFollowUpInterceptor分析
- jquery的基本使用-入口函数
- 数字转换成货币类型的方法
- 【POCKET 51】用 pocket 51学51单片机 之四:pocket 51功能模块测试
- 高通 MSM8K bootloader 之四: ramdump
- 滴滴的大数据可视化效果
- 好用的 Windows 软件授权管理工具 - slmgr
- 去除迅雷右侧资源信息栏和迅雷广告,以及迅雷的速度限制修改
- Sublime插件安装与提高Verilog编写效率插件推荐