此工具已失效!
我用JavaScript写了一个小工具,在b站视频播放页面执行,可以在当前视频的所有评论里查找指定用户发出的评论。
举个例子:你(或是别人)在某视频下发了一条评论,但没记住楼层。现在,如果你想要在众多评论里找到自己(或其他某个人)发的评论,可以使用本工具。
本工具可以搜索完所有的楼层,但查找楼中楼时,本工具只能查找到每个楼中楼的前5条回复(所以对于楼中楼,可能会有遗漏)。
如果你有油猴扩展,可以到UserScript安装页面安装此用户脚本。
如果你没有油猴扩展,你可以手动执行代码。下面提供两种执行方式:
1.控制台执行以下代码,它会远程加载js文件来执行:
var newscript=document.createElement("script"); newscript.src="/f/bilibili_comment_search.js"; document.body.appendChild(newscript);
这种方法的话,由于我的js的url是http的,所以在B站的https页面里无法执行,可以在地址栏把b站这个页面的网址手动改成http的。
2.下载js文件,然后手动复制其代码到控制台执行。
代码执行之后,在视频上方会出现“查找评论”的文字:
点击它,输入想查找的用户的id(就是打开TA主页时网址里的数字)。之后,每当找到这个人发的一条评论,就会在控制台输出该评论的楼层信息。
注意要在控制台看哦~我们可以根据页数和楼层数提示去找到这条评论。
如果工具搜索完了所有评论,会弹出搜索到了几条结果。如果你想中途停止搜索,点击视频上方的提示文字即可。
Read More →
在bilibili评论区搜索某人评论的工具
假设现在获得了一些格式化的时间/日期字符串,如何用JavaScript对其排序呢?
理想的办法就是用Date.parse()方法将这些字符串解析为时间,直接比较它们的毫秒数。示例如下:
function sortDate(sortby) { return function(object1, object2) { var value1 = Date.parse(object1); var value2 = Date.parse(object2); if(value1>value2){ return (sortby==="desc")?-1:1; }else if(value1<value2){ return (sortby==="desc")?1:-1; } } } var a=["2017/4/20","2016/6/3","2016/7/1","2016/7/27","2017/8/4","2016/10/13","2016/12/27","2017/1/14","2017/2/3","2017/2/3","2017/2/3","2017/2/3","2017/2/3","2017/2/3","2017/2/3","2017/3/1","2017/3/1","2017/3/1","2017/3/1","2017/3/1","2017/3/1","2017/3/1","2017/3/23","2017/3/31","2017/5/19","2017/5/19","2017/6/2","2017/6/24","2017/6/24","2017/6/24","2017/9/1","2017/9/5","2017/12/12","2018/2/19","2018/9/26","2017/5/19","2017/3/9","2017/7/14","2017/5/19","2017/5/19"]; a.sort(sortDate("desc"));
结果如下:
上例定义了一个sortDate函数,我们在数组的sort方法里将它作为参数。如果不手动设置排序参数为desc,那么这个函数将始终按升序排序。
标准的时间/日期格式如下:
"2017/4/20 16:20:30"
当然,只用一部分,或者改变下连接符,也是可以解析的。
Read More →
JavaScript对日期排序
因为JavaScript水平太渣,以前我都是用JQuery来做ajax。现在看了些资料,感觉原生的写法也不难,而且兼容性也已经不错了,所以跟着练一练。
同步的ajax请求:
var xhr=new XMLHttpRequest(); xhr.open("get","http://saber.我爱你/demo/checknew.php",false); xhr.send(null); if (xhr.status===200) { alert(xhr.responseText); }else{ alert("发生了异常,状态码为"+xhr.status+","+xhr.statusText); }
返回的数据里有如下属性:
responseText:作为响应主体被返回的文本。
responseXML:如果响应的内容类型是"text/xml"或"application/xml",这个属性中将保存包含着响应数据的XML DOM 文档。
status:响应的HTTP 状态。
statusText:HTTP 状态的说明。
异步的ajax请求:
var xhr=new XMLHttpRequest(); xhr.onreadystatechange=function(){ if (xhr.readyState===4) { if (xhr.status===200) { alert(xhr.responseText); }else{ alert("发生了异常,状态码为"+xhr.status+","+xhr.statusText); } } } xhr.open("get","http://saber.我爱你/demo/checknew.php",true); xhr.send(null);
检测状态的部分也可以这样写:
xhr.onload=function (argument) { if (this.status == 200) { //…… } }
异步请求除了在xhr.open里将最后的参数设置为true之外,在接收数据时也和同步请求不同。异步请求通过检查xhr对象的readyState属性来判断请求处在哪个阶段。当readyState为4时,表示接收到了数据,并且数据可用。
我们通过onreadystatechange事件来检测readyState的值,当值为4时即可对数据进行处理。
另外,在接收到响应之前还可以调用abort()方法来取消异步请求。即xhr.abort(); 。
原生Ajax的简单实例
<img src="/f/head15.jpg" id="stwRight"> <img src="/f/saber%E8%A1%A8%E6%83%85_1_1.jpg" id="stwCenter"> <img src="/f/x.png" id="swtClose"> <style type="text/css"> #LRdiv0,#LRdiv1{display:none !important;} #stwRight{position: fixed;right: 0;top: 60px;display: none;z-index: 999;cursor: pointer;} #stwCenter{position: fixed;display: none;width: 400px;height: 350px;left: 50%;margin-left: -200px;top: 50%;margin-top: -175px;z-index: 999;cursor: pointer;} #swtClose{position: fixed;display: none;width: 24px;height: 24px;left: 50%;margin-left: 175px;top: 50%;margin-top: -175px;z-index: 9999;cursor: pointer;} </style> <script type="text/javascript"> window.onload=function(){ function showSwtC(){ document.getElementById("stwCenter").style.display="block"; document.getElementById("swtClose").style.display="block"; } function showSwtR(){ document.getElementById("stwRight").style.display="block"; } function hideSwtC(){ document.getElementById("stwCenter").style.display="none"; document.getElementById("swtClose").style.display="none"; } function hideSwtR(){ document.getElementById("stwRight").style.display="none"; } function openSwt(){ LR_HideInvite();openZoosUrl();return false; } showSwtR(); setTimeout(function(){ hideSwtR(); showSwtC(); },4000); document.getElementById("stwRight").onclick=function(){ openSwt(); } document.getElementById("stwCenter").onclick=function(){ hideSwtC(); showSwtR(); openSwt(); setTimeout(function(){ hideSwtR(); showSwtC(); },8000); } document.getElementById("swtClose").onclick=function(){ hideSwtC(); showSwtR(); setTimeout(function(){ hideSwtR(); showSwtC(); },8000); } } </script>
侧边浮窗没做关闭按钮。
因为openSwt()里用了商务通自带的函数openZoosUrl(),所以页面上还是得加载商务通代码。如果把openSwt()改成直接用网址跳转,则不用加载商务通代码。
上面商务通不仅样式是我们自己做的,显示、隐藏的逻辑也需要自己定义。实际上对于有商务通代码的页面,我们可以直接利用商务通自身的函数来“偷梁换柱”,打开我们自己的商务通图片。
var sTimer = setInterval(function(){ if(typeof LR_showInviteDiv != "undefined"){ window.LR_showInviteDiv = function(){ //此处改写了商务通显示邀请框的函数 showSwt(); } clearInterval(sTimer); } },100);
LR_showInviteDiv是显示邀请框的函数,如果页面上有这个函数,则改写它,让它执行showSwt,也就是我们自己定义的一个函数,显示自己的邀请框。
恩……我对这这个代码研究了好久,发现这个办法并没有多方便,浪费时间。唯一的优点是不用写css来隐藏商务通的邀请框了。另外改写商务通的这个函数会导致商务通客户端发送邀请失败。麻烦。
简单的仿一下商务通效果
平时我们表单的提交多数是用action来指定提交到的文件,但这样会产生页面的刷新。用ajax提交可以避免刷新,但是需要我们自己组织要提交的数据。这就是表单序列化了。
jQuery有个serialize方法来做表单序列化,语法如下:
$(selector).serialize();
序列化之后,表单里需要提交的值会被组织成字符串,形如:
"name=124&company=baidu.com&fav=1,2,3"
如果里面有汉字之类,会自动进行url编码。表单序列化完全模拟了浏览器提交时的数据,这样我们就可以用ajax来提交表单了。
如一个id为“yy”的表单,它的提交的地址是"/plus/diy.php",提交按钮id是submit。那么表单序列化并提交的代码如下:
$("#submit").click(function(event) { event.preventDefault(); $.ajax({ type: "post", url: "/plus/diy.php", data: $("#yy").serialize(), success: function() { alert("信息提交成功。"); } }) })
注意用preventDefault()阻止浏览器默认事件(就是跳转到action页面,即使你没写action属性也会跳转的)。
后台对提交数据的处理和用action提交时的数据是一致的。
Read More →
JavaScript表单序列化
// ==UserScript== // @name 网站地图生成助手(Clearision主题专用) // @namespace https://saber.love // @version 0.1 // @description 自动生成当前网页的sitemap信息(文章页) // @author saber // @match https://saber.love/*.html // @grant none // ==/UserScript== var sitemap_url = window.location.href; //url var sitemap_pri = "0.5"; //权重 var changefreq = "Always"; //更新频率 var sitemap_year = new Date(); //年份 sitemap_year = sitemap_year.getFullYear(); // 因为主题生成的网页里没有包含年份,所以取当前年份 var sitemap_time_info = document.getElementsByClassName("post_time")[0].innerText.replace(/\n/g, "").replace(/\t/g, "").replace("/", "-").replace(" ", ""); var sitemap_date, sitemap_time; //时间和日期 if (sitemap_time_info.length === 9) { sitemap_date = sitemap_time_info.substring(0, 4).replace("-", "-0"); //天数在10号以下时前面没有0,所以需要补上0 sitemap_time = sitemap_time_info.substring(4, 9); } else if (sitemap_time_info.length === 10) { sitemap_date = sitemap_time_info.substring(0, 5); sitemap_time = sitemap_time_info.substring(5, 10); } window.stop(); //停止页面加载,可以节省图片流量 var this_sitemap_result = ("<url>" + "\r\n" + "<loc>" + sitemap_url + "</loc>" + "\r\n" + "<priority>" + sitemap_pri + "</priority>" + "\r\n" + ("<lastmod>" + sitemap_year + "-" + sitemap_date + "T" + sitemap_time + ":00+00:00</lastmod>") + "\r\n" + "<changefreq>" + changefreq + "</changefreq>" + "\r\n" + "</url>" + "\r\n"); //拼接出本页面的sitemap信息 localStorage.setItem("mymap", localStorage.getItem("mymap") + this_sitemap_result); //把本次的结果追加存储 var next_page = document.querySelector("#p_n_r a"); if (!!next_page) { //如果有下一页就自动打开下一页 next_page.click(); } else { //如果没有下一页就弹出结果 document.write("<xmp>" + localStorage.getItem("mymap") + "</xmp>"); alert("sitemap信息生成完毕"); localStorage.setItem("mymap", ""); //清空结果 }
本文代码是针对我这个网站写的,如果其他网站想要使用,可以对照自己网站进行修改。
使用方法:
在油猴里新建一个脚本,把下面的代码粘贴进去保存即可。之后打开或刷新本站任意一个网页,代码就会从这个页面一直抓取到最新的一篇文章,自动生成sitemap信息并存储到localStorage里。抓取完成后弹窗提醒,并把抓取结果输出到页面上。这样我们只需要等结果出来,最后复制结果就行了。
注意:
由于文章信息里没有包含年份,所以年份去的是当年。如果如在当年去获取之前的文章,那么年份就是错的。比如2018年1月去获取2017年12月的,结果会显示2018年12月。这个可以在获取后批量替换下。
使用之后记得关掉这个油猴脚本,以免影响正常浏览。
网站地图生成助手js版
<div id="demo"> <div class="scrollbox"> <div id="demo1"> <a href="">雪见雪见雪见雪见雪见雪见</a> <a href="">sabersabersabersaber</a> </div> <div id="demo2"></div> </div> </div> <style type="text/css"> #demo{width: 300px;overflow:hidden;} /*最外层box的宽度可以随意设置,但必须小于里面demo(如demo1)的宽度,否则滚动完一次会停止*/ #demo .scrollbox{width:1000%;}/*设置一个较大的范围,保证其宽度大于内部两个div宽度之和(如果宽度不够两个div就会错开)*/ #demo1,#demo2{display: inline-block;}/*浮动或设置display以保持在同一行*/ </style> <script type="text/javascript"> var demo = document.getElementById("demo"); var demo1 = document.getElementById("demo1"); var demo2 = document.getElementById("demo2"); demo2.innerHTML=document.getElementById("demo1").innerHTML; function Marquee(){ if(demo.scrollLeft-demo2.offsetWidth>=0){ demo.scrollLeft-=demo1.offsetWidth; } else{ demo.scrollLeft++; } } var myvar=setInterval(Marquee,30); demo.onmouseout=function (){myvar=setInterval(Marquee,30);} demo.onmouseover=function(){clearInterval(myvar);} </script>
我解释下dom结构:
id#demo是最外层,设置滚动区域的宽高。此代码中它的宽度需要比滚动内容的宽度小。
class.scrollbox是容纳两个滚动容器的,它的宽度需要设置得比较宽,以保证能容纳两个滚动内容。
id#demo1和#demo2就是滚动内容了,通过设置浮动或display让他们保持在同一行,循环滚动。
示例中给出的css样式都是基础的必须样式,如果需要其他样式请自行添加。
JavaScript无缝滚动一例
最近做手机站用到了TouchSlide,记录一些现成的可以套用的范式。
banner切换:
<div id="focus" class="focus1"> <div class="hd"> <ul class="clearfix"></ul> </div> <div class="bd"> <ul> <li><a href="swtlink"><img _src="images/banner1.jpg" src="images/blank.png" /></a></li> <li><a href="swtlink"><img _src="images/banner2.jpg" src="images/blank.png"/></a></li> <li><a href="swtlink"><img _src="images/banner1.jpg" src="images/blank.png"/></a></li> </ul> </div> </div> <script type="text/javascript"> TouchSlide({ slideCell:"#focus", titCell:".hd ul", //开启自动分页 autoPage:true ,此时设置 titCell 为导航元素包裹层 mainCell:".bd ul", effect:"left", autoPlay:true,//自动播放 autoPage:true, //自动分页 switchLoad:"_src" //切换加载,真实图片路径为"_src" }); </script>
对应的css样式:
.banner{position: relative;} .banner .hd{position: absolute;width: 54px;bottom: 3px;right: 3px;z-index: 999;} .banner .hd li{width: 10px;height: 10px;background: #fff;border-radius: 10px;display: inline-block;margin:0 4px;overflow: hidden;color: #fff;cursor: pointer;} .banner .hd li.on{background: #FFCC00;color: #FFCC00;}
tab切换:
<div id="tabBox1" class="tabBox"> <div class="hd"> <ul class="clearfix"> <li class="on"><a href="javascript:void(0)">标题1</a></li> <li><a href="javascript:void(0)">标题2</a></li> </ul> </div> <div class="bd" id="tabBox1-bd"> <div>内容</div> <div>内容</div> </div> <script type="text/javascript"> TouchSlide({slideCell:"#tabBox1",effect:"leftLoop"}); </script> </div>
TouchSlide的一些记录
此脚本已停止维护,请使用新版本。
以下内容作废。
2016.12.6
最近ikanman的图片格式有很多变成了.jpg.webp格式的,windows原生不支持此格式。有两个解决办法:
1.安装“WebP Codec for Windows”这个程序,安装之后可以使用windows图片查看器查看webp格式的图片。
2.安装支持webp格式的图片查看器,比如honeyview。
首先下载上面的文件,解压后把php文件丢到127.0.0.1里(如果放在其他网络位置,需要修改js中phpPatch的值为对应值)。
配置完成后,打开漫画阅读页面。
如果已经安装了UserScript,则可以看到页面顶部的页码区域会出现一个“开始下载”按钮(见上图)。
如果没有使用UserScript,则可以复制js文件的全部代码,在漫画阅读页面的浏览器控制台里执行js代码。正确结果也是出现“开始下载”按钮。
点击“开始下载”按钮即可开始下载。下载器会这个页面一直下载到漫画最后一页,保存到硬盘上(就是说可以从漫画的任何页面开始往后下载)。
下载时页面顶部会出现进度提示区域,点击可以设置是否停止下载。
下载器默认会在ikanman_down.php所在的文件夹里创建一个ikanman文件夹,之后会把下载到的漫画存放在里面,如图:
如果想修改存放位置,可修改php中$rootdir变量的值。
本文中说的比较简略,详见说明文档。如果遇到问题可以再问我。QQ交流群:499873152
ps:如果提示缺少msvcr110.dll,请安装VC++2012运行库的32位版本,之后重新启动wampserver。
ps2:如果下载中出了问题导致没下载完(如页面崩溃什么的),可以看一下下载到哪一页了,然后打开下载到的那一页,继续下载。
Read More →
仙尊ikanman漫画下载器发布啦~
以click事件为例,我们常用onclick和addEventListener来添加它。但是有添加就要有解除,下面先以绑定一个非匿名函数为例:
function test () { console.log("yyy"); } a.onclick=test; a.addEventListener("click", test, false);
事件函数test是有名字的。如果是无名字的函数,如下:
a.onclick=function(){ console.log("yyy"); } a.addEventListener("click", function(){ console.log("yyy"); }, false);
添加的时候,不管事件函数有没有名字,在效果上是一样的。
添加的时候要注意:
1.onclick和addEventListener添加同一类型的事件是不会互相覆盖的。所以在上面任意一个例子中,都会输出两次"yyy"。
2.如果同一元素存在多个onclick,或同一元素用多个addEventListener添加了同一事件,都是后面添加的事件覆盖前面添加的事件。当然,onclick和addEventListener还是不会互相覆盖的。
但说到移除事件,则有点坑。
1.对于onclick添加的事件,不管它的事件函数时有名字的还是无名字的,都可以将onclick事件设置为空来移除。如:
a.onclick=null;
2.对于addEventListener添加的事件,则比较坑。如果事件函数是有名字的,我们可以用removeEventListener来移除,如:
a.removeEventListener("click", test , false);
但如果事件函数是没有名字的,则无法移除。
虽然可能有一些变通的方法——如在函数外设立一个状态指示器,在每次执行函数时都进行判断,如果状态变成某个值,则不执行函数,就达到了不让函数生效的目的。但是在根源上,这个事件还是没有移除。
综上,当我们需要使用removeEventListener来移除事件的话,方法只能是给函数起个名字了。