saber 酱的抱枕

Fly me to the moon

09/24
2016
学习

使用立即执行函数创建独立作用域

设想网页上有四个按钮:

<input type="button" value="0">
<input type="button" value="1">
<input type="button" value="2">
<input type="button" value="3">

我们用for循环处理它们时,如果要用到它们对应的序号,则可能出现问题。如下JavaScript代码:

var bts=document.querySelectorAll("input");
for (var i = 0; i <= bts.length - 1; i++) {
    bts[i].addEventListener("click",function(){
        alert(i);
    })
}

按照设想,当我们点击按钮时,它们会从左到右分别弹出0/1/2/3,但实际上,全部弹出的是4。这里显而易见有两个问题:
1.为什么弹出的数字都一样;
2.为什么弹出的是4。

其实原因是同一个,那就是for循环里的i是贯穿其整个作用域的。我们给4个按钮分配的i是同一个变量,当这个变量变了的时候,4个按钮上绑定的i都变了。for循环从开始运行到结束,i的值依次是0/1/2/3/4(到4的时候停止运行),最后定格在了4。当我们在for循环执行完之后去点击按钮,i已经是4了,所以全部弹出的是4。

我们可以利用立即执行函数(匿名函数)来创建独立作用域,把每个按钮的事件都在独立作用域里绑定。并且我们绑定时不直接使用i,而是把i的值传递进去进行绑定。这样就可以解决上面的问题。代码如下:

var bts=document.querySelectorAll("input");
for (var i = 0; i <= bts.length - 1; i++) {
    !function(ii){
        bts[i].addEventListener("click",function(){
            alert(ii);
        })
    }(i)
}

这里面除了用立即执行函数包裹了绑定过程,还有个地方要注意,就是这个立即执行函数要有个参数,然后在执行它时把i作为参数传递进去。这样,绑定事件时所使用的ii是具体值,而非变量i。

之后,我们点击按钮,发现依次弹出0/1/2/3,问题得以解决。

使用立即执行函数创建独立作用域

09/23
2016
学习

网页评分工具demo

给文章或其他作品打分是很常见的功能,不过我之前做的网站里都没用到这个功能,于是今天自己写了个demo。

可以设置任意颗星星数;
可以设置一开始显示评分还是不显示评分;
每个人只能打分一次。
这个demo一星一分。


代码如下:

<div class="rate" data-value="0">
	<i title="1分"></i><i title="2分"></i><i title="3分"></i><i title="4分"></i><i title="5分"></i><i title="6分"></i><i title="7分"></i><i title="8分"></i><i title="9分"></i><i title="10分"></i>
</div>
<style type="text/css">
	.rate{height: 26px;}
	.rate i{display: inline-block;width: 26px;height: 100%;background-image: url(/f/pixiv_star.png);cursor: pointer;background-position: 0 0;}
    .rate .bgNone{background-position: 0px 0px;}
    .rate .bgHover{background-position: -26px 0px;}
    .rate .bgSure{background-position: -52px 0px;}
	.cursordef i{cursor:default;}
</style>
<script src="ratev0.1.js"></script>

外层div有个data-value属性,表示预设评分。设置为0则表示不显示这幅作品的评分,星星都不亮;大于0则为当前得分,并且会亮起对应的星星。
里面的每个i标签是一个星星,数量可以随意调整。
css样式里设置宽高来布局,并设置背景图片。把三种星星样式做到一张图片上,使用背景定位让三个样式显示三种背景图片。分别是bgNone(这个星星不亮的图案),bgHover(鼠标经过时星星亮起来),bgSure(这个星星有评分)。
当用户点击了一个星星后,会产生评分,之后就不能再点击了。

网页评分工具demo

09/20
2016
学习 软件

去除百度贴吧的视频

// ==UserScript==
// @name         去除贴吧视频
// @namespace    http://www.saber.love/?p=3014
// @version      0.1
// @description  去除百度贴吧的视频
// @author       雪见仙尊
// @match        http://tieba.baidu.com/*
// @grant        none
// @run-at	document-end
// ==/UserScript==

function removeVideoElement () {
	var topVideo=document.querySelector(".video_frs_head");	//贴吧顶部的视频区域
	if (!!topVideo) {
		topVideo.parentNode.removeChild(topVideo);
	}
	var videoPrve=document.querySelectorAll(".threadlist_video");	//帖子列表里未播放的视频
	for (var i = videoPrve.length - 1; i >= 0; i--) {
		videoPrve[i].parentNode.removeChild(videoPrve[i]);
	}

	var videoTag=document.querySelectorAll("video");	//网页上正在播放的视频
	for (var i = videoTag.length - 1; i >= 0; i--) {
		videoTag[i].parentNode.removeChild(videoTag[i]);
	}
}
removeVideoElement();
var removeVideoT=setInterval(removeVideoElement,1000);

手机版百度贴吧现在能发视频了,但是百度在电脑端推广视频就太无耻了。

顶部的视频(如剑网三吧顶部就有)竟然自动播放。(这个导致我chrome的gpu加速经常出问题,网页变成一片片的黑块)

帖子列表里的视频,虽然一开始显示的是预览图,但是你鼠标一经过就开始播放了,而且还停不了,必须再点一下,等视频尺寸变大,才又停止播放的按钮。

感觉自己宛如一个智障一样被玩弄,所以写了个脚本去除视频。帖子里的视频也会去掉,断子绝孙好爽的。(优酷土豆等外部视频不受影响)

你也可以到这里安装本代码的UserScript脚本

去除百度贴吧的视频

09/19
2016
学习 软件

获取半次元(bcy.net)coser作品的大图网址

document.body.insertAdjacentHTML('beforeend', `<div id="shouUrl" style="position: fixed; right: 0px; top: 100px; padding: 15px 20px; background: rgb(46, 178, 234); color: rgb(255, 255, 255); border-radius: 5px; text-align: center; line-height: 24px; font-size: 16px; cursor: pointer;">显示大图url</div>`);
document.querySelector("#shouUrl").addEventListener("click", () => {
	let newW = window.open();
	document.querySelectorAll(".img-wrap img").forEach(el => {
		newW.document.write(/.*(\.jpg|\.png)/.exec(el.src)[0].replace(/p\d.*banciyuan/, 'img-bcy-qn.pstatp.com') + '<br>');
	});
});

使用方法:
打开任意的cos作品页面,然后在浏览器的控制台里执行上面的代码。

你也可以在此安装本代码的UserScript版(推荐)。

当手动执行了代码或点击UserScript生成的按钮之后,浏览器会打开一个新的页面,并显示作品上所有图片的url:

获取半次元coser作品的大图网址

复制全部网址,用下载软件批量下载即可。

注意:
1.由于本工具会打开一个新页面并输出url,所以当你遇到脚本运行完了却没有弹出新页面的时候,请看一下是不是弹窗是被浏览器拦截了。
2.由于半次元图片的文件名是随机生成的字符,所以下载下来的图片顺序可能是混乱的。

获取半次元(bcy.net)coser作品的大图网址

09/13
2016
学习

JavaScript过滤PHP中不允许做文件名的字符

var reg = new RegExp(/'|#|&|\\|\/|:|\?|"|<|>|\*|\|/g);
string=string.replace(reg,"_");

JavaScript本身不能方便的保存文件,所以我做的几个下载器是用ajax把文件参数传给PHP,然后由PHP去建立文件的。这个正则用来过滤掉一些不能做文件名的特殊字符/特殊符号。

这个正则去掉了以下字符串:

 ' # & \ / : ? " < > * | 

注意前3个其实是能在windows中做文件名的。只是用在url中就可能会出现意外情况。

其中'会导致php创建文件时路径异常而失败(它被当做单引号了,包裹着字符串);
#则是不能用在get传递的参数里,(因为从#开始往后的字符都会被当做锚点信息,不会被当做参数);
参数里也不能出现我们意料之外的“&”,所以&也去掉(可以考虑下替换成&的转义字符);
剩下几个是windows资源管理器中不允许做文件名/文件夹名的字符。

这个列表权当是一点微小的贡献。

JavaScript过滤PHP中不允许做文件名的字符

09/9
2016
学习

半次元(bcy.net)图片下载器发布啦

bcy.net 图片下载器 cosplay图片 id41053745

半次元(byc.net)是一个中文的cosplay交流社区,里面有许多高质量的cosplay作品。有时候,我们看到自己喜欢的cosplay作品,可能想保存下来。半次元提供直接查看原图的功能,但是一张张图片保存比较麻烦。为了简化保存步骤,我使用JavaScript+PHP做了一个简单的下载工具。

下载本工具完整版

本工具包含bcy_download.js和bcy_download.php两个文件。


配置步骤:
1.把bcy_download.php放到web环境中;
2.把bcy_download.js的phpPath变量的值配置为为bcy_download.php的url。
phpPath的默认值为:

http://127.0.0.1/bcy_download.php

使用步骤:
1.在半次元的cosplay图片详情页面执行bcy_download.js中的代码。(你可以复制bcy_download.js代码然后打开控制台手动执行;也可在greasyfork.org安装本UserScript脚本来自动执行)

2.页面右上角出现一个下载按钮:
bcy.net 图片下载器 cosplay图片

3.点击即可开始下载。下载按钮上会有进度提醒:
bcy.net 图片下载器 cosplay图片

等到下载完成,会有弹窗提醒。
bcy.net 图片下载器 cosplay图片

下载的图片会存放在bcy_download.php同目录中的bcyimg文件夹中:
bcy.net 图片下载器 cosplay图片

bcy.net 图片下载器 cosplay图片


注意事项:
1.下载时可能会在一张图那里卡很久,等待即可。(我这边经常下几张就卡住一会儿,不知道半次元对于连续访问大图有没有做限制)
2.由于bcy_download.php会创建中文文件夹来保存图片,所以本工具仅建议在简体中文版本的Windows操作系统上使用。在其他系统上使用可能导致创建的文件夹名字变成乱码。
3.本工具仅做交流学习之用,请合理使用。下载的图片仅供收藏,请勿未经coser授权随意传播。因使用本工具产生的任何问题,本人概不负责。

半次元(bcy.net)图片下载器发布啦

09/1
2016
学习

JavaScript计算明天的日期

计算第二天的日期的要点在于,在跨月时进入下一月,在跨年时进入下一年。其他时间只要天数加1就行。所以找出每个月的最后一天就ok了。

function tomorrow_date (y,m,d){ //参数里的月份需要是自然月。也就是说月份+1这步在传参前就设置好
    var run = false;    //判断是否是闰年
    if (!(y%4)) {       //如果年份是4的整数倍
        if (!(y%100)) {     //如果是整百年
            if (!(y%400)) {     //如果是400的整数
                run = true;
            }
        }else{
            run = true;
        }
    }

    if(d==28&&m==2){    //2月28日
        if(!run) {  //非闰年
            d=1;
            m++;
        }else{  //闰年
            d++;
        }
    }else if(d==29&&m==2){  //2月29日
        d=1;
        m++;
    }else if(d==30&&(m==4||m==6||m==9||m==11)){    //30天的月份里的第30天
        d=1;
        m++;
    }else if(d==31){            //31天的月份里的第31天
        d=1;
        if (m==12){    //如果是12月则进入下一年
            m=1;
            y++;
        }else{
            m++;
        }
    }else{      //如果今天不是月份的最后一天
        d++;
    }

    return "明天是"+y+"年"+m+'月'+d+'日';
}

var myDate = new Date();
var y = myDate.getFullYear();
var m = myDate.getMonth()+1;    //因为js的月份是从0开始的,所以这里月份+1
var d = myDate.getDate();
document.write(tomorrow_date(y,m,d));

感谢TianMao指出闰年的问题~另外他提出了使用Date对象的setDate方法来计算下一天的办法。这个办法很简便,当我们重设了日期(第几天)后,JavaScript会自动更新Date对象的月份、年份,这样就我们就不用自己写上面的判断了。

var myDate = new Date();
myDate.setDate(myDate.getDate()+1);
var y = myDate.getFullYear();
var m = myDate.getMonth()+1;
var d = myDate.getDate();
console.log(y,m,d);

JavaScript计算明天的日期

08/25
2016
学习

JavaScript数组去重的一个方案

刚才我整理出来了一百多行url,想去掉重复的。于是我到JavaScript里建了个数组,把这些url都转成了数组里的字符串。之后我找到了一个使用hashtable(哈希表)的去重算法,比循环更简便:

function unique(arr) {
    var result = [], hash = {};
    for (var i = 0, elem; (elem = arr[i]) != null; i++) {
        if (!hash[elem]) {
            result.push(elem);
            hash[elem] = true;
        }
    }
    return result;
}

上面的方法是有缺陷的,今天在知乎专栏看到了更好的方法,用的是ES6的set类型。set类型不允许添加重复项,所以我们根本不用自己去重了,直接把数组转换文set对象就可以去掉重复项了:

function unique(arr){
    var set = new Set(arr);
    return Array.from(set);
}

JavaScript数组去重的一个方案

08/11
2016
学习

JavaScript中的变量提升

JavaScript有个叫“变量提升”的特性,意为:
在函数里声明的所有变量会被提升到函数顶部声明(但不涉及到赋值)。

示例:

var a=0;
!function(){
	alert(a);
	var a=1;
}()

在函数外声明了变量a=0,之后在函数里重新声明了a=1。
在这中间我们弹出a,它的值不是0,而是undefined。这就是变量提升导致的。发生变量提升之后,函数里声明的a被提升到函数顶部声明了(但这并不涉及到赋值),所以代码实际上相当于这样:

var a=0;
!function(){
	var a;
	alert(a);
	a=1;
}()

所以如果函数外已经声明了一个变量,那么就不要在函数内重复声明它,这样将会触发变量提前,可能会造成一些问题。

如果需要在函数内重复声明,那么将这些变量在函数顶部先声明但不赋值(就是写得和变量提升后的实际代码一样),可以让代码更直观。

其实这个概念是我昨天发布了搜索bilibili评论工具时,8q给我指出的。今天看书很巧的也看到了这个地方,弄清楚了。

JavaScript中的变量提升

08/9
2016
学习 软件

在bilibili评论区搜索某人评论的工具

此工具已失效!

saber pixiv

我用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评论区搜索某人评论的工具