定时器,BOM常用对象: history, location, navigator-05

2016-0913am day05

1. 定时器

什么是定时器: 让程序按照指定的时间间隔自动执行任务
何时需要定时器: 动画

1.周期性定时器: 让程序按照指定的时间间隔反复自动执行同一任务。
  • 何时: 只要反复自动执行一项任务
  • 如何: 3件事:
  1. 任务函数: 定义每次要执行的任务
  2. 启动定时器:
let timer = setInterval(任务函数,interval) //让引擎每隔interval ms自动执行一次任务函数

注意:interval是时间,单位是毫秒,其中timer是当前定时器任务的一个序号

  1. 停止定时器:
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.一次性定时器: 让程序先等待一段时间,再自动执行一次任务。( 执行一次后,自动停止)
  • 何时: 只要先等待一段时间,再执行一次任务
  • 用法: 同周期性定时器
  1. 任务函数:定义每次要执行的任务
  2. 启动定时器:
 let timer=setTimeout(task,wait); //wait是等待时间

注意:wait是时间,单位是毫秒,其中timer是当前定时器任务的一个序号

  1. 停止定时器:
 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>&nbsp;&nbsp;
  <a href="b.html">2</a>&nbsp;&nbsp;
  <a href="c.html">3</a>&nbsp;&nbsp;
</div><br/>
<div>
  <a href="javascript: history.go(-1)">后退一次</a>&nbsp;&nbsp;
  <a href="javascript: history.go(1)">前进一次</a>&nbsp;&nbsp;
  <a href="javascript: history.go(2)">前进二次</a>&nbsp;&nbsp;
</div>
//b.html
<div>
  <a href="a.html">1</a>&nbsp;&nbsp;
  <a href="b.html">2</a>&nbsp;&nbsp;
  <a href="c.html">3</a>&nbsp;&nbsp;
</div><br/>
<div>
  <a href="javascript: history.go(-2)">后退二次</a>&nbsp;&nbsp;
  <a href="javascript: history.go(-1)">后退一次</a>&nbsp;&nbsp;
  <a href="javascript: history.go(1)">前进一次</a>&nbsp;&nbsp;
  <a href="javascript: history.go(2)">前进二次</a>&nbsp;&nbsp;
</div>
//c.html
<div>
  <a href="a.html">1</a>&nbsp;&nbsp;
  <a href="b.html">2</a>&nbsp;&nbsp;
  <a href="c.html">3</a>&nbsp;&nbsp;
</div><br/>
<div>
  <a href="javascript: history.go(-2)">后退二次</a>&nbsp;&nbsp;
  <a href="javascript: history.go(-1)">后退一次</a>&nbsp;&nbsp;
  <a href="javascript: history.go(1)">前进一次</a>&nbsp;&nbsp;
</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>");
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,874评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,102评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,676评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,911评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,937评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,935评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,860评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,660评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,113评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,363评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,506评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,238评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,861评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,486评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,674评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,513评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,426评论 2 352

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,649评论 18 139
  • 曾经你是我的一生幸福 你是我生命的骄傲 那时候的我是多么的幸运 也是那么的快乐 只是因为有你的陪伴 容颜易老时光如...
    冬收阅读 202评论 0 0
  • 汉武通西域,安石献异榴。 燃山花五月,润脉果三秋。 妙物宜华夏,佳名盛峄州。 吾乡植万亩,海内可通邮! 张骞奉汉武...
    刀客特唬阅读 365评论 3 5
  • 打开QQ表列,点开那个人,进入空间只有一条说说,一张自拍并配上三个字“沧桑了”,看着他的那张极其丑陋但熟悉的面孔。...
    刘彦呈live阅读 2,386评论 1 0
  • 我原来其实对芬兰人没啥印象,因为我是自己都不知道对自己有啥印象的粗心大白羊。但是看了此文,我才真正有了印象,也对内...
    淡淡紫桐风阅读 447评论 0 2