WebAPI编程(第三天,第四天)

WebAPI编程(第三天,第四天)

  • [day03 - Web APIs](#day03 - Web APIs)
    • [1.1. 节点操作](#1.1. 节点操作)
      • [1.1.1 删除节点](#1.1.1 删除节点)
      • [1.1.2 案例:删除留言](#1.1.2 案例:删除留言)
      • [1.1.3 复制(克隆)节点](#1.1.3 复制(克隆)节点)
      • [1.1.4 案例:动态生成表格](#1.1.4 案例:动态生成表格)
      • [1.1.5 创建元素的三种方式](#1.1.5 创建元素的三种方式)
      • [1.1.6 innerTHML和createElement效率对比](#1.1.6 innerTHML和createElement效率对比)
    • [1.2. DOM的核心总结](#1.2. DOM的核心总结)
      • [1.2.1. 创建](#1.2.1. 创建)
      • [1.2.2. 增加](#1.2.2. 增加)
      • [1.2.3. 删](#1.2.3. 删)
      • [1.2.4. 改](#1.2.4. 改)
      • [1.2.5. 查](#1.2.5. 查)
      • [1.2.6. 属性操作](#1.2.6. 属性操作)
      • [1.2.7. 事件操作(重点)](#1.2.7. 事件操作(重点))
    • [1.3. 事件高级](#1.3. 事件高级)
    • [1.4. 常用鼠标事件](#1.4. 常用鼠标事件)
      • [1.4.1 案例:禁止选中文字和禁止右键菜单](#1.4.1 案例:禁止选中文字和禁止右键菜单)
      • [1.4.2 鼠标事件对象](#1.4.2 鼠标事件对象)
      • [1.4.3 获取鼠标在页面的坐标](#1.4.3 获取鼠标在页面的坐标)
      • [1.4.4 案例:跟随鼠标的天使](#1.4.4 案例:跟随鼠标的天使)
  • [day04 - Web APIs](#day04 - Web APIs)
    • [1.1. 常用的键盘事件](#1.1. 常用的键盘事件)
      • [1.1.1 键盘事件](#1.1.1 键盘事件)
      • [1.1.2 键盘事件对象](#1.1.2 键盘事件对象)
      • [1.1.3 案例:模拟京东按键输入内容](#1.1.3 案例:模拟京东按键输入内容)
      • [1.1.4 案例:模拟京东快递单号查询](#1.1.4 案例:模拟京东快递单号查询)
    • [1.2. BOM](#1.2. BOM)
    • [1.3. JS执行机制](#1.3. JS执行机制)
      • [1.3.1 JS 是单线程](#1.3.1 JS 是单线程)
      • [1.3.2 同步任务和异步任务](#1.3.2 同步任务和异步任务)
      • [1.3.3 JS执行机制(事件循环)](#1.3.3 JS执行机制(事件循环))
      • [1.3.4 代码思考题](#1.3.4 代码思考题)

day03 - Web APIs

学习目标:

能够使用removeChild()方法删除节点

能够完成动态生成表格案例

能够使用传统方式和监听方式给元素注册事件

能够说出事件流执行的三个阶段

能够在事件处理函数中获取事件对象

能够使用事件对象取消默认行为

能够使用事件对象阻止事件冒泡

能够使用事件对象获取鼠标的位置

能够完成跟随鼠标的天使案例

1.1. 节点操作

1.1.1 删除节点

node.removeChild() 方法从 node节点中删除一个子节点,返回删除的节点。

js 复制代码
    <button>删除</button>
    <ul>
        <li>熊大</li>
        <li>熊二</li>
        <li>光头强</li>
    </ul>
    <script>
        // 1.获取元素
        var ul = document.querySelector('ul');
        var btn = document.querySelector('button');
        // 2. 删除元素  node.removeChild(child)
        // ul.removeChild(ul.children[0]);
        // 3. 点击按钮依次删除里面的孩子
        btn.onclick = function() {
            if (ul.children.length == 0) {
                this.disabled = true;
            } else {
                ul.removeChild(ul.children[0]);
            }
        }
    </script>

1.1.2 案例:删除留言

js 复制代码
    <textarea name="" id=""></textarea>
    <button>发布</button>
    <ul>

    </ul>
    <script>
        // 1. 获取元素
        var btn = document.querySelector('button');
        var text = document.querySelector('textarea');
        var ul = document.querySelector('ul');
        // 2. 注册事件
        btn.onclick = function() {
            if (text.value == '') {
                alert('您没有输入内容');
                return false;
            } else {
                // console.log(text.value);
                // (1) 创建元素
                var li = document.createElement('li');
                // 先有li 才能赋值
                li.innerHTML = text.value + "<a href='javascript:;'>删除</a>";
                // (2) 添加元素
                // ul.appendChild(li);
                ul.insertBefore(li, ul.children[0]);
                // (3) 删除元素 删除的是当前链接的li  它的父亲
                var as = document.querySelectorAll('a');
                for (var i = 0; i < as.length; i++) {
                    as[i].onclick = function() {
                        // 删除的是 li 当前a所在的li  this.parentNode;
                        ul.removeChild(this.parentNode);
                    }
                }
            }
        }
    </script>

1.1.3 复制(克隆)节点

js 复制代码
    <ul>
        <li>1111</li>
        <li>2</li>
        <li>3</li>
    </ul>
    <script>
        var ul = document.querySelector('ul');
        // 1. node.cloneNode(); 括号为空或者里面是false 浅拷贝 只复制标签不复制里面的内容
        // 2. node.cloneNode(true); 括号为true 深拷贝 复制标签复制里面的内容
        var lili = ul.children[0].cloneNode(true);
        ul.appendChild(lili);
    </script>

1.1.4 案例:动态生成表格

js 复制代码
    <script>
        // 1.先去准备好学生的数据
        var datas = [{
            name: '魏璎珞',
            subject: 'JavaScript',
            score: 100
        }, {
            name: '弘历',
            subject: 'JavaScript',
            score: 98
        }, {
            name: '傅恒',
            subject: 'JavaScript',
            score: 99
        }, {
            name: '明玉',
            subject: 'JavaScript',
            score: 88
        }, {
            name: '大猪蹄子',
            subject: 'JavaScript',
            score: 0
        }];
        // 2. 往tbody 里面创建行: 有几个人(通过数组的长度)我们就创建几行
        var tbody = document.querySelector('tbody');
		// 遍历数组
        for (var i = 0; i < datas.length; i++) { 
            // 1. 创建 tr行
            var tr = document.createElement('tr');
            tbody.appendChild(tr);
            // 2. 行里面创建单元格td 单元格的数量取决于每个对象里面的属性个数  
            // 使用for in遍历学生对象
            for (var k in datas[i]) { 
                // 创建单元格 
                var td = document.createElement('td');
                // 把对象里面的属性值 datas[i][k] 给 td  
                td.innerHTML = datas[i][k];
                tr.appendChild(td);
            }
            // 3. 创建有删除2个字的单元格 
            var td = document.createElement('td');
            td.innerHTML = '<a href="javascript:;">删除 </a>';
            tr.appendChild(td);

        }
        // 4. 删除操作 开始 
        var as = document.querySelectorAll('a');
        for (var i = 0; i < as.length; i++) {
            as[i].onclick = function() {
                // 点击a 删除 当前a 所在的行(链接的爸爸的爸爸)  node.removeChild(child)  
                tbody.removeChild(this.parentNode.parentNode)
            }
        }
    </script>

1.1.5 创建元素的三种方式

js 复制代码
    <script>
        // 三种创建元素方式区别 
        // 1. document.write() 创建元素  如果页面文档流加载完毕,再调用这句话会导致页面重绘
         var btn = document.querySelector('button');
         btn.onclick = function() {
             document.write('<div>123</div>');
         }

        // 2. innerHTML 创建元素
        var inner = document.querySelector('.inner');
         for (var i = 0; i <= 100; i++) {
             inner.innerHTML += '<a href="#">百度</a>'
         }
        var arr = [];
        for (var i = 0; i <= 100; i++) {
            arr.push('<a href="#">百度</a>');
        }
        inner.innerHTML = arr.join('');
        // 3. document.createElement() 创建元素
        var create = document.querySelector('.create');
        for (var i = 0; i <= 100; i++) {
            var a = document.createElement('a');
            create.appendChild(a);
        }
    </script>

1.1.6 innerTHML和createElement效率对比

innerHTML字符串拼接方式(效率低)

js 复制代码
<script>
    function fn() {
        var d1 = +new Date();
        var str = '';
        for (var i = 0; i < 1000; i++) {
            document.body.innerHTML += '<div style="width:100px; height:2px; border:1px solid blue;"></div>';
        }
        var d2 = +new Date();
        console.log(d2 - d1);
    }
    fn();
</script>

createElement方式(效率一般)

js 复制代码
<script>
    function fn() {
        var d1 = +new Date();

        for (var i = 0; i < 1000; i++) {
            var div = document.createElement('div');
            div.style.width = '100px';
            div.style.height = '2px';
            div.style.border = '1px solid red';
            document.body.appendChild(div);
        }
        var d2 = +new Date();
        console.log(d2 - d1);
    }
    fn();
</script>

innerHTML数组方式(效率高)

js 复制代码
<script>
    function fn() {
        var d1 = +new Date();
        var array = [];
        for (var i = 0; i < 1000; i++) {
            array.push('<div style="width:100px; height:2px; border:1px solid blue;"></div>');
        }
        document.body.innerHTML = array.join('');
        var d2 = +new Date();
        console.log(d2 - d1);
    }
    fn();
</script>

1.2. DOM的核心总结

关于dom操作,我们主要针对于元素的操作。主要有创建、增、删、改、查、属性操作、事件操作。

1.2.1. 创建

1.2.2. 增加

1.2.3. 删

1.2.4. 改

1.2.5. 查

1.2.6. 属性操作

1.2.7. 事件操作(重点)

1.3. 事件高级

1.3.1. 注册事件(2种方式)

1.3.2 事件监听

addEventListener()事件监听(IE9以后支持)

eventTarget.addEventListener()方法将指定的监听器注册到 eventTarget(目标对象)上,当该对象触发指定的事件时,就会执行事件处理函数。

attacheEvent()事件监听(IE678支持)

​ eventTarget.attachEvent()方法将指定的监听器注册到 eventTarget(目标对象) 上,当该对象触发指定的事件时,指定的回调函数就会被执行。

js 复制代码
<button>传统注册事件</button>
<button>方法监听注册事件</button>
<button>ie9 attachEvent</button>
<script>
    var btns = document.querySelectorAll('button');
    // 1. 传统方式注册事件
    btns[0].onclick = function() {
        alert('hi');
    }
    btns[0].onclick = function() {
            alert('hao a u');
        }
   // 2. 事件侦听注册事件 addEventListener 
   // (1) 里面的事件类型是字符串 必定加引号 而且不带on
   // (2) 同一个元素 同一个事件可以添加多个侦听器(事件处理程序)
    btns[1].addEventListener('click', function() {
        alert(22);
    })
    btns[1].addEventListener('click', function() {
            alert(33);
    })
    // 3. attachEvent ie9以前的版本支持
    btns[2].attachEvent('onclick', function() {
        alert(11);
    })
</script>
事件监听兼容性解决方案

封装一个函数,函数中判断浏览器的类型:

1.3.3. 删除事件(解绑事件)

js 复制代码
    <div>1</div>
    <div>2</div>
    <div>3</div>
    <script>
        var divs = document.querySelectorAll('div');
        divs[0].onclick = function() {
            alert(11);
            // 1. 传统方式删除事件
            divs[0].onclick = null;
        }
        // 2. removeEventListener 删除事件
        divs[1].addEventListener('click', fn) // 里面的fn 不需要调用加小括号
        function fn() {
            alert(22);
            divs[1].removeEventListener('click', fn);
        }
        // 3. detachEvent
        divs[2].attachEvent('onclick', fn1);

        function fn1() {
            alert(33);
            divs[2].detachEvent('onclick', fn1);
        }
    </script>

1.3.4. DOM事件流

复制代码
html中的标签都是相互嵌套的,我们可以将元素想象成一个盒子装一个盒子,document是最外面的大盒子。
当你单击一个div时,同时你也单击了div的父元素,甚至整个页面。

那么是先执行父元素的单击事件,还是先执行div的单击事件 ???

比如:我们给页面中的一个div注册了单击事件,当你单击了div时,也就单击了body,单击了html,单击了document。

复制代码
当时的2大浏览器霸主谁也不服谁!
IE 提出从目标元素开始,然后一层一层向外接收事件并响应,也就是冒泡型事件流。
Netscape(网景公司)提出从最外层开始,然后一层一层向内接收事件并响应,也就是捕获型事件流。

江湖纷争,武林盟主也脑壳疼!!!

最终,w3c 采用折中的方式,平息了战火,制定了统一的标准 -------- 先捕获再冒泡。
现代浏览器都遵循了此标准,所以当事件发生时,会经历3个阶段。

DOM 事件流会经历3个阶段:

  1. 捕获阶段

  2. 当前目标阶段

  3. 冒泡阶段

​ 我们向水里面扔一块石头,首先它会有一个下降的过程,这个过程就可以理解为从最顶层向事件发生的最具体元素(目标点)的捕获过程;之后会产生泡泡,会在最低点( 最具体元素)之后漂浮到水面上,这个过程相当于事件冒泡。

事件冒泡

js 复制代码
    <div class="father">
        <div class="son">son盒子</div>
    </div>
    <script>
        // onclick 和 attachEvent(ie) 在冒泡阶段触发
        // 冒泡阶段 如果addEventListener 第三个参数是 false 或者 省略 
        // son -> father ->body -> html -> document
        var son = document.querySelector('.son');
		// 给son注册单击事件
        son.addEventListener('click', function() {
            alert('son');
        }, false);
		// 给father注册单击事件
        var father = document.querySelector('.father');
        father.addEventListener('click', function() {
            alert('father');
        }, false);
		// 给document注册单击事件,省略第3个参数
        document.addEventListener('click', function() {
            alert('document');
        })
    </script>

事件捕获

js 复制代码
    <div class="father">
        <div class="son">son盒子</div>
    </div>
    <script>
        // 如果addEventListener() 第三个参数是 true 那么在捕获阶段触发
        // document -> html -> body -> father -> son
         var son = document.querySelector('.son');
		// 给son注册单击事件,第3个参数为true
         son.addEventListener('click', function() {
             alert('son');
         }, true);
         var father = document.querySelector('.father');
		// 给father注册单击事件,第3个参数为true
         father.addEventListener('click', function() {
             alert('father');
         }, true);
		// 给document注册单击事件,第3个参数为true
        document.addEventListener('click', function() {
            alert('document');
        }, true)
    </script>

1.3.5. 事件对象

什么是事件对象

事件发生后,跟事件相关的一系列信息数据的集合都放到这个对象里面,这个对象就是事件对象。

比如:

  1. 谁绑定了这个事件。

  2. 鼠标触发事件的话,会得到鼠标的相关信息,如鼠标位置。

  3. 键盘触发事件的话,会得到键盘的相关信息,如按了哪个键。


javascript 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        div {
            width: 100px;
            height: 100px;
            background-color: pink;
        }
    </style>
</head>

<body>
    <div>123</div>
    <script>
        // 事件对象
        var div = document.querySelector('div');
        div.onclick = function(e) {
                // console.log(e);
                // console.log(window.event);
                // e = e || window.event;
                console.log(e);


            }
            // div.addEventListener('click', function(e) {
            //         console.log(e);

        //     })
        // 1. event 就是一个事件对象 写到我们侦听函数的 小括号里面 当形参来看
        // 2. 事件对象只有有了事件才会存在,它是系统给我们自动创建的,不需要我们传递参数
        // 3. 事件对象 是 我们事件的一系列相关数据的集合 跟事件相关的 比如鼠标点击里面就包含了鼠标的相关信息,鼠标坐标啊,如果是键盘事件里面就包含的键盘事件的信息 比如 判断用户按下了那个键
        // 4. 这个事件对象我们可以自己命名 比如 event 、 evt、 e
        // 5. 事件对象也有兼容性问题 ie678 通过 window.event 兼容性的写法  e = e || window.event;
    </script>
</body>

</html>
事件对象的使用

事件触发发生时就会产生事件对象,并且系统会以实参的形式传给事件处理函数。

所以,在事件处理函数中声明1个形参用来接收事件对象。

事件对象的兼容性处理

事件对象本身的获取存在兼容问题:

  1. 标准浏览器中是浏览器给方法传递的参数,只需要定义形参 e 就可以获取到。

  2. 在 IE6~8 中,浏览器不会给方法传递参数,如果需要的话,需要到 window.event 中获取查找。

复制代码
只要"||"前面为false, 不管"||"后面是true 还是 false,都返回 "||" 后面的值。
只要"||"前面为true, 不管"||"后面是true 还是 false,都返回 "||" 前面的值。
js 复制代码
    <div>123</div>
    <script>
        var div = document.querySelector('div');
        div.onclick = function(e) {
                // 事件对象
                e = e || window.event;
                console.log(e);
        }
    </script>
事件对象的属性和方法
e.target 和 this 的区别
  • this 是事件绑定的元素(绑定这个事件处理函数的元素) 。

  • e.target 是事件触发的元素。

复制代码
常情况下terget 和 this是一致的,
但有一种情况不同,那就是在事件冒泡时(父子元素有相同事件,单击子元素,父元素的事件处理函数也会被触发执行),
	这时候this指向的是父元素,因为它是绑定事件的元素对象,
	而target指向的是子元素,因为他是触发事件的那个具体元素对象。
js 复制代码
    <div>123</div>
    <script>
        var div = document.querySelector('div');
        div.addEventListener('click', function(e) {
            // e.target 和 this指向的都是div
            console.log(e.target);
            console.log(this);

        });
    </script>

事件冒泡下的e.target和this

js 复制代码
    <ul>
        <li>abc</li>
        <li>abc</li>
        <li>abc</li>
    </ul>
    <script>
        var ul = document.querySelector('ul');
        ul.addEventListener('click', function(e) {
              // 我们给ul 绑定了事件  那么this 就指向ul  
              console.log(this); // ul

              // e.target 触发了事件的对象 我们点击的是li e.target 指向的就是li
              console.log(e.target); // li
        });
    </script>
javascript 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        div {
            width: 100px;
            height: 100px;
            background-color: pink;
        }
    </style>
</head>

<body>
    <div>123</div>
    <ul>
        <li>abc</li>
        <li>abc</li>
        <li>abc</li>
    </ul>
    <script>
        // 常见事件对象的属性和方法
        // 1. e.target 返回的是触发事件的对象(元素)  this 返回的是绑定事件的对象(元素)
        // 区别 : e.target 点击了那个元素,就返回那个元素 this 那个元素绑定了这个点击事件,那么就返回谁
        var div = document.querySelector('div');
        div.addEventListener('click', function(e) {
            console.log(e.target);
            console.log(this);

        })
        var ul = document.querySelector('ul');
        ul.addEventListener('click', function(e) {
                // 我们给ul 绑定了事件  那么this 就指向ul  
                console.log(this);
                console.log(e.currentTarget);

                // e.target 指向我们点击的那个对象 谁触发了这个事件 我们点击的是li e.target 指向的就是li
                console.log(e.target);

            })
            // 了解兼容性
            // div.onclick = function(e) {
            //     e = e || window.event;
            //     var target = e.target || e.srcElement;
            //     console.log(target);

        // }
        // 2. 了解 跟 this 有个非常相似的属性 currentTarget  ie678不认识
    </script>
</body>

</html>

1.3.6 阻止默认行为

html中一些标签有默认行为,例如a标签被单击后,默认会进行页面跳转。

js 复制代码
    <a href="http://www.baidu.com">百度</a>
    <script>
        // 2. 阻止默认行为 让链接不跳转 
        var a = document.querySelector('a');
        a.addEventListener('click', function(e) {
             e.preventDefault(); //  dom 标准写法
        });
        // 3. 传统的注册方式
        a.onclick = function(e) {
            // 普通浏览器 e.preventDefault();  方法
            e.preventDefault();
            // 低版本浏览器 ie678  returnValue  属性
            e.returnValue = false;
            // 我们可以利用return false 也能阻止默认行为 没有兼容性问题
            return false;
        }
    </script>

1.3.7 阻止事件冒泡

事件冒泡本身的特性,会带来的坏处,也会带来的好处。

js 复制代码
    <div class="father">
        <div class="son">son儿子</div>
    </div>
    <script>
        var son = document.querySelector('.son');
		// 给son注册单击事件
        son.addEventListener('click', function(e) {
            alert('son');
            e.stopPropagation(); // stop 停止  Propagation 传播
            window.event.cancelBubble = true; // 非标准 cancel 取消 bubble 泡泡
        }, false);

        var father = document.querySelector('.father');
		// 给father注册单击事件
        father.addEventListener('click', function() {
            alert('father');
        }, false);
		// 给document注册单击事件
        document.addEventListener('click', function() {
            alert('document');
        })
    </script>

阻止事件冒泡的兼容性处理

1.3.8 事件委托

事件冒泡本身的特性,会带来的坏处,也会带来的好处。

什么是事件委托
复制代码
把事情委托给别人,代为处理。

事件委托也称为事件代理,在 jQuery 里面称为事件委派。

说白了就是,不给子元素注册事件,给父元素注册事件,把处理代码在父元素的事件中执行。

事件委托的原理

​ 给父元素注册事件,利用事件冒泡,当子元素的事件触发,会冒泡到父元素,然后去控制相应的子元素。

事件委托的作用
  • 我们只操作了一次 DOM ,提高了程序的性能。

  • 动态新创建的子元素,也拥有事件。

js 复制代码
    <ul>
        <li>知否知否,点我应有弹框在手!</li>
        <li>知否知否,点我应有弹框在手!</li>
        <li>知否知否,点我应有弹框在手!</li>
        <li>知否知否,点我应有弹框在手!</li>
        <li>知否知否,点我应有弹框在手!</li>
    </ul>
    <script>
        // 事件委托的核心原理:给父节点添加侦听器, 利用事件冒泡影响每一个子节点
        var ul = document.querySelector('ul');
        ul.addEventListener('click', function(e) {
            // e.target 这个可以得到我们点击的对象
            e.target.style.backgroundColor = 'pink';
        })
    </script>

1.4. 常用鼠标事件

javascript 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    我是一段不愿意分享的文字
    <script>
        // 1. contextmenu 我们可以禁用右键菜单
        document.addEventListener('contextmenu', function(e) {
                e.preventDefault();
            })
            // 2. 禁止选中文字 selectstart
        document.addEventListener('selectstart', function(e) {
            e.preventDefault();

        })
    </script>
</body>

</html>

1.4.1 案例:禁止选中文字和禁止右键菜单

js 复制代码
<body>
    我是一段不愿意分享的文字
    <script>
        // 1. contextmenu 我们可以禁用右键菜单
        document.addEventListener('contextmenu', function(e) {
                e.preventDefault();
        })
        // 2. 禁止选中文字 selectstart
        document.addEventListener('selectstart', function(e) {
            e.preventDefault();
        })
    </script>
</body>

1.4.2 鼠标事件对象


1.4.3 获取鼠标在页面的坐标

js 复制代码
    <script>
        // 鼠标事件对象 MouseEvent
        document.addEventListener('click', function(e) {
            // 1. client 鼠标在可视区的x和y坐标
            console.log(e.clientX);
            console.log(e.clientY);
            console.log('---------------------');

            // 2. page 鼠标在页面文档的x和y坐标
            console.log(e.pageX);
            console.log(e.pageY);
            console.log('---------------------');

            // 3. screen 鼠标在电脑屏幕的x和y坐标
            console.log(e.screenX);
            console.log(e.screenY);

        })
    </script>

1.4.4 案例:跟随鼠标的天使

js 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        img {
            position: absolute;
            top: 2px;
        }
    </style>
</head>

<body>
    <img src="images/angel.gif" alt="">
    <script>
        var pic = document.querySelector('img');
        document.addEventListener('mousemove', function(e) {
            // 1. mousemove只要我们鼠标移动1px 就会触发这个事件
            // console.log(1);
            // 2.核心原理: 每次鼠标移动,我们都会获得最新的鼠标坐标, 把这个x和y坐标做为图片的top和left 值就可以移动图片
            var x = e.pageX;
            var y = e.pageY;
            console.log('x坐标是' + x, 'y坐标是' + y);
            //3 . 千万不要忘记给left 和top 添加px 单位
            pic.style.left = x - 50 + 'px';
            pic.style.top = y - 40 + 'px';
        });
    </script>
</body>

</html>

day04 - Web APIs

学习目标:

能够说出常用的3-5个键盘事件

能够知道如何获取当前键盘按下的是哪个键

能够知道浏览器的顶级对象window

能够使用window.onload事件

能够使用window.onresize事件

能够说出两种定时器的区别

能够使用location对象的href属性完成页面之间的跳转

能够使用location对象获取url中的参数部分

能够使用history提供的方法实现页面刷新

1.1. 常用的键盘事件

1.1.1 键盘事件

js 复制代码
    <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>

1.1.2 键盘事件对象

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

js 复制代码
    <script>
        // 键盘事件对象中的keyCode属性可以得到相应键的ASCII码值
        // 1. 我们的keyup 和keydown事件不区分字母大小写  a 和 A 得到的都是65
        // 2. 我们的keypress 事件 区分字母大小写  a  97 和 A 得到的是65
        document.addEventListener('keyup', function(e) {
            // console.log(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>

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

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

注意:触发获得焦点事件,可以使用 元素对象.focus()

js 复制代码
    <input type="text">
    <script>
        // 获取输入框
        var search = document.querySelector('input');
		// 给document注册keyup事件
        document.addEventListener('keyup', function(e) {
            // 判断keyCode的值
            if (e.keyCode === 83) {
                // 触发输入框的获得焦点事件
                search.focus();
            }
        })
    </script>

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

要求:当我们在文本框中输入内容时,文本框上面自动显示大字号的内容。

js 复制代码
    <div class="search">
        <div class="con">123</div>
        <input type="text" placeholder="请输入您的快递单号" class="jd">
    </div>
    <script>
        // 获取要操作的元素
        var con = document.querySelector('.con');
        var jd_input = document.querySelector('.jd');
		// 给输入框注册keyup事件
        jd_input.addEventListener('keyup', function() {
				// 判断输入框内容是否为空
                if (this.value == '') {
                    // 为空,隐藏放大提示盒子
                    con.style.display = 'none';
                } else {
                    // 不为空,显示放大提示盒子,设置盒子的内容
                    con.style.display = 'block';
                    con.innerText = this.value;
                }
            })
        // 给输入框注册失去焦点事件,隐藏放大提示盒子
        jd_input.addEventListener('blur', function() {
                con.style.display = 'none';
            })
        // 给输入框注册获得焦点事件
        jd_input.addEventListener('focus', function() {
            // 判断输入框内容是否为空
            if (this.value !== '') {
                // 不为空则显示提示盒子
                con.style.display = 'block';
            }
        })
    </script>

1.2. BOM

1.2.1. 什么是BOM

​ BOM(Browser Object Model)即浏览器对象模型,它提供了独立于内容而与浏览器窗口进行交互的对象,其核心对象是 window。

​ BOM 由一系列相关的对象构成,并且每个对象都提供了很多方法与属性。

​ BOM 缺乏标准,JavaScript 语法的标准化组织是 ECMA,DOM 的标准化组织是 W3C,BOM 最初是Netscape 浏览器标准的一部分。

1.2.2. BOM的构成

BOM 比 DOM 更大,它包含 DOM。

1.2.3. 顶级对象window

1.2.4. window对象的常见事件

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

第1种

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

第2种

​ DOMContentLoaded 事件触发时,仅当DOM加载完成,不包括样式表,图片,flash等等。

​ IE9以上才支持!!!

​ 如果页面的图片很多的话, 从用户访问到onload触发可能需要较长的时间, 交互效果就不能实现,必然影响用户的体验,此时用 DOMContentLoaded 事件比较合适。

js 复制代码
  <!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script>
        // window.onload = function() {
        //     var btn = document.querySelector('button');
        //     btn.addEventListener('click', function() {
        //         alert('点击我');
        //     })
        // }
        // window.onload = function() {
        //     alert(22);
        // }
        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);
            })
            // load 等页面内容全部加载完毕,包含页面dom元素 图片 flash  css 等等
            // DOMContentLoaded 是DOM 加载完毕,不包含图片 falsh css 等就可以执行 加载速度比 load更快一些
    </script>
</head>

<body>

    <button>点击</button>

</body>

</html>
调整窗口大小事件

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

注意:

  1. 只要窗口大小发生像素变化,就会触发这个事件。

  2. 我们经常利用这个事件完成响应式布局。 window.innerWidth 当前屏幕的宽度

js 复制代码
    <script>
        // 注册页面加载事件
        window.addEventListener('load', function() {
            var div = document.querySelector('div');
        	// 注册调整窗口大小事件
            window.addEventListener('resize', function() {
                // window.innerWidth 获取窗口大小
                console.log('变化了');
                if (window.innerWidth <= 800) {
                    div.style.display = 'none';
                } else {
                    div.style.display = 'block';
                }
            })
        })
    </script>
    <div></div>

1.2.5. 定时器(两种)

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

  • setTimeout()

  • setInterval()

setTimeout() 炸弹定时器
开启定时器


普通函数是按照代码顺序直接调用。

简单理解: 回调,就是回头调用的意思。上一件事干完,再回头再调用这个函数。

例如:定时器中的调用函数,事件处理函数,也是回调函数。

以前我们讲的 element.onclick = function(){} 或者 element.addEventListener("click", fn); 里面的 函数也是回调函数。

js 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <script>
        // 1. setTimeout 
        // 语法规范:  window.setTimeout(调用函数, 延时时间);
        // 1. 这个window在调用的时候可以省略
        // 2. 这个延时时间单位是毫秒 但是可以省略,如果省略默认的是0
        // 3. 这个调用函数可以直接写函数 还可以写 函数名 还有一个写法 '函数名()'
        // 4. 页面中可能有很多的定时器,我们经常给定时器加标识符 (名字)
        // setTimeout(function() {
        //     console.log('时间到了');

        // }, 2000);
        function callback() {
            console.log('爆炸了');
        }
        var timer1 = setTimeout(callback, 3000);
        var timer2 = setTimeout(callback, 5000);
        // setTimeout('callback()', 3000); // 我们不提倡这个写法
    </script>
</body>

</html>
案例:5秒后关闭广告
js 复制代码
<body>
    <img src="images/ad.jpg" alt="" class="ad">
    <script>
        // 获取要操作的元素
        var ad = document.querySelector('.ad');
		// 开启定时器
        setTimeout(function() {
            ad.style.display = 'none';
        }, 5000);
    </script>
</body>
停止定时器

clearTimeout(timer)

js 复制代码
    <button>点击停止定时器</button>
    <script>
        var btn = document.querySelector('button');
		// 开启定时器
        var timer = setTimeout(function() {
            console.log('爆炸了');
        }, 5000);
		// 给按钮注册单击事件
        btn.addEventListener('click', function() {
            // 停止定时器
            clearTimeout(timer);
        })
    </script>
setInterval() 闹钟定时器
开启定时器
js 复制代码
    <script>
        // 1. setInterval 
        // 语法规范:  window.setInterval(调用函数, 延时时间);
        setInterval(function() {
            console.log('继续输出');
        }, 1000);
        // 2. setTimeout  延时时间到了,就去调用这个回调函数,只调用一次 就结束了这个定时器
        // 3. setInterval  每隔这个延时时间,就去调用这个回调函数,会调用很多次,重复调用这个函数
    </script>
案例:倒计时
js 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        div {
            margin: 200px;
        }
        
        span {
            display: inline-block;
            width: 80px;
            height: 40px;
            background-color: #333;
            font-size: 20px;
            color: #fff;
            text-align: center;
            line-height: 40px;
        }
    </style>
</head>

<body>
    <div>
        <span class="hour">1</span>
        <span class="minute">2</span>
        <span class="second">3</span>
    </div>
    <script>
        // 1. 获取元素 
        var hour = document.querySelector('.hour'); // 小时的黑色盒子
        var minute = document.querySelector('.minute'); // 分钟的黑色盒子
        var second = document.querySelector('.second'); // 秒数的黑色盒子
        var inputTime = +new Date('2019-5-1 18:00:00'); // 返回的是用户输入时间总的毫秒数
        countDown(); // 我们先调用一次这个函数,防止第一次刷新页面有空白 
        // 2. 开启定时器
        setInterval(countDown, 1000);

        function countDown() {
            var nowTime = +new Date(); // 返回的是当前时间总的毫秒数
            var times = (inputTime - nowTime) / 1000; // times是剩余时间总的秒数 
            var h = parseInt(times / 60 / 60 % 24); //时
            h = h < 10 ? '0' + h : h;
            hour.innerHTML = h; // 把剩余的小时给 小时黑色盒子
            console.log(' hour.innerHTML', hour.innerHTML)
            var m = parseInt(times / 60 % 60); // 分
            m = m < 10 ? '0' + m : m;
            minute.innerHTML = m;
            console.log(' minute.innerHTML', minute.innerHTML)

            var s = parseInt(times % 60); // 当前的秒
            s = s < 10 ? '0' + s : s;
            second.innerHTML = s;
            console.log(' second.innerHTML', second.innerHTML)

        }
    </script>
</body>

</html
停止定时器

clearInterval(timer);

javascript 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <button class="begin">开启定时器</button>
    <button class="stop">停止定时器</button>
    <script>
        var begin = document.querySelector('.begin');
        var stop = document.querySelector('.stop');
        var timer = null; // 全局变量  null是一个空对象
        begin.addEventListener('click', function() {
            timer = setInterval(function() {
                console.log('ni hao ma');
            }, 1000);
        })
        stop.addEventListener('click', function() {
            clearInterval(timer);
        })
    </script>
</body>

</html>
案例:发送短信倒计时

​ 点击按钮后,该按钮60秒之内不能再次点击,防止重复发送短信。

js 复制代码
    手机号码: <input type="number"> <button>发送</button>
    <script>
        var btn = document.querySelector('button');
		// 全局变量,定义剩下的秒数
        var time = 3; 
		// 注册单击事件
        btn.addEventListener('click', function() {
            // 禁用按钮
            btn.disabled = true;
            // 开启定时器
            var timer = setInterval(function() {
                // 判断剩余秒数
                if (time == 0) {
                    // 清除定时器和复原按钮
                    clearInterval(timer);
                    btn.disabled = false;
                    btn.innerHTML = '发送';
                } else {
                    btn.innerHTML = '还剩下' + time + '秒';
                    time--;
                }
            }, 1000);
        });
    </script>

1.2.6. this指向问题

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

现阶段,我们先了解一下几个this指向

  1. 全局作用域或者普通函数中this指向全局对象window(注意定时器里面的this指向window)

  2. 方法调用中谁调用this指向谁

  3. 构造函数中this指向构造函数的实例

js 复制代码
    <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>

1.2.7. location对象

什么是 location 对象
URL
location 对象的属性
案例:5分钟自动跳转页面
js 复制代码
    <button>点击</button>
    <div></div>
    <script>
        var btn = document.querySelector('button');
        var div = document.querySelector('div');
        btn.addEventListener('click', function() {
            // console.log(location.href);
            location.href = 'http://www.itcast.cn';
        })
        var timer = 5;
        setInterval(function() {
            if (timer == 0) {
                location.href = 'http://www.itcast.cn';
            } else {
                div.innerHTML = '您将在' + timer + '秒钟之后跳转到首页';
                timer--;
            }
        }, 1000);
    </script>
案例:获取URL参数
js 复制代码
    <div></div>
	<script>
        console.log(location.search); // ?uname=andy
        // 1.先去掉?  substr('起始的位置',截取几个字符);
        var params = location.search.substr(1); // uname=andy
        console.log(params);
        // 2. 利用=把字符串分割为数组 split('=');
        var arr = params.split('=');
        console.log(arr); // ["uname", "ANDY"]
        var div = document.querySelector('div');
        // 3.把数据写入div中
        div.innerHTML = arr[1] + '欢迎您';
    </script>
location对象的常见方法
js 复制代码
    <button>点击</button>
    <script>
        var btn = document.querySelector('button');
        btn.addEventListener('click', function() {
            // 记录浏览历史,所以可以实现后退功能
            // location.assign('http://www.itcast.cn');
            // 不记录浏览历史,所以不可以实现后退功能
            // location.replace('http://www.itcast.cn');
            location.reload(true);
        })
    </script>

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

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

js 复制代码
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 = "";     //电脑
 }

1.2.9 history对象

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

javascript 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <a href="list.html">点击我去往列表页</a>
    <button>前进</button>
    <script>
        var btn = document.querySelector('button');
        btn.addEventListener('click', function() {
            // history.forward();
            history.go(1);
        })
    </script>
</body>

</html>
javascript 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <a href="index.html">点击我去往首页</a>
    <button>后退</button>
    <script>
        var btn = document.querySelector('button');
        btn.addEventListener('click', function() {
            // history.back();
            history.go(-1);
        })
    </script>
</body>

</html>

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

1.3. JS执行机制

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

js 复制代码
 console.log(1);
 
 setTimeout(function () {
     console.log(3);
 }, 1000);
 
 console.log(2);

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

js 复制代码
 console.log(1);
 
 setTimeout(function () {
     console.log(3);
 }, 0);
 
 console.log(2);

1.3.1 JS 是单线程

js 复制代码
	单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。如果前一个任务耗时很长,后一个任务就不得不一直等着。
	这样所导致的问题是: 如果 JS 执行的时间过长,这样就会造成页面的渲染不连贯,导致页面渲染加载阻塞的感觉。

1.3.2 同步任务和异步任务

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

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

同步

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

异步

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

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

同步任务指的是:

在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;

异步任务指的是:

不进入主线程、而进入"任务队列"的任务,当主线程中的任务运行完了,才会从"任务队列"取出异步任务放入主线程执行。

javascript 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <script>
        // 第一个问题
        // console.log(1);

        // setTimeout(function() {

        //     console.log(3);

        // }, 1000);

        // console.log(2);

        // 2. 第二个问题
        // console.log(1);

        // setTimeout(function() {

        //     console.log(3);

        // }, 0);

        // console.log(2);

        // 3. 第三个问题

        console.log(1);
        document.onclick = function() {
            console.log('click');
        }
        console.log(2);
        setTimeout(function() {
            console.log(3)
        }, 3000)
    </script>
</body>

</html>

1.3.3 JS执行机制(事件循环)


1.3.4 代码思考题

js 复制代码
 console.log(1);
 document.onclick = function() {
   console.log('click');
 }

 setTimeout(function() {
   console.log(3)
 }, 3000)
 console.log(2);
相关推荐
学了就忘几秒前
JavaScript 异步编程与请求取消全指南
开发语言·javascript·ecmascript
凯哥19702 分钟前
Sciter.js 指南 - GUI的窗口管理特性详解
前端
秋天的一阵风3 分钟前
Webpack 插件开发:为 Vue.js 应用实现图片预加载
前端·vue.js·webpack
努力学习的小刘4 分钟前
JS实现并发控制、请求合并、数据缓存
前端
LengineerC4 分钟前
React添加路由切换过渡动画
前端
通南北4 分钟前
使用python实现自动化拉取压缩包并处理流程
开发语言·python·自动化
火星思想5 分钟前
Webpack热更新后模块生效的完整过程
前端·webpack·架构
月亮慢慢圆6 分钟前
监视器
前端
sevenliao7 分钟前
js 继承方式有哪几种
javascript
10年前端老司机8 分钟前
微信小程序自定义组件
前端·javascript·微信小程序