JavaScript里说到延迟执行,一般想到的就是定时器。而且原生的方法里除了定时器,也没什么别的办法了。
但是定时器其实是一种插入机制,只针对它内部的代码做延迟,不能延迟整体代码的执行。
如果在某个时候,我们想让后面的代码全部延迟一定时间执行,只能把后面的代码全都放进定时器(或者改一下代码,只放调用部分)。多嵌套了一层,在代码的阅读和理解上产生了负面效果,很不舒服。
想要实现类似于其他程序的sleep函数的效果,我们可以用笨办法来做一个,实现整体代码的延迟。
示例:
function sleep(milliSeconds){
var startTime = new Date().getTime();
while (new Date().getTime() < startTime + milliSeconds);
}
console.log("1");
sleep(1000);
console.log("2");
不过使用sleep需要小心,因为它是整体延迟,会阻塞JavaScript进程,导致页面也卡住(类似于ajax的同步模式)。
比如上例代码,延迟一秒。如果在页面加载时执行,由于这一秒里JavaScript没执行完,所以页面加载时间就会增加一秒(+1s?),同时在这1秒里无法对页面进行操作。
那如果在页面加载完成后执行呢?这也会导致页面卡住1秒,因为sleep的代码导致CPU占用非常高,页面除了循环什么都不做了,导致用户在这1秒里无法对页面进行操作。
所以这个sleep虽然在效果上是真正的sleep(参考其他编程语言),但还是需要确认使用场景才能用,不能乱用。毕竟后台sleep用户只是多等了1秒,前台sleep却会导致页面卡住,对用户操作会产生直接的影响。
JavaScript中的Blob对象可以存储二进制数据,并且还可以为数据指定MINE类型,因此适合在网页上储存文件用。
创建Blob对象需要使用new Blob()构造函数,它的语法如下:
Blob(blobParts[, options])
它有两个参数,第一个参数blobParts是要转化为Blob对象的数据,它必须在一个数组里。即使这份数据本来是独立的,也要创建一个数组把它包含到数组里。
第二个参数是可选的,使用Object类型的键值对来指定MINE类型。
示例:
var data='<b>aaa</b>';
var blob=new Blob([data],{"type":"text/html"});
console.log(blob);
上例中是储存了一个html类型的Blob对象,实际使用中我们也可以储存其他文件类型,常见的有图片、json等。
相关资料:MDN上的相关内容
Read More →
最近把之前做的一个百度贴吧只看楼主的脚本改了下,发布到了greasyfork上。
在帖子的任何地方,按下Alt+L组合键即可自动点击“只看楼主”,不用再翻到帖子顶部去点击啦~
ps:在只看楼主模式下,再次按下Alt+L组合键,就会取消只看楼主了。
代码:
document.addEventListener("keydown", function(event) {
var ev = event || window.event;
if (ev.altKey&&ev.keyCode==76) {
document.querySelector("#lzonly").click();
}
}, false);

今天想找个百度贴吧小尾巴的脚本,但是有些功能太多,我用不着那么复杂的,所以自己写了个简单的。(简陋到没有前台设置界面)
可以插入一条文字内容和(或)一张图片,分别在两个变量里设置(在脚本里修改):

如果两条都设置了内容,那么就会一起发出去。你也可以清空文字或图片对应的内容,之后就不会追加那条内容了。
要使用时,使用快捷键Shift+Enter提交,就会加上小尾巴。如果使用贴吧的正常方式——Ctrl+Enter或者点击提交按钮,就不会加上小尾巴。
这个脚本已经失效,并且我也不维护了,抱歉。
最近我修改某个网站,删除了很多上传的图片,但是又懒得去文章里一篇篇去掉出错的图片(任务量太大),所以就想到了用JavaScript在网页上找出出错的图片,并将其隐藏。
一开始我自己尝试了写了一些代码试试,主要是使用img元素的onerror事件。虽然代码在demo中达到了预期效果,但是加在实际页面里却不生效。对此我有一些猜测,但尚不能确定准确原因,后来还是用谷歌搜了现成的代码。
document.addEventListener("error", function(e){
var elem = e.target;
if(elem.tagName.toLowerCase() === 'img'){
// 如果引发error事件的元素是img元素,就进行处理
elem.style.display="none"; //隐藏该图片
// elem.src = "/img/hint.jpg"; //或者替换为其他图片
}
}, true /*指定事件处理函数在捕获阶段执行*/);
将这份代码加在网页开头(所有img元素之前)即可。
今天我使用百度地图生成器制作在线地图之后,发现了标注图片失效的问题。
正常时:

生成后:

搜了下这个情况,好像是去年底出现的,官方论坛上有人反映但一直没有恢复。
后来我找到了原因。我们使用百度地图生成器添加标注的时候是正常的,因为当时显示的是确实存在的图片。后来生成的地图里,标注图标使用的图片是另一个图片,但是这个图片已经不存在了,所以就出现了这个问题。
我们可以将生成后的地图里的不存在的图片替换为地图生成器里的正常图片来解决问题。将下面的JavaScript代码加在百度地图代码的页面里即可:
var bzT=window.setInterval(function () {
if (!!document.querySelector("#platform > div:nth-child(2) > div:nth-child(5) > span > div > img")) {
document.querySelector("#platform > div:nth-child(2) > div:nth-child(5) > span > div > img").src="http://api.map.baidu.com/lbsapi/creatmap/images/us_mk_icon.png";
clearInterval(bzT);
}
},500)
JavaScript是可以获取Response Header(响应头)的信息的:
如果是使用XMLHttpRequest, 这个对象本身有一个getResponseHeader(DOMString header)的方法来获取。
如果是使用jQuery.ajax, 在success属性对应的回调函数中,第三个参数会被jQuery设置一个jqXHR的对象,这个对象是对XMLHttpRequest对象的一个封装,也是有getResponseHeader方法的。
不过我这里要说的是GM_xmlhttpRequest,也就是俗称的“油猴脚本”里的功能。在firefox里的油猴扩展是Greasemonkey,在chrome中则是Tampermonkey。它们都内置了GM_xmlhttpRequest方法,用于处理ajax事件。
GM_xmlhttpRequest有个很好用的地方是它不会受跨域限制(当油猴脚本跨域时,会先提示你是否允许跨域,允许即可)。
要使用GM_xmlhttpRequest,需要先在脚本头部引入GM_xmlhttpRequest:
// @grant GM_xmlhttpRequest
然后用GM_xmlhttpRequest的head方法获取响应头:
GM_xmlhttpRequest({
url: "url",
method: "HEAD",
onload: function(response) {
console.log(response.responseHeaders);
}
});
我获取了p站一个图片的响应头,输出类似下面:
Date: Tue, 07 Mar 2017 05:31:54 GMT X-Content-Type-Options: nosniff Last-Modified: Tue, 08 Mar 2016 09:00:36 GMT Server: nginx Content-Type: image/jpeg Cache-Control: max-age=31536000 Accept-Ranges: bytes Content-Length: 528794 Expires: Fri, 02 Mar 2018 10:41:44 GMT
不过我现在还有个疑惑,就是油猴怎么从响应头中提取某个特性属性的值。它好像没有getResponseHeader方法。
我最近做了一个带下拉菜单的导航,学到了event.currentTarget的使用。
demo如下:
代码:
<nav>
<ul>
<li class="lelve1">
<a href="">下拉菜单</a>
<div class="subNav">
<a href="">企业简介</a>
<a href="">发展历程</a>
<a href="">主营业务</a>
</div>
</li>
</ul>
</nav>
<script src="http://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
<script>
var isHover=false;
$(".lelve1").mouseenter(
function (event) {
isHover=true;
$(this).find(".subNav").fadeIn();
//$(event.currentTarget).find(".subNav").fadeIn();
}
);
$(".lelve1").mouseleave(
function (event) {
isHover=false;
var a=$(this);
setTimeout(function () {
if (!isHover) {
a.find('.subNav').fadeOut();
//$(event.currentTarget).find(".subNav").fadeOut();
}
},50)
}
);
</script>
因为鼠标进入、鼠标离开事件都是绑定在一级导航上的,所以操作子导航的显示、隐藏时,都是通过在一级导航的元素里寻找子元素达到的:
$(this).find(".subNav").fadeIn();
a.find('.subNav').fadeOut();
这时都是使用this来指代一级导航,但除了使用this,还有另一个办法,就是使用event.currentTarget。
那event.currentTarget是什么呢?event.currentTarget指向事件所绑定的元素。
我们的鼠标进入、鼠标离开都是绑定在一级导航上,所以event.currentTarget所指向的元素始终是一级导航,使用起来很方便,而且可靠。
this在多层事件函数嵌套时经常会发生改变。但如果使用event.currentTarget的话,在这个作用域链里,event.currentTarget都不会变。所以我觉得event.currentTarget更方便可靠。
ps:event的属性里有一个大概比event.currentTarget更常用的,是event.target,指向触发该事件的元素。
event.currentTarget指向事件所绑定的元素,而event.target始终指向事件发生时的元素。
以前我有个错误的认知,以为哪个元素绑定的事件,那么触发事件的元素也是这个元素。其实不是的,像本例,当鼠标从子导航上离开时,触发一级导航mouseleave事件的元素(event.target)是a标签,而不是一级导航li标签。
今天看到一个代码,通过document.all函数判断浏览器是否是IE。代码大致是这样的:
if (document.all){
// 是IE
}else{
// 不是IE
}
这里面有个有意思的地方。
document.all函数会返回页面上所有html元素的集合,现在主流浏览器均支持,比如在chrome中执行一下:

在返回的集合中包含了页面上所有的html元素。
那么问题来了,既然chrome也支持这个函数,结果也不为空,这样判断时不应该是true吗?
试一下将其转换为布尔值,结果竟然是false!惊了!

其实,在IE之外的浏览器里,运行 typeof document.all ,得到的都是结果都是undefined。而在IE里就是object。
这个现象是有历史原因的。document.all最早是由IE4实现的,当时很多程序猿就通过document.all来判断是否是IE浏览器。后来其他浏览器也实现了document.all,但是又不想被旧程序判断为IE浏览器,所以就把document.all的类型设置为undefined了。
这样,在IE之外的浏览器里判断document.all就会得到false了。
ps:IE11里判断document.all也是false了,所以此方法已经不可靠。