自用-通过WEB页面阅读本地小说,生成章节导航,设置字色和背景色达到护眼目的,HTML+CSS+JS

  • 章节导航
    • 需求分析
    • HTML代码
    • CSS代码
    • JS代码
    • 总结

章节导航

从分析需求入手,查找资料,制定方案,通过ctrlCV大法实现目的。

需求分析

平时打发时间看些小说,有时从网上找一些txt的资源,在安卓手机上有非常好用而且顺眼的阅读APP,但是小小屏幕看久了总是会累的。用电脑看,视野开阔,阅读效率也高,然而目前PC阅读常见的方案无论是网站阅读(页面配色不够舒适,广告多)还是EXE阅读(如TXT小说阅读器,虽然用着不错,仍嫌配色不够护眼)总是差强人意,所以我就需要有一个能满足护眼需求的阅读工具。
考虑自己半吊子的QT能力和前后端水平,罗列了几种可用方案,并最终选择了纯html+css+js的简单实现。

  1. 纯QT实现 ,考虑界面如何自适应会比较麻烦,虽然是在看小说,但是既然是在电脑上,就要考虑应用遮挡问题,难免需要调整窗口大小。另外学艺不精,配置各种图标和做中文处理的时候难免遇到各种问题;由于UI美工能力不足,需要不停调试效果,用QT一次次编译生效实在有点恶心,想做点能在使用时对阅读器效果灵活配置的功能会不断增加项目规模,然而我只是想爱眼阅读而已。
  2. 本地WEB 做界面,还是web前端三剑客实现起来容易。无论是划分功能块、调整样式,还是添加操作上的交互,都很容易。基本上浏览器也都支持打开本地文件。
  3. QT+本地WEB 其实是有些配置能存下来会比较好的,比如历史文件、阅读到的位置、字号颜色等配置,要么前台cache,或者用后台,后台用jar或者c都行,c的话新建个qt项目就是了,那么把web直接嵌到QT界面上并实现通信就是个容易想到的方案。不过也有些“成本”问题,后台读写配置要么用配置文件读写,要么连个redis或mysql,终归只是想实现些锦上添花的功能,却要多实现不少东西。而且虽然没有尝试,但很可能打开文件时要从浏览器支持的FileReader换成从C读取文件并发内容给WEB了。
  4. 本地WEB页面丢到NGINX里 想用cache存一些配置数据,用本地web文件是不行的,丢到ngnix里面去,通过http访问,操作起来还挺简单。

那么我对功能点的具体需求是什么呢?

  1. 没有乱七八糟的多余元素 自己从头做起来的东西,有多余的东西倒还比较难
  2. 加载文档最基本都需求。IE以外的浏览器基本都能很方便的支持
  3. 修改字色、背景色、字号等做这个东西都核心目的。灵活点可以整个调色盘,简单点就挑些配色做下拉框
  4. 定位/章节导航切割文档,类似翻页。正则匹配,用通用点的规则,结果可能就没那么精准,按需取舍
  5. 保存阅读配置至少记录下读到的章节
  6. 翻页/翻章节 ctrl + ←→方向键

HTML代码

<!DOCTYPE html>
<html><head><title>本地TXT阅读</title><meta name="name" content="content" charset="utf-8"><link rel="stylesheet" href="style.css"><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.12.1/css/all.css"><script src='https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js' type='text/javascript'></script><script src='./settings.js' type='text/javascript'></script></head><body><input type="file" id="file" /><input type="button" onclick="readText()" value="打开"><input type='number' id="fontsizt" min='16' max='32' value='22'/><input type="button" onclick="setSize()" value="设置字号"><input type='number' id="paragraght" min='1' max='' value='1'/><input type="button" onclick="setParagraph()" value="设置章节">    <input type="button" id="prev" onclick="Number.parseInt(document.getElementById('paragraght').value)>1&&document.getElementById('paragraght').value--;setParagraph()" value="上一章"> <input type="button" id="next" onclick="Number.parseInt(document.getElementById('paragraght').value)<Number.parseInt(document.getElementById('paragraght').max)&&document.getElementById('paragraght').value++;setParagraph()" value="下一章">    <div id="top" style="position:absolute;top:2px;right:10px">颜色: <select id="fcolor" onchange="setColor(this)"><option>选择</option>
<option value="blue" style="color:blue">蓝色</option>
<option value="yellow" style="color:yellow;background-color:#73B6EF">黄色</option>
<option value="navy" style="color:navy">海军蓝</option>
<option value="royalblue" style="color:royalblue">皇家蓝</option>
<option value="green" style="color:green">深绿色</option>
<option value="purple" style="color:purple">紫色</option>
<option value="olive" style="color:olive">橄榄色</option>
<option value="DarkCyan" style="color:DarkCyan">深青色</option>
<option value="lime" style="color:lime">鲜绿色</option>
<option value="gray" style="color:#d8d6d0">灰色</option>
<option value="#FFF" style="color:white;background-color:#73B6EF">白色</option></select>背景色: <select id="bkcolor" onchange="setBack(this)"><option>选择</option>
<option value="wheat" style="background-color:wheat">小麦色</option>
<option value="Gainsboro" style="background-color:Gainsboro">淡灰色</option>
<option value="lightgreen" style="background-color:lightgreen">淡绿色</option>
<option value="khaki" style="background-color:khaki">黄褐色</option>
<option value="yellowgreen" style="background-color:yellowgreen">黄绿色</option>
<option value="lightblue" style="background-color:lightblue">淡蓝色</option>
<option value="violet" style="background-color:violet">紫罗兰</option>
<option value="#000" style="background-color:#000;color:#eee">黑色</option>
<option value="AntiqueWhite" style="background-color:AntiqueWhite">古典白</option>
<option value="#F2FD84" style="background-color:#F2FD84">#F2FD84</option></select><table><tbody><tr><td width="120"><span></span></td></tr></tbody></table></div><input type="checkbox" id="check"><label for="check"><i class="fas fa-bars" id="btn"></i><i class="fas fa-times" id="cancel"></i></label><div class="sidebar"><header>目录</header><ul id="leftNav"><!-- <li><a href="#"><i class="fas fa-qrcode"></i>Dashboard</a></li> --><!-- <li><a href="#"><i class="fas fa-link"></i>Shortcuts</a></li> --><li><a href="#"><i class="fas fa-stream"></i>Overview</a></li><!-- <li><a href="#"><i class="fas fa-calendar-week"></i>Events</a></li> --><!-- <li><a href="#"><i class="far fa-question-circle"></i>About</a></li> --><!-- <li><a href="#"><i class="fas fa-sliders-h"></i>Services</a></li> --><!-- <li><a href="#"><i class="far fa-envelope"></i>Contact</a></li> --></ul></div><div class="showtext"><pre id="tt" style="word-wrap: break-word; white-space: pre-wrap;font-weight: bolder; font-family: 微软雅黑;"></pre></div></body>
</html>
<style></style>
<script charset="utf-8">window.onload=function () {styleObj=document.styleSheets[2]if(typeof(FileReader)=="undefined"){alert("你的浏览器不支持文件读取");document.write("");}else{console.log("你的浏览器支持文件读取");}/*var jQueryElement=document.createElement('script');jQueryElement.type = 'text/javascript';jQueryElement.onload = function () {console.log('jQuery loaded');setSize();};jQueryElement.src = 'https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js';document.getElementsByTagName('head')[0].appendChild(jQueryElement);*/s1=document.getElementById("fcolor");s2=document.getElementById("bkcolor");s1.selectedIndex=10;s2.selectedIndex=8;ev = document.createEvent("HTMLEvents");ev.initEvent("change", false, true);s1.dispatchEvent(ev) ;//fireEvent不支持s2.dispatchEvent(ev) ;setSize();$(document).keydown(function(event){if(event.ctrlKey && event.keyCode == 37){$('#prev').click();}else if(event.ctrlKey && event.keyCode == 39){$('#next').click();}});
}//1 浏览器打开本地文档 https://zhidao.baidu.com/question/1541329842508075787.html
//2 修改颜色select+option选择颜色(含cookie设置,注意cookie无法在本地web页面使用) https://www.shouce.ren/api/html/html4/tools-color_selector.html
//3 章节正则匹配识别 https://blog.csdn.net/weixin_29143935/article/details/114791177   https://blog.csdn.net/weixin_42448623/article/details/102785880
//4 JSON有效性判断 https://www.cnblogs.com/lanleiming/p/7096973.html
//5 左侧章节导航栏 https://blog.csdn.net/qq_25503949/article/details/106244548
//6 滚动条样式修改(webkit) https://jingyan.baidu.com/article/e75057f2017b2debc81a8968.html
//7 滚动条设置scrollTop时平滑过度 https://blog.51cto.com/u_15693675/5407922
//8 键盘监听 https://www.cnblogs.com/pangpanghuan/p/6423204.html
//9 setcookie要给个时间,以免关闭浏览器(会话结束)时被清除https://www.csdn.net/tags/Ntjacg2sMTI4MjktYmxvZwO0O0OO0O0O.html
</script>

CSS代码

style.css

* {margin: 0;padding: 0;list-style: none;text-decoration: none;font-family: "Roboto", sans-serif;
}html,body,#page{height: 100%;width: 100%;
}
pre{height: 100%;width: 100%;
}
body{overflow:hidden;
}
#tt{overflow-y:auto;
}
::-webkit-Scrollbar{width:10px;height:10px;
}
::-webkit-Scrollbar-thumb{border-radius:5px;-webkit-box-shadow:inset 0 0 5px rgba(0,0,0,0.2);background:rgba(255,255,255,0.2);
}
::-webkit-Scrollbar-track{-webkit-box-shadow:inset 0 0 5px rgba(0,0,0,0.2);border-radius:0;background:rgba(255,255,255,0.1);
}.sidebar {position: fixed;left: -250px;width: 250px;height: 100vh;background-color: #042331;transition: all 0.5s ease;//ease 开始和结束慢,中间快
}.sidebar header {color: white;text-align: center;line-height: 45px;font-size: 22px;background: #0d547633;user-select: none;//用户不能选取
}.sidebar ul a {display: block;padding-left: 20px;line-height: 34px;border-top: 1px solid rgba(255, 255, 255, .1);border-bottom: 1px solid #a5a5a5;color: white;transition: 0.3s linear;
}
.sidebar ul{/*leftNav*/overflow-y:auto;height:90%;scroll-behavior: smooth;
}
.sidebar ul i {padding-right: 16px;
}.sidebar ul a:hover {padding-left: 10px;
}#check {display: none;
}label #btn,
label #cancel {position: absolute;cursor: pointer;background-color: #3aa327;border-radius: 3px;
}label #btn {left: 0px;top: 25px;color: black;font-size: 18px;padding: 3px 9px;transition: 0.3s;z-index:1;
}label #cancel {z-index: 999;left: -197px;top: 29px;font-size: 30px;color: #0a5275;padding: 4px 9px;transition: 0.3s;
}#check:checked~.sidebar {left: 0px;
}.showtext{position: absolute;height: 94%;width: 98%;padding: 22px;left:0px;transition: all 0.5s ease;
}
#check:checked~.showtext {left: 250px;width: calc(98% - 250px);
}#check:checked~label #btn {left: 250px;opacity: 0;
}#check:checked~label #cancel {left: 208px;
}section {background: url(./bg.png) no-repeat;background-position: center;//定位背景图片在中间height: 100vh;background-size: cover;transition: all 0.5s;
}#check:checked~section {margin-left: 250px;
}

【~】号说明:参考的文章里解释的不太好,可以看这个
General_sibling_combinator说明
A~B:A和B是两个筛选器。与A同层级,同父级,且位置在A后的,所有用B筛选出的元素的样式。

JS代码

setting.js

function readText() {var file=document.getElementById("file").files[0];console.log(document.getElementById("file").files);curFilename=file.name;//全局var reader=new FileReader();reader.readAsText(file,"GB2312");reader.onload=function(data){var tt=document.getElementById("tt")//tt.innerHTML=this.result;console.log(this.result.length);var titleRule=/\s*(第)([一二三四五六七八九十零百千万]{1,9})[章](\s*)(\S*)(\n|\r|\r\n)/g; //  \s*(第)(.{1,9})[章节卷集部篇回](\s*)(\S*)(\n|\r|\r\n)var titleRuleS=/(第)(.{1,9})[章](\s*)(\S*)/;//进行章节标题匹配查找titles=this.result.match(titleRule);//全局//todo:处理章节标题fileTitle=[]//全局var titleUL="";titles.forEach(function(e){var titlenow=e.match(/(第)(.{1,9})[章](\s*)(\S*)/)[0];//console.log(titlenow+"at"+dtxt.indexOf(titlenow))fileTitle.push(titlenow);titleUL+='<li><a href="#" οnclick="loadData(\''+titlenow+'\')"><i class="fas fa-stream"></i>'+titlenow+'</a></li> \';})document.getElementById('leftNav').innerHTML=titleUL;//切割文档fileData=[]//全局for(var i=0;i<fileTitle.length-1;i++){fileData.push(this.result.substring(this.result.indexOf(fileTitle[i]),this.result.indexOf(fileTitle[i+1])))}fileData.push(this.result.substring(this.result.indexOf(fileTitle[fileTitle.length-1])))//加载文档currentPage=0;//全局var cache = getCookie("localReadCache");if(isJSON(cache)){var cacheJSON=JSON.parse(cache);if(cacheJSON.hasOwnProperty(curFilename)){currentPage=cacheJSON[curFilename];document.getElementById('paragraght').value=Number.parseInt(currentPage+1);$('#leftNav').scrollTop($('.sidebar ul a')[currentPage-1].offsetTop)}}tt.innerHTML=fileData[currentPage];maxPage=fileTitle.length-1;//全局var para=document.getElementById("paragraght");para.max=maxPage+1;}}function setSize(){var fontsize=document.getElementById("fontsizt");if (Number.parseInt(fontsize.value)>=Number.parseInt(fontsize.min)){var tt = document.getElementById('tt');tt.style.fontSize=fontsize.value+"px";}}function setParagraph(){var para=document.getElementById("paragraght");if (Number.parseInt(para.value)>=Number.parseInt(para.min)&&Number.parseInt(para.value)<=Number.parseInt(para.max)){var index=Number.parseInt(para.value)-1;var data=fileData[index];var tt=document.getElementById("tt");tt.innerHTML=fileData[index];currentPage=index;$('#leftNav').scrollTop($('.sidebar ul a')[currentPage-1].offsetTop)var cache = getCookie("localReadCache");if(isJSON(cache)){var cacheJSON=JSON.parse(cache);cacheJSON[curFilename]=currentPage;setCookie("localReadCache",JSON.stringify(cacheJSON),86400*60);}else{var newCache={};newCache[curFilename]=currentPage;setCookie("localReadCache",JSON.stringify(newCache),86400*60);}}}function loadData(title){var index=fileTitle.indexOf(title);if(index>-1){var data=fileData[index];var tt=document.getElementById("tt");tt.innerHTML=fileData[index];currentPage=index;document.getElementById('paragraght').value=Number.parseInt(currentPage+1);var cache = getCookie("localReadCache");if(isJSON(cache)){var cacheJSON=JSON.parse(cache);cacheJSON[curFilename]=currentPage;setCookie("localReadCache",JSON.stringify(cacheJSON),86400*60);}else{var newCache={};newCache[curFilename]=currentPage;setCookie("localReadCache",JSON.stringify(newCache),86400*60);}}}function isJSON(str) {if (typeof str == 'string') {try {var obj=JSON.parse(str);if(typeof obj == 'object' && obj ){return true;}else{return false;}} catch(e) {console.log('error:'+str+'!!!'+e);return false;}}console.log('It is not a string!')
}//liuming lium03@tom.com QQ395310500//flow
// var styleObj=document.styleSheets[2]//设置cookie
function setCookie(name,value,expires){//var curCookie=name+"="+escape(value)+((expires)?";expires="+expires.toGMTString():"");//document.cookie=curCookie;var exp = new Date();exp.setTime(exp.getTime() + (expires?expires:0)*1000);var curCookie=name+"="+escape(value)+((expires)?";expires="+exp.toGMTString():"");document.cookie=curCookie;
}//取出cookie
function getCookie(name)
{var aCookie = document.cookie.split("; ");for (var i=0; i < aCookie.length; i++){var aCrumb = aCookie[i].split("=");if (name == aCrumb[0]) return unescape(aCrumb[1]);}return null;
}//删除cookie
function deleteCookie(name) {if (getCookie(name)) {document.cookie = name + "=; expires=Thu, 01-Jan-70 00:00:01 GMT";}
}//flowfunction setFont(select){var fontSize=select.value+"pt";
if (document.all){styleObj.addRule("body","font-size:"+fontSize);
}else{styleObj.insertRule("body{font-size:"+fontSize+"}",document.styleSheets[0].cssRules.length);
}
}function setColor(select){var color=select.value;
if (document.all){styleObj.addRule("body","color:"+color);
}else{styleObj.insertRule("body{color:"+color+"}",document.styleSheets[2].cssRules.length);
}
}function setBack(select){var bgcolor=select.value;
if (document.all){styleObj.addRule("body","background-color:"+bgcolor);
}else{styleObj.insertRule("body{background-color:"+bgcolor+"}",document.styleSheets[2].cssRules.length);\
}
}

总结

纯纯是ctrlCV,代码越简单越好呀。

【护眼阅读】PC端通过主流常用浏览器打开本地WEB页面阅读本地TXT小说相关推荐

  1. 校验用户登录手机端还是PC端,是否微信浏览器打开

    .JS var browertype = "web";//浏览器类型     var isWeiXin="not";       //初始化方法     $(f ...

  2. PC端微信内置浏览器调试

    PC端微信内置浏览器打开调试(微信必须3.2.1及以下) 使用http-server运行以下代码,使用微信打开地址链接 <html><script type="text/j ...

  3. 调试微信 PC 端的内置浏览器界面

    2021-08-03 最新更新 好久没看,微信也更新了好几版.下面的方法并没有失效,不过上了 3.3.x 后的微信版本已经禁用了右键和查看 chrome://version 的功能了.进过实测,最后一 ...

  4. pc端微信内置浏览器F12

    pc端微信内置浏览器F12 1.下载devtools_resources.pak https://files.cnblogs.com/files/wunaozai/devtools_resources ...

  5. 调试那些事儿之PC端微信内置浏览器

    一.前言 为什么要调试 PC 端微信内置浏览器呢?个人觉得原因可能如下: 1.用户在电脑上的微信内置浏览器打开网页,遇到了问题,开发就需要去排查问题 2.查看公众号网页的代码比较难查看,也不方便调试, ...

  6. PC端微信内置浏览器兼容问题

    PC端微信内置浏览器兼容问题 微信自带浏览器用的是QQ浏览器X5内核,而X5内核是腾讯基于开源Webkit优化的浏览器渲染引擎,目前除了微信.手机QQ.京东等有30多款APP内置浏览器都是基于X5内核 ...

  7. PC端微信自带浏览器网页跳转授权页面空白问题

    手机微信授权正常的,但PC微信用自带浏览器打开网页的时候空白,经过多次尝试,发现原来是授权地址的参数顺序问题.因为项目是单页面应用,由于微信授权时会自动去掉"#"后的内容,所以当时 ...

  8. 【易语言作品】夜猫护眼宝 PC版 大神勿喷,语言是国产的易语言!

    可保护您长时间或夜晚坐在电脑桌前,给您最大的眼睛保护!夜猫护眼宝电脑版是一款蓝光过滤软件.通过该软件,可以有效降低电脑辐射,减少对眼睛的伤害,是专为办公人员.游戏玩家等长时间对着电脑人群而设计.根据时 ...

  9. html px转换,pc端px转换为rem针对屏幕分辨率进行页面适配

    常用的pc端网站适配方案是什么?用的最多的大概就是父元素按照设计图的宽度进行固定宽度,margin:0 auto居中,两边留白.但是有的设计图不适合这样两边留白的适配方案. 最近接手了一个pc端的项目 ...

最新文章

  1. git保姆级入门(包含解决git仓库报错500的问题)
  2. Linux内核抢占实现机制分析【转】
  3. HDU2044 一只小蜜蜂…(简单递推)
  4. 2020年全国硕士研究生招生考试考生进入复试的初试成绩基本要求(学术学位类)
  5. threadlocal使用_多方位点评ThreadLocal,细看各大开源软件实现
  6. unix文件权限判断
  7. 机器学习用于金融市场预测难在哪?
  8. PHP制作登录异常ip检测功能实例
  9. 大屏监控系统实战(16)-项目拾遗
  10. mysql 浮点类型和定点_mysql 中的浮点和定点类型
  11. 内部网关协议和外部网关协议
  12. 限时促销_江北恒一乐优家丨限时优惠大促销
  13. Java 密码扩展无限制权限策略文件[转]
  14. FreeImage的学习总结总结(三)
  15. b700a怎么连蓝牙_索尼WI-H700耳机蓝牙连接方法
  16. 无人驾驶小车调试笔记(五)-- 命令行通信
  17. fbm是什么意思_fba是什么意思
  18. Html5---div布局方式
  19. 计算机程序由算法,涉及计算机程序算法的发明专利申请问答
  20. 服务器和工作站有什么区别?

热门文章

  1. 【语音去噪】基于最小二乘自适应滤波LMS和RLS实现语音去噪含Matlab源码
  2. python音乐库_python - 网易云音乐的 Python 组件库
  3. Direct3D基础——Direct3D概述
  4. [Vue warn]: Failed to resolve component: xxx
  5. 《了不起的盖茨比》----走出绿灯困境
  6. 云小蜜人工智能训练师
  7. 我用维权失败经历告诉你,在淘宝上买到假货只能忍气吞声
  8. Debian 8桌面安装Nvidia GTX960显卡驱动
  9. nginx反向代理实现二级域名转一级域名
  10. elasticsearch DSL查询之should查询