2016-0913am day05
1. 定时器
什么是定时器: 让程序按照指定的时间间隔自动执行任务
何时需要定时器: 动画
1.周期性定时器: 让程序按照指定的时间间隔反复自动执行同一任务。
- 何时: 只要反复自动执行一项任务
- 如何: 3件事:
- 任务函数: 定义每次要执行的任务
- 启动定时器:
let timer = setInterval(任务函数,interval) //让引擎每隔interval ms自动执行一次任务函数
注意:interval
是时间,单位是毫秒,其中timer
是当前定时器任务的一个序号
- 停止定时器:
clearInterval(timer)
如果需要停止定时器,都要在启动时就提前保存序号
- 如何自动停止定时器:
在任务函数的结尾,判断一个临界值,如果达到临界值,就停止定时器
例子1:写一个距离放学时间还剩下几小时几分钟几秒的倒计时
html中
<h1>距离放学还有<span id="time"></span></h1>
<button onclick="stop(this)" >||</button>
js中
//Step1: 定义任务函数,计算now到end的时间差(当前时间至目标时间差)
function task() {
//定义目标时间end:
var end = new Date("2019/1/20 12:00");
var now = new Date(); //获得当前时间now
//获得时间差(s): end-now /1000
var s = Math.round((end - now) / 1000);
if (s > 0) { //如果s>0
var h = Math.floor(s / 3600); //求小时(h):
h < 10 && (h = "0" + h); //如果h<10,就改为0+h
var m = Math.floor(s % 3600 / 60); //求分钟(m):
m < 10 && (m = "0" + m); //如果m<10,就改为0+m
s %= 60; //求秒(s):
s < 10 && (s = "0" + s); //如果s<10,就改为0+s
//找到id为time的span,设置其内容为h:m:s
document.getElementById("time").innerHTML = h + ":" + m + ":" + s;
} else { //停止定时器
clearInterval(timer);
timer = null;
document.getElementById("time").innerHTML = "下课了!";
}
}
//Step2: 启动定时器:
task();//想让这个倒计时一开始就出来,不会卡一秒再出来,所以先调用一次
var timer = setInterval(task, 1000);//注意这个task不要加(),且匿名函数的this指的是window
//Step3: 停止定时器:
function stop(btn) {
//如果btn的内容为||
if (btn.innerHTML == "||") {
clearInterval(timer); //停止定时器
timer = null;
btn.innerHTML = "|>"; //修改btn的内容为|>
} else { //否则
timer = setInterval(task, 1000); //启动定时器
btn.innerHTML = "||"; //修改btn的内容为||
}
}
例子2:用纯js实现一个动态表盘
html中
<div id="clock">
<div id="h"></div>
<div id="m"></div>
<div id="s"></div>
<div id="a1">I</div>
<div id="a2">II</div>
<div id="a3">III</div>
<div id="a4">IIII</div>
<div id="a5">V</div>
<div id="a6">VI</div>
<div id="a7">VII</div>
<div id="a8">VIII</div>
<div id="a9">IX</div>
<div id="a10">X</div>
<div id="a11">XI</div>
<div id="a12">XII</div>
</div>
css中
#clock {
width: 100px;
height: 100px;
border-radius: 50%;
border: 2px solid black;
position: relative;
}
#s {
width: 2px;
height: 55px;
position: absolute;
top: 5px;
left: 49px;
background-color: red;
transform-origin: 50% 45px;
}
#m {
width: 4px;
height: 50px;
position: absolute;
top: 10px;
left: 48px;
background-color: black;
transform-origin: 50% 40px;
}
#h {
width: 6px;
height: 45px;
position: absolute;
top: 15px;
left: 47px;
background-color: black;
transform-origin: 50% 35px;
}
div[id^="a"] {
position: absolute;
font-size: .5em;
text-align: center;
width: 7px;
height: 5px;
top: 0;
left: 46.5px;
transform-origin: 50% 50px;
}
#a4,
#a8 {
font-size: .4em;
font-weight: bold
}
#a1 {
transform: rotate(30deg)
}
#a2 {
transform: rotate(60deg)
}
#a3 {
transform: rotate(90deg)
}
#a4 {
transform: rotate(120deg)
}
#a5 {
transform: rotate(150deg)
}
#a6 {
transform: rotate(180deg)
}
#a7 {
transform: rotate(210deg)
}
#a8 {
transform: rotate(240deg)
}
#a9 {
transform: rotate(270deg)
}
#a10 {
transform: rotate(300deg)
}
#a11 {
transform: rotate(330deg)
}
js中:时钟有12个大格子,每个大格子中有5个小格,总共有60个小格。时钟一圈为360度,大格子角度为360/12=30度,小格子角度为360/60=6度
秒针:角度=秒数*6
分针:角度=(秒数/60+分数)*6
时针:角度=((秒数/60+分数)/60+小时数)*30
//Step1: 定义任务
function task() {
var now = new Date(); //获得当前时间now
var h = now.getHours(); //获得h
h >= 12 && (h -= 12); //如果h>=12,就h-12
var m = now.getMinutes(); //获得m
var s = now.getSeconds(); //获得s
var sDeg = s * 6; //计算sDeg
var mDeg = (s/60+m)*6; //计算mDeg
var hDeg = ((s/60+m)/60+h)*30; //计算hDeg
//查找id为h的div,设置其transform属性为:rotate(hDegdeg)
document.getElementById("h")
.style
.transform = "rotate(" + hDeg + "deg)";
//查找id为m的div,设置其transform属性为:rotate(mDegdeg)
document.getElementById("m")
.style
.transform = "rotate(" + mDeg + "deg)";
//查找id为s的div,设置其transform属性为:rotate(sDegdeg)
document.getElementById("s")
.style
.transform = "rotate(" + sDeg + "deg)";
}
//Step2: 启动定时器:
task();
setInterval(task, 1000);
2.一次性定时器: 让程序先等待一段时间,再自动执行一次任务。( 执行一次后,自动停止)
- 何时: 只要先等待一段时间,再执行一次任务
- 用法: 同周期性定时器
- 任务函数:定义每次要执行的任务
- 启动定时器:
let timer=setTimeout(task,wait); //wait是等待时间
注意:wait是时间,单位是毫秒,其中timer是当前定时器任务的一个序号
- 停止定时器:
clearTimeout(timer);
不是停止执行,而是停止等待
例子1:支付成功后有一个5秒钟的倒计时,若用户未操作则倒计时结束后,自动跳转页面
html中
<span id="time">5秒钟后自动关闭</span><br>
<a href="javascript:stop()">留在本页</a>
js中
//Step1: 任务:
function task() {
var span = document.getElementById("time"); //获得id为time的元素,保存在变量span中
var n = parseInt(span.innerHTML); //将span的内容,转为整数,保存在n中
n--;
if (n > 0) {
span.innerHTML = n + span.innerHTML.slice(1); //设置span的内容为:n+span的内容截取1之后的剩余字符
} else {
window.close(); //关闭页面
}
}
//Step2: 启动一次性定时器
var timer = setInterval(task, 1000);
//Step3: 停止定时器:
function stop() {
clearInterval(timer);
timer = null;
}
例子2:在浏览器窗口的右下角设置一个弹窗,间隔一段时间弹出,也可关闭
html中
<div id="msg">
<a href="javascript:adv.moveDown()">X</a>
</div>
css中
#msg {
width: 200px;
height: 200px;
position: fixed;
right: 30px;
bottom: -200px;
background-color: LightBlue;
}
#msg>a {
float: right;
padding: 5px 10px;
border: 1px solid black;
cursor: pointer;
}
js中
var adv = {
distance: 0, //总距离
duration: 2000, //总时间
steps: 200, //总步数
step: 0, //步长
interval: 0, //每步时间间隔
timer: null, //保存定时器序号
moved: 0, //保存已经移动的步数
div: null, //保存广告div
WAIT: 3000, //保存等待时间
init: function () {
this.div = document.getElementById("msg");//查找id为msg的div保存在div属性中
this.distance = -parseFloat(
getComputedStyle(this.div).bottom //获得DISTANCE: 获得div计算后的样式中的bottom属性值,转为浮点数,*-1
);
this.interval = this.duration / this.steps;//计算interval: duration/steps
this.step = this.distance / this.steps; //计算step:distance/steps
this.moveUp(); //启动上移
},
//启动上移
moveUp: function () {
this.timer = setInterval(
this.moveStep.bind(this, 1), this.interval); //启动周期性定时器,设置任务为moveUpStep,将序号保存在timer中
},
//向上移动一步
moveStep: function (dir) {
var bottom = parseFloat(getComputedStyle(this.div).bottom);//获得div计算后的样式的bottom值,转为浮点数,保存在变量bottom中
this.div.style.bottom = bottom + dir * this.step + "px";//设置div的bottom值为bottom+step
this.moved++;
if (this.moved == this.steps) { //如果moved等于STEPS
clearInterval(this.timer); //停止定时器,timer置为null,moved归零
this.timer = null;
this.moved = 0;
if (dir == -1) { //如果是下移结束
setTimeout(
this.moveUp.bind(this), this.WAIT);//启动一次性定时器,传入moveUp方法作为任务,等待时间设置为WAIT
}
}
},
moveDown: function () {
if (this.timer == null) //如果timer是null
this.timer = setInterval( //启动周期性定时器,传入moveStep作为任务,将序号保存在timer中
this.moveStep.bind(this, -1), this.interval
);
}
}
adv.init();
注:定时器中的回调函数必须等到主程序执行完才能执行,这是常考的笔试题。
2. BOM常用对象:
1.history: 保存当前窗口打开后成功访问过的url历史记录栈
history.go(n): 前进n步
例如:
前进一步: history.go(1)
后退一步: history.go(-1)
刷新: history.go(0)
各个浏览器对于history的维护不同,不需要深究,只需了解
//a.html
<div>
<a href="a.html">1</a>
<a href="b.html">2</a>
<a href="c.html">3</a>
</div><br/>
<div>
<a href="javascript: history.go(-1)">后退一次</a>
<a href="javascript: history.go(1)">前进一次</a>
<a href="javascript: history.go(2)">前进二次</a>
</div>
//b.html
<div>
<a href="a.html">1</a>
<a href="b.html">2</a>
<a href="c.html">3</a>
</div><br/>
<div>
<a href="javascript: history.go(-2)">后退二次</a>
<a href="javascript: history.go(-1)">后退一次</a>
<a href="javascript: history.go(1)">前进一次</a>
<a href="javascript: history.go(2)">前进二次</a>
</div>
//c.html
<div>
<a href="a.html">1</a>
<a href="b.html">2</a>
<a href="c.html">3</a>
</div><br/>
<div>
<a href="javascript: history.go(-2)">后退二次</a>
<a href="javascript: history.go(-1)">后退一次</a>
<a href="javascript: history.go(1)">前进一次</a>
</div>
2.location: 封装当前窗口正在打开的url的对象(粗俗的说就是地址栏)
2.1location的属性
url的组成回忆:
例子:http://www.w3school.com.cn/js/js_window_location.asp
冒号左边是协议,冒号右边是主机和端口号,往后是路径,路径有两种,一种如果有锚点会有#...,如果提交了表单后面会有问号?,后面有一堆变量,那叫search,叫查询字符串,
例子:
当前浏览的网址是:
https://www.jianshu.com/writer#/notebooks/29423782/notes/33732804/preview
location.href:"https://www.jianshu.com/writer#/notebooks/29423782/notes/33732804/preview"
location.protocol:"https:"
location.host:"www.jianshu.com"
location.hostname:"www.jianshu.com"
location.port:" " //没有端口默认是80端口
location.pathname:"/writer"
location.hash:"#/notebooks/29423782/notes/33732804/preview"
location.search:" "
属性 | 含义 | 备注 |
---|---|---|
href | 设置或返回完整url | |
protocol | 设置或返回协议 | |
host | 设置或返回主机名+端口 | |
hostname | 设置或返回主机名 | |
port | 设置或返回端口 | |
pathname | 设置或返回路径 | |
hash | 设置或返回#锚点名 | |
search | 设置或返回?表单变量 |
例子:在提交表单时,将location.search(url中的字符串)变成哈希数组或者对象的形式。
html中
<form>
姓名:<input name="username"/>
密码:<input type="password" name="pwd"/>
<input type="submit"/>
</form><br>
<!--2. 实现不能后退的页面跳转-->
<a href="javascript:location.replace('http://www.baidu.com')">go to baidu</a>
js中
function getSearch(){
//"?变量名=值&变量名=值"
var search=location.search; //获得url中的查询字符串,保存在变量search中:
var params={};//创建空对象params
if(search!=""){//如果search!=""
var props=search.slice(1).split("&");//去掉search开头的?,再按&切割,将结果保存在变量props中
for(var i=0;i<props.length;i++){
var arr=props[i].split("=");//将当前元素按=切割,结果保存在变量arr中
//向params对象中添加新属性:
//属性名为arr中第0个元素
//属性值为arr中第1个元素
params[arr[0]]=arr[1];
}
}
return params;//返回params
}
console.dir(getSearch());//{变量名:值,变量名:值}
2.2 location的方法
location的方法基本上用来在当前窗口打开新链接
方法 | 含义 | 备注 |
---|---|---|
assign() | 加载新的文档 | |
reload() | 重新加载当前文档 | |
replace() | 用新的文档替换当前文档 |
在当前窗口打开新链接:
location.href="新的url"; //js中只要这个一赋值,立刻就会在当前窗口打开新的url
location="新的url"; //不写.href 一样会立刻打开新链接
location.assign("新的url"); //这个本质是把新的url赋值给了href
在当前窗口打开,不可后退:
location.replace("新的url");
重新加载当前页面:
location.reload(force) //默认不强制
其中: force表示是否强制从服务器硬盘获取文件。 true/false
3.navigator: 封装浏览器配置信息的对象
navigator每个浏览器封装的不同,记住三个最常用的就行。
- cookieEnabled: 判断浏览器是否启用cookie。(cookie: 客户端本地,持久存储用户私密数据的文件)
//如果浏览器启用了cookie
if(navigator.cookieEnabled){
document.write("<h1>已启用cookie,请妥善保存个人信息</h1>");
}else{//否则
document.write("<h1>cookie已禁用,记住密码功能无法使用</h1>");
}//Chrome: 设置->高级->隐私->cookie->
//选中两个阻止xxx
- plugins: 包含了所有插件的信息
//判断浏览器是否包含指定名称的插件
function checkPlugin(pname){
for(var i=0;i<navigator.plugins.length;i++){ //遍历navigator的plugins集合
if(navigator.plugins[i].name==pname){//如果当前插件的name等于pname
return true;
}
}
return false;
}
console.log(
checkPlugin("Chrome PDF Viewer"),//true
checkPlugin("QQ Music")//false
);
- userAgent: 包含浏览器名称和版本号的字符串
document.write("<h1>" + navigator.userAgent + "</h1>");
var browser = "unknown";
var ua = navigator.userAgent;
if (ua.indexOf("MSIE") != -1) { //如果ua中包含MSIE
browser = "IE"; //browser赋值为"IE"
} else if (ua.indexOf("Firefox") != -1) { //否则,如果ua中包含Firefox
browser = "Firefox";
} else if (ua.indexOf("OPR") != -1) { //否则,如果ua中包含OPR
browser = "Opera"; //browser赋值为"Opera"
} else if (ua.indexOf("Chrome") != -1) { //否则,如果ua中包含Chrome
browser = "Chrome";
} else if (ua.indexOf("Safari") != -1) { //否则,如果ua中包含Safari
browser = "Safari";
} else if (ua.indexOf("Trident") != -1) { //否则,如果ua中包含Trident
browser = "IE"; //browser赋值为"IE"
}
document.write("<h1>浏览器名称: " + browser + "</h1>");
var version = "unknown";
if (browser != "unknown") { //如果browser不是"unknown"
if (browser == "Opera") { //如果browser是Opera
var i = ua.indexOf("OPR") + 3 + 1; //在ua中查找OPR的位置,+3+1,保存在i中
version = parseFloat(ua.slice(i, i + 3)); //截取ua中i位置之后的3位,转为浮点数保存在version中
} else if (browser == "IE" && ua.indexOf("MSIE") == -1) { //否则,如果browser是"IE",且ua中找不到"MSIE"
version = "11"; //将version改为"11"
} else { //否则
var i = ua.indexOf(browser) + browser.length + 1; //在ua中查找browser的位置,+browser的字符个数+1,保存在i中
version = parseFloat(ua.slice(i, i + 3)); //选取ua中i位置之后的3位,转为浮点数保存在version中
}
}
document.write("<h1>版本号: " + version + "</h1>");