zl程序教程

您现在的位置是:首页 >  后端

当前栏目

14前端学习之WebAPI(四):键盘事件、BOM基础(window,定时器, this,location,navigator,history)、JS执行机制

2023-09-27 14:29:29 时间

一、常用键盘事件:

1. 键盘事件:

键盘事件触发条件
onkeyup某个按键被松开时触发
onkeydown某个按年被按下时触发
onkeypress某个按键被按下时触发(不识别功能按键, 如:ctrl, shift,箭头等)

注意:

  • 如果使用addEventListener不需要加on;
  • onkeypress不识别功能按键, 如:ctrl, shift,箭头等;
  • 三个事件的执行顺序: keydown --> keypress --> keyup
<script>
    // 常用的键盘事件
    //1. keyup 按键弹起的时候触发 
    document.addEventListener('keyup', function() {
        console.log('我弹起了');
    })

    //3. keypress 按键按下的时候触发  不能识别功能键 比如 ctrl shift 左右箭头啊
    document.addEventListener('keypress', function() {
            console.log('我按下了press');
    })
    //2. keydown 按键按下的时候触发  能识别功能键 比如 ctrl shift 左右箭头啊
    document.addEventListener('keydown', function() {
            console.log('我按下了down');
    })
    // 4. 三个事件的执行顺序  keydown -- keypress -- keyup
</script>

2. 键盘事件对象:

键盘事件对象属性说明
keyCode返回该键的ASCII的值

注意:

  • onkeydown和onkeyup不区分字幕大小写, onkeypress区分字母大小写;
  • 在实际开发中, 更多的使用keydown和keyup, 它能识别所有的键(包括功能键);
  • keypress不识别功能键, 但是keyCode属性能区分大小写, 返回不同的ASCII值;

2.1 使用keyCode属性判断用户按下哪个键:

<script>
    // 键盘事件对象中的keyCode属性可以得到相应键的ASCII码值
    document.addEventListener('keyup', function(e) {
        console.log('up:' + e.keyCode);
        // 可以利用keycode返回的ASCII码值来判断用户按下了那个键
        if (e.keyCode === 65) {
            alert('您按下的a键');
        } else {
            alert('您没有按下a键')
        }
    })
    document.addEventListener('keypress', function(e) {
        // console.log(e);
        console.log('press:' + e.keyCode);
    })
</script>

3. 案例: 模拟京东按键输入内容:

当按下s键, 光标就定位到搜索框(文本框获得焦点)

3.1 案例分析:

  • 核心思路: 检测用户是否按下s键, 如果按下s键, 就把光标定位到搜索框里;
  • 使用键盘事件对象里面的keyCode判断用户按下的是否是s键;
  • 搜索框获得焦点,: 使用js里面的focus()方法;

3.2 实现:

<head>
    <title>京东按键</title>
    <script>
        window.onload = function() {
            var search = document.querySelector('input');
            document.addEventListener('keyup', function(e) {
                // 判断keyCode值
                if(e.keyCode === 83) {
                    search.focus();
                }
            })
        }
    </script>
</head>
<body>
    <input type="text">
</body>

4. 案例: 模拟京东快递单号查询

要求: 当在文本框输入内容是,文本框上边自动显示大字号的内容;
在这里插入图片描述

4.1 案例分析:

  • 快单号输入内容时, 上面的大字号字体盒子(con)显示这里面的文字;
  • 同时把快递单号里面的值(value)获取过来赋值给coon盒子(innerText)作为内容;
  • 如果快递单号里面内容为空, 则隐藏大号字体盒子(con)盒子;
  • 注意: keydown和keypress在文本里面的特点: 他们两个事件触发的时间, 文字还没有落入文本框中;
  • keyup事件触发的时候, 文字已经落入文本框里面了;
  • 当失去焦点, 就隐藏这个con盒子;
  • 当获得焦点, 并且文本框内容不为空, 就显示这个con盒子;

4.2 实现:

<head>
    <title>京东单号</title>
    <style>
        .con {
            font-size: 26px;
        }
    </style>
    <script>
        window.onload = function() {
            var con = document.querySelector('.con');
            var jd_input = document.querySelector('.jd');

            jd_input.addEventListener('keyup', function(e){
                if(this.value == ''){
                    // 为空, 隐藏放大盒子
                    con.style.display = 'none';
                } else {
                    // 不为空, 显示放大盒子
                    con.style.display = 'block';
                    con.innerHTML = this.value;
                }
            })
            // 给输入框注册失去焦点事件, 隐藏放大盒子
            jd_input.addEventListener('blur', function(e) {
                con.style.display = 'none';
            })

            // 给输入框注册获得焦点事件
            jd_input.addEventListener('focus', function(e) {
                // 判断输入框内容是否为空
                if(this.value !== '') {
                    con.style.display = 'block';
                }
            })
        }
    </script>
</head>
<body>
    <div class="search">
        <div class="con">123</div>
        <input type="text" name="" id=""placeholder="请输入您的快递单号" class="jd">
    </div> 
</body>

在这里插入图片描述

二、BOM:

1. 什么是BOM:

  • BOM(Browser Object Model)即浏览器对象模型,它提供了独立于内容而与浏览器窗口进行交互的对象,其核心对象是 window;
  • BOM 由一系列相关的对象构成,并且每个对象都提供了很多方法与属性;
  • BOM 缺乏标准,JavaScript 语法的标准化组织是 ECMA,DOM 的标准化组织是 W3C,BOM 最初是Netscape 浏览器标准的一部分;
    在这里插入图片描述

2. BOM的构成

BOM 比 DOM 更大, 它包含 DOM.
在这里插入图片描述

3. 顶级对象window

window对象是浏览器的顶级对象, 它具有双重角色:

  • 它是js访问浏览器窗口的一个接口;
  • 它是一个全局对象. 定义在全局作用域中的变量, 函数都会变成window对象的属性和方法;

在调用的时候可以省略window, 如:alert(), prompt()等.
注意:
window下的一个特殊属性window.name

4. window对象的常见事件:

4.1 页面(窗口)加载事件(2种):

第一种:

window.onload = function() {}
或者:
window.addEventListener("load", function() {});

window.onload 是窗口 (页面)加载事件, 当文档内容完全加载完成会触发该事件(包括图像、脚本文件、CSS 文件等), 就调用的处理函数

注意:

  • 有了window.onload就可以把JS代码写在只能写一次, 如果有多次, 会最后一个window.onlad为准;
  • 如果使用addEventListener则没有限制;

第二种:

document.addEventListener('DOMContentLoaded', function() { })
  • DOMContentLoaded 事件触发时,仅当DOM加载完成,不包括样式表,图片,flash等等;
  • IE9以上才支持!!!
  • 如果页面的图片很多的话, 从用户访问到onload触发可能需要较长的时间, 交互效果就不能实现,必然影响用户的体验,此时用 DOMContentLoaded 事件比较合适;
<head>
    <title>BOM加载</title>
    <script>
    	// 后加载
        window.addEventListener('load', function() {
            var btn = document.querySelector('button');
            btn.addEventListener('click', function() {
                alert('点击我');
            })
        })
        window.addEventListener('load', function() {
            alert(22);
        })
        document.addEventListener('DOMContentLoaded', function() {
            alert(33);
        })
    </script>
</head>
<body>
    <button>惦记我</button>
</body>

4.2 调整窗口大小事件:

window.onresize = function()
window.addEventListener('resize', function() {});

window.onresize 是调整窗口大小加载事件, 当触发时就调用的处理函数。

**注意: **

  • 只要窗口大小发生像素变化,就会触发这个事件。
  • 利用这个事件完成响应式布局; window.innerWidth 当前屏幕的宽度;
<head>
    <title>响应布局</title>
    <style>
        div {
            width: 300px;
            height: 300px;
            background-color: pink;
        }
    </style>
    <script>
        window.onload = function() {
            var div = document.querySelector('div');
            window.addEventListener('resize', function() {
                console.log("当前宽度:" + window.innerWidth + ", 高度:" + window.innerHeight);
                if(window.innerWidth <= 800) {
                    div.style.display = 'none';
                } else {
                    div.style.display = 'block';
                }
            })
        }
    </script>
</head>
<body>
    <div></div>
</body>

在这里插入图片描述

5. 定时器(两种):

window 对象给提供了 2 个非常好用的方法-定时器。

  • setTimeout()
  • setInterval()

5.1 setTimeout() 炸弹定时器

开启定时器

window.setTimeout(调用函数 [, 延迟的毫秒数])

setTimeout()这个调用函数称之为回调函数callback
注意:

  • window可以省略;
  • 这个调用函数可以直接写函数, 函数名或者**采取字符串’函数名()’**三种形式; 第三种不推荐;
  • 延迟的毫秒数省略默认是0, 如果写,必须写毫秒;
  • 因为定时器可能很多, 所以经常会给定时器赋值一个标识;
普通函数是按照代码顺序直接调用;

简单理解: 回调,就是回头调用的意思; 上一件事干完,再回头再调用这个函数;
例如: 定时器中的调用函数,事件处理函数,也是回调函数;

element.onclick = function(){}   或者  element.addEventListener(“click”, fn) ; 里面的 函数也是回调函数;
<head>
    <title>定时器</title>

    <script>
        // 回调函数是一个匿名函数
        setTimeout(function() {
            console.log('时间到...')
        }, 2000)

        function callback() {
            console.log('callback...')
        }
        var timer1 = setTimeout(callback, 4000);
        var timer2 = setTimeout(callback, 5000);
    </script>
</head>
<body>
    
</body>

在这里插入图片描述

5.1.1 案例: 5秒钟后关闭广告

在这里插入图片描述
案例分析:

  • 核心思路: 5秒之后, 就把广告隐藏起来;
  • 用定时器setTimeout

实现:

<head>
    <title>5秒关闭广告</title>
    <script>
        window.onload = function() {
            var ad = document.querySelector('.ad');
            // 开启定时器
            setTimeout(function() {
                ad.style.display = 'none';
            }, 5000)
        }

    </script>
</head>
<body>
    <img src="./images/AD.png" class = 'ad'  alt="">
</body>

5.1.2 停止定时器:

window.clearTimeout(timeoutID)

window.clearTimeout()方法取消了先前通过调用setTimeout()建立的定时器

注意:

  • window可以省略;
  • 里面的参数就是定时器的标志符;
<head>
    <title>Document</title>
</head>
<body>
    <button>点击停止定时器</button>
    <script>
        var btn = document.querySelector('button');
		// 开启定时器
        var timer = setTimeout(function() {
            console.log('爆炸了');
        }, 5000);
		// 给按钮注册单击事件
        btn.addEventListener('click', function() {
            // 停止定时器
            clearTimeout(timer);
        })
    </script>
</body>

5.2 setInterval() 闹钟定时器:

开启定时器

window.setInterval(回调函数 [, 间隔毫秒数])

window.setInterval()方法重复调用一个函数, 每隔一段时间, 就去调用一个回调函数

注意:

  • window可以省略;
  • 这个调用函数可以直接写函数, 或者写函数名, 或者采取字符串’函数名()’ 三种形式;
  • 间隔的毫秒数省略默认是0, 如果写, 必须是毫秒, 表示每隔多少毫秒就自动调用这个函数;
  • 因为定时器可能有很多, 所以经常给定时器赋值一个标识符;
  • 第一次执行也就是间隔毫秒数之后执行, 之后每隔毫秒数执行一次;
<head>
    <title>循环定时器</title>
    <script>
        // 1. setInterval 
        setInterval(function() {
            console.log('继续输出');
        }, 1000);
    </script>
</head>

5.2.2 案例:倒计时

在这里插入图片描述

案例分析

  • 这个倒计时是不断变化的, 因此需要定时器来自动变化(setInterval);
  • 三个黑色盒子里面分别存放时分秒;
  • 三个黑色盒子利用innerHTML放入计算的小时分钟秒数;
  • 第一次执行也是间隔毫秒数, 因此刚刷新的页面会有空白;
  • 最好采用封装函数的方式, 这样可以先调用一次这个函数, 防止刚开始刷洗页面的空白页面;

实现:

<head>
    <title>京东秒杀</title>
    <script>
        window.onload = function() {
            var hour = document.querySelector('.hour')
            var minute = document.querySelector('.minute')
            var second = document.querySelector('.second')
            var inputTime = +new Date('2020-5-1 18:00:00'); // 返回的是用户输入时间总的毫秒数
            // 定义函数
            function countDown() {
                var nowTime = +new Date(); // 返回的是当前时间总的毫秒数
                var times = (inputTime - nowTime) / 1000; // times是剩余时间总的秒数 
                var h = parseInt(times / 60 / 60); //时
                h = h < 10 ? '0' + h : h;
                hour.innerHTML = h; // 把剩余的小时给 小时黑色盒子
                var m = parseInt(times / 60 % 60); // 分
                m = m < 10 ? '0' + m : m;
                minute.innerHTML = m;
                var s = parseInt(times % 60); // 当前的秒
                s = s < 10 ? '0' + s : s;
                second.innerHTML = s;
            }
            
            // 防止页面刷新有空白
            countDown();
            // 开启定时器
            setInterval(countDown, 1000);

        }

    </script>
</head>
<body>
    <div>
        <p>距离2020-05-02 18:00:00 还有</p>
        <span class="hour">1</span>:
        <span class="minute">2</span>:
        <span class="second">3</span>
    </div>
</body>

在这里插入图片描述

5.2.2 停止定时器:

window.clearInterval(IntervalID)

clearInterval()方法取消了先前通过调用setInterval()建立的定时器;
注意:

  • window可以省略;
  • 里面的参数就是定时器的标志符;

5.2.3 案例:发送短信倒计时:

在这里插入图片描述
点击按钮后,该按钮60秒之内不能再次点击,防止重复发送短信

案例分析:

  • 按钮点击之后, 会禁用disable为true;
  • 同事按钮里面的内容会变化, 注意button里面的内容通过innerHTML修改;
  • 里面秒数是会变化的, 因此需要用到定时器;
  • 定义一个变量, 在定时器里面, 不断递减;
  • 如果变量为0, 说明时间到了, 需要停止定时器, 并且复原按钮初始状态;

实现:

<head>
    <title>短信倒计时</title>
    <script>
        window.onload = function() {
            var tel = document.querySelector('.tel');
        var btn = document.querySelector('button')
        var time = 180; // 倒计时的秒数

            // 注册点击事件
            btn.addEventListener('click', function() {
                // 禁用按钮
                this.disabled = true;
                //开启定时器
                var timer = setInterval(function() {
                    if(time == 0){
                        // 清除定时器
                        clearInterval(timer);
                        this.disabled = false;
                        this.innerHTML = "发送短信";
                    } else {
                        btn.innerHTML = "还有"+ time + '秒';
                        time --;
                    }
                }, 1000)
            })
        }
    </script>
</head>
<body>
    手机号: <input type="tel" name="" id="" class="tel">
    <button>发送短信</button>
</body>

6. this指向问题:

this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,一般情况下this的最终指向的是那个调用它的对象.

  • 全局作用域或者普通函数中this指向全局对象window(注意定时器里面的this指向window)
  • 方法调用中谁调用this指向谁;
  • 构造函数中this指向构造函数的实例;
<button>点击</button>
<script>
     // this 指向问题 一般情况下this的最终指向的是那个调用它的对象
     // 1. 全局作用域或者普通函数中this指向全局对象window( 注意定时器里面的this指向window)
     console.log(this);
     function fn() {
         console.log(this);
     }
     window.fn();
     window.setTimeout(function() {
         console.log(this);
     }, 1000);
     // 2. 方法调用中谁调用this指向谁
     var o = {
         sayHi: function() {
             console.log(this); // this指向的是 o 这个对象
         }
     }
     o.sayHi();
     var btn = document.querySelector('button');
     btn.addEventListener('click', function() {
             console.log(this); // 事件处理函数中的this指向的是btn这个按钮对象
         })
     // 3. 构造函数中this指向构造函数的实例
     function Fun() {
         console.log(this); // this 指向的是fun 实例对象
     }
     var fun = new Fun();
 </script>

在这里插入图片描述

7. location对象:

7.1 什么是location对象:

window对象给提供了一个location属性用于获取或设置窗体的url, 并且可以用于解析url. 因为设个属性返回的是一个对象, 所以这个属性也被称之为location对象

7.2 URL:

**统一资源定位符(Uniform Resource Locator, URL)**是互联网上标准资源的地址. 互联网上每个文件都有唯一的一个URL, 它包含的信息支出文件的位置以及浏览器应该如何处理它
url一般的语法格式为:


protool:/host[:port]/path/[?query] # fragment
http://www.baidu.com/index?name=andy&age=18#link
组成说明
protool通讯协议(常用的http, https,ftp,maito等)
host主机名(域名, ip)www.baidu.com
port端口号(可选),省略时使用协议默认端口号, 如;http: 80; https:443
path路径, 由零或多个’/'符号隔开的字符串, 一般表示主机上的一个目录或文件地址
query参数, 以键值对的形式, 通过&符号链接
fragment片段 #后面内容, 常见于链接、锚点

7.3 location对象属性:

location对象属性返回值
location.href获取或者设置页面的url
location.host返回主机名(域名)
location.port返回端口号, 如果没有写, 返回空字符串
location.pathname返回路径
location.search返回参数
location.hash返回片段 #内容

7.4 案例: 5s后自动跳转页面

案例分析:

  • 利用定时器做倒计时效果;
  • 时间到了, 就跳转页面, 使用location.href
    实现:
<head>
    <title>跳转页面</title>
    <script>
        window.onload = function() {
            var btn = document.querySelector('button');
            var div = document.querySelector('div');
            var time = 5; // 5秒

            // 注册事件
            btn.addEventListener('click', function() {
            	this.disabled = true;
                setInterval(function() {
                    if(time == 0) {
                        location.href = 'http://www.baidu.com'
                    } else {
                        div.innerHTML = time +"秒后跳转页面"
                        time --;
                    }
                }, 1000)
            });
        }
    </script>
</head>
<body>
    <button>倒计时跳转</button>
    <div></div>
</body>

在这里插入图片描述

7.5 location对象常见方法:

location对象方法返回值
location.assign()跟href一样, 可以跳转页面(也称重定向页面)
location.replace()替换当前页面, 因为不记录历史, 所以不能后退页面
location.reload()重新加载页面, 相当于刷新按钮, 如果参数为true, 则强制刷新
<button>assign</button>
<button>replace</button>
<button>reload</button>
<script>
    var btns = document.querySelectorAll('button');
	btn[0].addEventListener('click', function() {
        // 记录浏览历史,所以可以实现后退功能
        location.assign('http://www.baidu.com');
    })
    btn[1].addEventListener('click', function() {
        // 不记录浏览历史,所以不可以实现后退功能
        location.replace('http://www.baidu.com');
    })
    btn[2].addEventListener('click', function() {
        // 刷新页面
        location.reload(true);
    })
</script>

8. navigator对象:

navigator 对象包含有关浏览器的信息,它有很多属性,最常用的是 userAgent,该属性可以返回由客户机发送服务器的 user-agent 头部的值。

下面前端代码可以判断用户那个终端打开页面,实现跳转

if((navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i))) {
    window.location.href = "";     //手机
 } else {
    window.location.href = "";     //电脑
 }

9 history对象

​ window对象给提供了一个 history对象,与浏览器历史记录进行交互。该对象包含用户(在浏览器窗口中)访问过的URL

history()对象方法作用
history.back()可以后退功能
history.fowward()前进功能
history.go(参数)前进/后退功能, 参数1, 前进1个页面; 参数-1, 后退一个页面

history对象一般在实际开发中比较少用,但是会在一些 OA 办公系统中见到

三、JS执行机制:

以下代码执行的结果是什么?

 console.log(1);
 
 setTimeout(function () {
     console.log(3);
 }, 1000);
 
 console.log(2);

以下代码执行的结果是什么?

 console.log(1);
 
 setTimeout(function () {
     console.log(3);
 }, 0);
 
 console.log(2);

1. JS 是单线程:

JavaScript语言的一大特点就是单线程, 也就是说, 同一时间只能做一件事. 这是因为JavaScript这门脚本语言诞生的使用所致----JavaScript是为了处理页面中用户交互, 以及操作DOM而诞生的.
单线程就意味着, 所有任务需要排队, 前一个任务结束, 才会执行后一个任务. 如果前一个任务耗时, 后一个任务就不得不等待.
这样导致的问题是: 如果JS执行时间过长, 这样就会造成页面渲染不连贯, 造成页面渲染加载阻塞的感觉.

2 同步任务和异步任务:

单线程导致的问题就是后面的任务等待前面任务完成,如果前面任务很耗时(比如读取网络数据), 后面任务不得不一直等待

为了解决这个问题,利用多核 CPU 的计算能力,HTML5 提出 Web Worker 标准,允许 JavaScript 脚本创建多个线程,但是子线程完全受主线程控制。于是,JS 中出现了同步任务和异步任务

同步
前一个任务结束后再执行后一个任务,程序的执行顺序与任务的排列顺序是一致的、同步的。比如做饭的同步做法:要烧水煮饭,等水开了(10分钟之后),再去切菜,炒菜。

异步
​ 你在做一件事情时,因为这件事情会花费很长时间,在做这件事的同时,你还可以去处理其他事情。比如做饭的异步做法,在烧水的同时,利用这10分钟,去切菜,炒菜

他们本质区别: 这条流水线上各个流程的执行顺序不同;

JS中所有任务可以分成两种,一种是同步任务(synchronous),另一种是异步任务(asynchronous)。

同步任务指的是:
	在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;
异步任务指的是:
	不进入主线程、而进入”任务队列”的任务,当主线程中的任务运行完了,才会从”任务队列”取出异步任务放入主线程执行。

在这里插入图片描述

3. JS执行机制(事件循环)

  • 先执行执行栈中的同步任务;
  • 异步任务(回调函数)放入任务队列中;
  • 一旦执行栈中的所有同步任务执行完毕, 系统就会按次序读取任务对列中的异步任务, 于是被读取的异步任务结束登台状态, 进去执行栈, 开始执行;

在这里插入图片描述

由于主线程不断的重复获得任务,、执行任务、再获取任务、在执行, 所以这种机制被称为事件循环(event loop)