JavaScript从零开始 学习记录(三)

前言

到了我最为感兴趣的部分了,要戒骄戒躁,毕竟还没出发多远,不能想着一步登天,稳扎稳打

笔记范围

从这节视频到那节视频结束

课程目标

  • 能够说出Web APIs阶段与JavaScript语法阶段的关联性
  • 能够说出什么是API
  • 能够说出什么是Web API

Web APIs 和 JS基础关联性

JS基础阶段

  • 学习的是ECMAScript标准规定的基本语法
  • 为JS后面的课程打基础、做铺垫

Web APIs阶段

  • Web APIs 是 w3c组织的标准
  • Web APIs主要学习 DOM 和 BOM
  • Web APIs 为JS 所独有的部分
  • 需要使用JS基础课程内容

JS基础 学习的是ECMAScript基础语法,这为后面作铺垫

Web APIs是JS应用,大量使用JS基础语法做交互效果

API 和 Web API

API(Application Programming Interface,应用程序编程接口)是一些预先定义的函数,目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力,而又无需访问源码或理解内部工作机制的细节

简单理解:API是程序员提供的一种工具,以便能够轻松的实现想要完成的功能

Web API是浏览器提供的一套操作浏览器功能和页面元素的API(BOM和DOM)

现阶段主要针对于浏览器讲解常用的API,对浏览器做交互效果

如:想要浏览器弹出一个警示框,直接使用alert(‘弹出’)

MDN详细 API:https://developer.mozilla.org/zh-CN/docs/Web/API

因为Web API很多,所以称 这个阶段为Web APIs

  • API是程序员提供的一个接口,帮助实现某种功能,会使用就好,不必纠结内部实现机制

  • Web API主要针对浏览器提供的接口,主要针对浏览器做交互效果

  • Web API一般有输入和输出(函数的传参和返回值),Web API很多都是方法(函数)

  • 学习Web API可以结合前面学习内置对象方法的思路来学习

课程目标

  • 能够说出什么是DOM
  • 能够获取页面元素
  • 能够给元素注册事件
  • 能够操作DOM元素的属性
  • 能够创建元素
  • 能够操作DOM节点

DOM简介

文档对象模型(Document Object Model,简称DOM),是W3C组织推荐的处理可扩展标记语言(HTML或者XML)的标准编程接口

W3C 已经定义了一系列的DOM接口,通过这些DOM接口可以改变网页的内容、结构和样式

  • 文档:一个页面就是一个文档,DOM中使用document表示
  • 元素:页面中的所有标签都是元素,DOM中使用element表示
  • 节点:网页中的所有内容都是节点(标签、属性、文本、注释等),DOM中使用node表示

文档包含节点,节点包含元素

获取元素

DOM在实际开发中主要用来操作元素

获取页面中的元素可以使用以下几种方式:

  • 根据ID获取
  • 根据标签名获取
  • 通过HTML5新增的方法获取
  • 特殊元素获取

根据ID获取

使用getElementById()方法可以获取带有ID的元素对象

在这里插入图片描述
JavaScript从零开始 学习记录(三)_第1张图片
JavaScript从零开始 学习记录(三)_第2张图片
注意: 多刷新几次,控制台输出就会发生变化(原因不详)

根据标签名获取

使用getElementsByTagName()方法可以返回带有指定标签名的对象集合

还可以获取某个元素(父元素)内部所有指定标签名的子元素

element.getElementsByTagName('标签名');

注意:父元素必须是单个对象(必须指明是哪一个元素对象),获取的适合不包括父元素本身

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <ul>
        <li>知否知否,应是等你好久1</li>
        <li>知否知否,应是等你好久2</li>
        <li>知否知否,应是等你好久3</li>
        <li>知否知否,应是等你好久4</li>
    </ul>
    <ol id="ol">
        <li>生僻字</li>
        <li>生僻字</li>
        <li>生僻字</li>
    </ol>
    <script>
        var lis = document.getElementsByTagName('li');
        console.log(lis);
        console.log(lis[0]);
        for (var i = 0; i < lis.length; i++) {
            console.log(lis[i]);
        }
        // 如果页面中只有一个标签,返回的依旧是伪数组形式
        var tes = document.getElementsByTagName('div');
        console.log(tes); // 得到的是一个空的伪数组形式
        // var ol = document.getElementsByTagName('ol'); //[ol]
        // console.log(ol[0].getElementsByTageName('li')); 
        var ol = document.getElementById('ol');
        console.log(ol.getElementsByTagName('li'));
    </script>
</body>
</html>

JavaScript从零开始 学习记录(三)_第3张图片

H5新增获取元素方式

document.getElementsByClassName('类名'); // 根据类名返回元素对象集合
document.querySelector('选择器'); // 根据指定选择器返回第一个元素对象
document.querySelectorAll('选择器'); // 根据指定选择器返回

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div class="box">盒子</div>
    <div class="box">盒子</div>
    <div id="nav">
        <ul>
            <li>首页</li>
            <li>产品</li>
        </ul>
    </div>
    <script>
        // getElementsByClassName 根据类名获得某些元素集合
        var boxs = document.getElementsByClassName('box');
        console.log(boxs);
        // querySelector 返回指定选择器的第一个元素对象
        var firstBox = document.querySelector('.box');
        console.log(firstBox);
        var nav = document.querySelector('#nav');
        console.log(nav);
        var li = document.querySelector('li');
        console.log(li);
        var allBox = document.querySelectorAll('.box');
        console.log(allBox);
        var lis = document.querySelectorAll('li');
        console.log(lis);
    </script>
</body>
</html>

JavaScript从零开始 学习记录(三)_第4张图片

获取特殊元素

获取body元素

document.body // 返回body元素对象
document.documentElement // 返回html元素对象

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        // 获取body 元素
        var bodyEle = document.body;
        console.log(bodyEle);
        console.dir(bodyEle);
        // 获取html 元素
        var htmlEle = document.documentElement;
        console.log(htmlEle);
    </script>
</body>
</html>

JavaScript从零开始 学习记录(三)_第5张图片

事件基础

JavaScript使我们有能力创建动态页面,而事件使可以被JavaScript侦测到的行为

简单理解:触发–响应机制

网页中每个元素都可以产生某些可以触发JavaScript的事件

在用户点击某按钮时产生一个事件,然后去执行某些操作

事件三要素:谁触发的,怎么触发的,触发的后果

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <button id="btn">唐伯虎</button>
    <script>
        // 点击一个按钮,弹出对话框
        // 事件是有三部分组成 事件源 事件类型 事件处理程序 也称为事件三要素
        // 事件源 事件被触发的对象 按钮
        var btn = document.getElementById('btn');
        // 事件类型 如何触发 比如鼠标点击(onclick) 还是鼠标经过 还是键盘按下
        // 事件处理程序 通过一个函数赋值的方式 完成
        btn.onclick = function() {
            alert('点秋香');
        }
    </script>
</body>
</html>

效果

JavaScript从零开始 学习记录(三)_第6张图片

执行事件的步骤

  1. 获取事件源
  2. 注册事件(绑定事件)
  3. 添加事件处理程序(采取函数赋值形式)

JavaScript从零开始 学习记录(三)_第7张图片
JavaScript从零开始 学习记录(三)_第8张图片

鼠标事件 触发条件
onclick 鼠标点击左键触发
onmouseover 鼠标经过触发
onmouseout 鼠标离开触发
onfocus 获得鼠标焦点触发
onblur 失去鼠标焦点触发
onmousemove 鼠标移动触发
onmouseup 鼠标弹起触发
onmousedown 鼠标按下触发

分析事件三要素

操作元素

JavaScript的DOM操作可以改变网页内容、结构和样式,可以利用DOM操作元素来改变元素的内容、属性等

改变元素内容

element.innerText 从起始位置到终止位置的内容,但它去除html标签,同时空格和换行也会去掉

element.innerHTML 起始位置到终止位置的全部内容,包括html标签,同时保留空格和换行

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        div+p {
            width: 300px;
            height: 30px;
            line-height: 30px;
            color: #fff;
            background-color: pink;
        }
    </style>
</head>
<body>
    <button>显示当前系统时间</button>
    <div>某个时间</div>
    <p>123</p>
    <script>
        // 点击按钮,div 里面的文字会发生变化
        // 获取元素
        var btn = document.querySelector('button');
        var div = document.querySelector('div');
        // 注册事件
        btn.onclick = function() {
            // div.innerText = '2019-6-6';
            div.innerText = getDate();
        }

        function getDate() {
            var date = new Date();
            var year = date.getFullYear();
            var month = date.getMonth() + 1;
            var dates = date.getDate();
            var arr = ['星期天', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];
            var day = date.getDay();
            return '今天是' + year + '年' + month + '月' + dates + '日' + arr[day];
        }
        var p = document.querySelector('p');
        p.innerText = getDate();
    </script>
</body>
</html>

效果

JavaScript从零开始 学习记录(三)_第9张图片

innerText和innerHTML的区别

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div></div>
    <p>
        我是文字
        <span>123</span>
    </p>
    <script>
        // innerText不识别 html标签 去除空格和换行
        var div = document.querySelector('div');
        div.innerText = '今天是:/strong> 2023';
        div.innerHTML = '今天是: 2023';
        var p = document.querySelector('p');
        console.log(p.innerText);
        console.log(p.innerHTML);
    </script>
</body>
</html>

JavaScript从零开始 学习记录(三)_第10张图片

常用元素的属性操作

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        img {
            width: 300px;
        }
    </style>
</head>
<body>
    <button id="ldh">刘德华</button>
    <button id="zxy">张学友</button><br/>
    <img src="../img/ldh.jpg" alt="" title="刘德华">

    <script>
        // 修改元素属性
        // 获取元素
        var ldh = document.getElementById('ldh');
        var zxy = document.getElementById('zxy');
        var img = document.querySelector('img');
        // 注册事件
        zxy.onclick = function() {
            img.src = '../img/zxy.jpg';
            img.title = '张学友思密达';
        }
        ldh.onclick = function() {
            img.src = '../img/ldh.jpg';
            img.title = '刘德华'
        }
    </script>
</body>
</html>

效果如下

JavaScript从零开始 学习记录(三)_第11张图片

案例:分时显示不同图片,显示不同问候语

案例分析

  1. 根据系统不同时间来判断,所以需要用到日期内置对象
  2. 利用多分支语句来设置不同的图片
  3. 需要一个图片,并且根据时间修改图片,就需要用到操作元素src属性
  4. 需要一个div元素,显示不同问候语,修改元素内容即可
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <img src="../img/swh.gif" alt="">
    <div>上午好</div>
    <script>
        var img = document.querySelector('img');
        var div = document.querySelector('div');
        var date = new Date();
        var h = date.getHours();
        if (h < 12) {
            img.src = '../img/swh.gif';
            div.innerHTML = '亲,上午好,好好写代码';
        } else if (h < 18) {
            img.src = '../img/xwh.gif';
            div.innerHTML = '亲,下午好,好好写代码';
        } else {
            img.src = '../img/wsh.gif';
            div.innerHTML = '亲,晚上好,好好写代码';
        }
    </script>
</body>
</html>

表单元素的属性操作

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <button>按钮</button>
    <input type="text" value="输入内容">
    <script>
        var btn = document.querySelector('button');
        var input = document.querySelector('input');
        btn.onclick = function() {
            // 表单里面的值(文字内容) 通过value来修改
            input.value = '被点击了';
            // 如果想要某个表单被禁用 不能再点击 disabled 禁用按钮
            // btn.disabled = true;
            this.disabled = true;
            // this 指向的事件函数的调用者
        }
    </script>
</body>
</html>

JavaScript从零开始 学习记录(三)_第12张图片

仿京东显示隐藏密码明文案例

案例分析

  1. 核心思路:点击眼睛按钮,把密码框类型改为文本框就可以看见里面的密码
  2. 一个按钮两个状态,点击一次,切换为文本框,继续点击一次,切换为密码框
  3. 算法:利用一个flag变量,来判断flag的值,如果是1就切换为文本框,flag设置为0,如果是0就切换为密码框,flag设置为1

JavaScript从零开始 学习记录(三)_第13张图片

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .box {
            position: relative;
            width: 400px;
            border: 1px solid #ccc;
            margin: 100px auto;
        }
        .box input {
            width: 370px;
            height: 30px;
            border: 0;
            outline: none;
        }
        .box img {
            position: absolute;
            top: 6px;
            right: 6px;
            width: 20px;
        }
    </style>
</head>
<body>
    <div class="box">
        <label for="">
            <img src="../img/eye_off.png" alt="" id="eye">
        </label>
        <input type="password" name="" id="pwd">
    </div>
    <script>
        // 获取元素
        var eye = document.getElementById('eye');
        var pwd = document.getElementById('pwd');
        // 注册事件 处理程序
        var flag = 0;
        eye.onclick = function() {
            if (flag == 0) {
                pwd.type = 'text';
                eye.src = '../img/eye_open.png';
                flag = 1;
            } else {
                pwd.type = 'password';
                eye.src = '../img/eye_off.png';
                flag = 0;
            }  
        }
    </script>
</body>
</html>

效果
JavaScript从零开始 学习记录(三)_第14张图片

修改样式属性

可以通过JS修改元素的大小、颜色、位置等样式

element.style 行内样式操作element.className 类名样式操作

注意:

  1. JS里面的样式采取驼峰命名法,如fontSize、backgroundColor
  2. JS修改style样式操作,产生的是行内样式,css权重较高

如果直接对div元素使用元素选择器,会出现实际高度高于设定高度2倍

如下(导致原因不详,HTML 和 CSS知识忘了不少)

JavaScript从零开始 学习记录(三)_第15张图片

故而不直接对其进行元素选择,用类选择器

JavaScript从零开始 学习记录(三)_第16张图片

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .circle {
            width: 200px;
            height: 200px;
            background-color: pink;
            border-radius: 50%;
        }
    </style>
</head>
<body>
    <div class="circle"></div>
    <script>
        // 获取元素
        var div = document.querySelector('div');
        // 注册事件 处理程序
        div.onclick = function() {
            this.style.backgroundColor = 'purple';
            this.style.width = '250px';
        }
    </script>
</body>
</html>

效果

JavaScript从零开始 学习记录(三)_第17张图片

仿淘宝关闭二维码案例

案例分析

  1. 核心思路 利用样式的显示和隐藏完成,display:none隐藏元素,display:block显示元素
  2. 点击按钮,就让这个二维码盒子隐藏起来
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .box {
            position: relative;
            width: 0px;
            height: 0px;
            border: 0px solid #ccc;
            margin: 100px auto;
            font-size: 12px;
            text-align: center;
            color: #f40;
        }
        .box img {
            width: 60px;
            margin-top: 5px;
        }
        .close-btn {
            position: absolute;
            top: 5px;
            left: -16px;
            width: 14px;
            height: 14px;
            border: 1px solid #ccc;
            line-height: 14px;
            font-family: Arial, Helvetica, sans-serif;
            cursor: pointer;
        }
    </style>
</head>
<body>
    <div class="box">
        <img src="../img/tao.jpg" alt="">
        <span class="close-btn">x</i>
    </div>
    <script>
        // 获取元素
        var btn = document.querySelector('.close-btn');
        var box = document.querySelector('.box');
        // 注册事件 程序处理
        btn.onclick = function() {
            box.style.display = 'none'
        }
    </script>
</body>
</html>

效果

JavaScript从零开始 学习记录(三)_第18张图片

循环精灵图

精灵图简介
JavaScript从零开始 学习记录(三)_第19张图片
案例分析

  1. 精灵图图片排列有规律
  2. 核心思路:利用for循环 修改精灵图片的 背景位置background-position

在这里插入图片描述

JavaScript从零开始 学习记录(三)_第20张图片
JavaScript从零开始 学习记录(三)_第21张图片
JavaScript从零开始 学习记录(三)_第22张图片
JavaScript从零开始 学习记录(三)_第23张图片
JavaScript从零开始 学习记录(三)_第24张图片

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            list-style: none;
            margin: 0;
            padding: 0;
        }

        .box {
            width: 250px;
            height: 180px;
            margin: 100px auto;
        }

        .box li {
            float: left;
            width: 24px;
            height: 24px;
            background-color: pink;
            margin: 10px 0 30px 30px;
            background: url('../img/jlt.png') no-repeat;
        }
    </style>
</head>
<body>
    <div class="box">
        <ul>
            <li></li>
            <li></li>
            <li></li>
            <li></li>
            <li></li>
            <li></li>
            <li></li>
            <li></li>
            <li></li>
            <li></li>
            <li></li>
            <li></li>
        </ul>
    </div>
    <script>
        // 获取元素
        var lis = document.querySelectorAll('li');
        for (var i = 0; i < lis.length; i++) {
            // 让索引号 乘以 44 就是每个li 的背景y坐标 index就是y的坐标
            var index = i * 44;
            lis[i].style.backgroundPosition = '0 -' + index + 'px'
        }
    </script>
</body>
</html>

显示隐藏文本框内容

案例分析

  1. 首先表单需要2个新事件,获得焦点 onfocus 失去焦点onblur
  2. 如果获得焦点,判断表单里面内容是否为默认文字,如果是默认文字,就清空表单内容
  3. 如果失去焦点,判断表单内容是否为空,如果为空,则表单内容改为默认文字
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        input {
            color: #999;
        }
    </style>
</head>
<body>
    <input type="text" value="手机">
    <script>
        // 获取元素
        var text = document.querySelector('input');
        // 注册事件 获得焦点事件
        text.onfocus = function() {
            console.log('得到了焦点');
            if (this.value === '手机') {
                this.value = '';
            }
            // 获得焦点 需要把文本框内的文字颜色变黑
            this.style.color = '#333';
        }
        // 注册事件 失去焦点事件
        text.onblur = function() {
            console.log('失去了焦点');
            if (this.value === '') {
                this.value = '手机';
            }
            // 失去焦点 需要把文本框内的文字颜色变浅
            this.style.color = '#999';
        }
    </script>
</body>
</html>

效果
JavaScript从零开始 学习记录(三)_第25张图片

通过className更改元素样式

  • 如果样式修改较多,可以采取类名方式更改元素样式
  • class是个关键字,所以使用className来操作元素类名属性
  • className 会直接更改元素类名,覆盖掉原先的类名
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .circle {
            width: 100px;
            height: 100px;
            background-color: pink;
        }
        .change {
            background-color: purple;
            color: #fff;
            font-size: 25px;
            height: 100px;
            width: 100px;
            margin-top: 100px;
        }
    </style>
</head>
<body>
    <div class="circle">文本</div>
    <script>
        var test = document.querySelector('div');
        test.onclick = function() {
            // 让当前元素的类名改为 change
            // this.className = 'change';
            // 如果想保留原先的类名,可以这么做 多类名选择器
            this.className = 'circle change';
        }
    </script>
</body>
</html>

效果

JavaScript从零开始 学习记录(三)_第26张图片

密码框验证信息

案例分析

  1. 首先判断的事件是表单失去焦点onblur
  2. 如果输入正确则提示正确的信息颜色为绿色小图标
  3. 如果输入不是6到16位,则提示错误信息颜色为红色小图标
  4. 因为里面变化样式较多,采取className修改样式
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        div {
            width: 600px;
            margin: 100px auto;
        }
        .icon {
            width: 16px;
            height: 16px;
            margin:0 1px -3px 0;
            display: inline-block;
        }
        .message {
            display: inline-block;
            font-size: 12px;
            color: #999;
            padding-left: -6px;
        }
    </style>
</head>
<body>
    <div class="regiester">
        <input type="password" class="ipt">
        <img src="../img/mess.png" class="icon">
        <p class="message">    
            请输入6~16位密码
        </p>
    </div>
    <script>
        var ipt = document.querySelector('.ipt');
        var img = document.querySelector('.icon');
        var message = document.querySelector('.message'); 
        ipt.onblur = function() {
            // 根据表单值的长度 ipt.value.length
            if (this.value.length < 6 || this.value.length > 16) {
                img.src = '../img/wrong.png';
                message.innerHTML = '您输入的位数不对要求6~16位';
                message.style.color = 'red';
            } else {
                img.src = '../img/right.png';
                message.innerHTML = '您输入的正确';
                message.style.color = '#000';
            }
        }
    </script>
</body>
</html>

效果
JavaScript从零开始 学习记录(三)_第27张图片

操作元素总结

操作元素是DOM核心内容

JavaScript从零开始 学习记录(三)_第28张图片

开关灯

效果

JavaScript从零开始 学习记录(三)_第29张图片

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <button>关灯</button>
    <script>
        var btn = document.querySelector('button');
        var bd = document.body;
        var flag = false;
        btn.onclick = function() {
            flag = !flag;
            if (flag) {
                bd.style.backgroundColor = 'black';
                this.innerHTML = '开灯';
            } else {
                bd.style.backgroundColor = 'white';
                this.innerHTML = '关灯';
            }
        }
    </script>
</body>
</html>

排他思想

  1. 所有元素全部清楚样式
  2. 给当前元素设置样式

先排除其他,在设置自己的样式(排除他人,留下自己)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <button>按钮1</button>
    <button>按钮2</button>
    <button>按钮3</button>
    <button>按钮4</button>
    <button>按钮5</button>
    <script>
        // 获取所有按钮元素
        var btns = document.getElementsByTagName('button');
        for (var i = 0; i < btns.length; i++) {
            btns[i].onclick = function() {
                // 先把所有按钮的背景颜色去掉
                for (var i = 0; i < btns.length; i++) {
                    btns[i].style.backgroundColor = '';
                }
                // 然后让当前按钮的背景颜色位pink
                this.style.backgroundColor = 'pink';
            }
        }
    </script>
</body>
</html>

效果
JavaScript从零开始 学习记录(三)_第30张图片

百度换肤

案例分析

  1. 给一组元素注册事件
  2. 给小图片利用循环注册点击事件
  3. 当点击了这张图片,让页面背景改为当前的图片
  4. 核心算法:把当前图片src路径取出来,给body作为背景即可
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }
        body {
            margin:0px;
            background: url(../img/bd1.jpg) no-repeat;
            background-size:100% 100%;
            background-attachment:fixed;
        }
        li {
            list-style: none;
        }
        .baidu li {
            float: left;
            margin: 0 1px;
            cursor: pointer;
        }

        .baidu img {
            width: 100px;
        }
    </style>
</head>
<body>
    <ul class="baidu">
        <li><img src="../img/bd1.jpg"></li>
        <li><img src="../img/bd2.jpeg"></li>
        <li><img src="../img/bd3.jpg"></li>
        <li><img src="../img/bd4.png"></li>
    </ul>
    <script>
        // 获取元素
        var imgs = document.querySelector('.baidu').querySelectorAll('img');
        // 循环注册事件
        for (var i = 0; i < imgs.length; i++) {
            imgs[i].onclick = function() {
                document.body.style.backgroundImage = 'url(' + this.src + ')';
            }
        }
    </script>
</body>
</html>

效果

表格隔行变色

仿照新浪财经网页效果 https://vip.stock.finance.sina.com.cn/mkt/

案例分析

  1. 鼠标经过 onmouseover 鼠标离开 onmouseout
  2. 核心思路:鼠标经过tr行,当前的行变背景颜色,鼠标离开去掉当前的背景颜色
  3. 注意:第一行不需要变换颜色
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        table {
            /* 去掉td之间的空隙 */
            border-spacing: 0; 
            width: 100%
        }
        thead th {
            border-bottom: 1px solid #ACD3F2;
            background: #D4EDFF;
        }
        tbody tr {
            height: 30px;
            
        }
        tbody td {
            border-bottom: 1px solid #d7d7d7;
            font-size: 12px;
            color: blue;
        }

        .bg {
            background-color: #E6F3FC;
        }
    </style>
</head>
<body>
    <div style="text-align: center;">
        <table>
            <thead>
                <tr>
                    <th>代码</th>
                    <th>名称</th>
                    <th>最新价</th>
                    <th>涨跌额</th>
                    <th>涨跌幅</th>
                    <th>买入</th>
                    <th>卖出</th>
                    <th>昨收</th>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>sh603061</td>
                    <td>N金海通</td>
                    <td>84.36</td>
                    <td>+25.78</td>
                    <td>+44.008%</td>
                    <td>84.36</td>
                    <td>0.00</td>
                    <td>58.58</td>
                </tr>
                <tr>
                    <td>sh688525</td>
                    <td>佰维存储</td>
                    <td>26.96</td>
                    <td>+4.49</td>
                    <td>+19.982%</td>
                    <td>26.96</td>
                    <td>0.00</td>
                    <td>22.47</td>
                </tr>
                <tr>
                   <td>sh688049</td> 
                   <td>炬芯科技</td> 
                   <td>36.51</td> 
                   <td>+4.10</td> 
                   <td>+12.650%</td> 
                   <td>36.50</td> 
                   <td>36.51</td> 
                   <td>32.41</td> 
                </tr>
                <tr>
                    <td>sh688230</td>
                    <td>芯导科技</td>
                    <td>70.08</td>
                    <td>+7.64</td>
                    <td>+12.236%</td>
                    <td>70.07</td>
                    <td>70.08</td>
                    <td>62.44</td>
                </tr>
            </tbody>
            <script>
                // 获取元素
                var trs = document.querySelector('tbody').querySelectorAll('tr');
                // 利用循环绑定注册事件
                for (var i = 0; i < trs.length; i++) {
                    // 鼠标经过事件
                    trs[i].onmouseover = function() {
                        this.className = 'bg';
                    }
                    // 鼠标离开事件
                    trs[i].onmouseout = function() {
                        this.className = '';
                    }
                }
                
            </script>
        </table>    
    </div>
</body>
</html>

效果

JavaScript从零开始 学习记录(三)_第31张图片

表单全选取消全选

案例分析

  1. 全选和取消全选做法:让下面所有复选框的checked属性(选中状态)跟随全选按钮即可
  2. 下面复选框全部选中,上面全选才能选中做法:给下面所有复选框绑定点击事件,每次点击都要循环查看下面所有复选框是否被选中,如果有一个没选中,上面全选就不选中
  3. 可以设置一个变量,来控制全选是否选中
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            padding: 0;
            margin: 0;
        }

        .wrap {
            width: 300px;
            margin: 100px auto 0;
        }
        table {
            border-collapse: collapse;
            border-spacing: 0;
            border: 1px solid #c0c0c0;
            width: 300px;
        }
        th,
        td {
            border: 1px solid #d0d0d0;
            color: #404060;
            padding: 10px;
        }
        th {
            background-color: #09c;
            font: bold 16px "微软雅黑";
            color: #fff;
        }
        td {
            font: 14px "微软雅黑";
        }
        tbody tr {
            border-color: #f0f0f0;
        }
        tbody tr:hover {
            cursor: pointer;
            background-color: #fafafa;
        }
    </style>
</head>
<body>
    <div class="wrap" style="text-align: center;">
        <table>
            <thead>
                <tr>
                    <th>
                        <input type="checkbox" id="j_cbAll" />
                    </th>
                    <th>商品</th>
                    <th>价钱</th>
                </tr>
            </thead>
            <tbody id="j_tb">
                <tr>
                    <td>
                        <input type="checkbox" />
                    </td>
                    <td>iPhone8</td>
                    <td>8000</td>
                </tr>
                <tr>
                    <td>
                        <input type="checkbox" />
                    </td>
                    <td>iPad Pro</td>
                    <td>5000</td>
                </tr>
                <tr>
                    <td>
                        <input type="checkbox" />
                    </td>
                    <td>iPad Air</td>
                    <td>2000</td>
                </tr>
                <tr>
                    <td>
                        <input type="checkbox" />
                    </td>
                    <td>Apple Watch</td>
                    <td>2000</td>
                </tr>
            </tbody>
        </table>
    </div>
    <script>
        // 获取元素
        var j_chAll = document.getElementById('j_cbAll');
        var j_tbs = document.getElementById('j_tb').getElementsByTagName('input');
        // 注册事件 处理程序
        j_cbAll.onclick = function() {
            // this.checked 可以得到复选框的选中状态 true就是选中 false就是未选中
            for (var i = 0; i < j_tbs.length; i++) {
                j_tbs[i].checked = this.checked;
            }
        }
        // 下面复选框全部选中,上面全选才被选中
        for (var i = 0; i < j_tbs.length; i++) {
            j_tbs[i].onclick = function() {
                // flag 控制全选按钮是否选中
                var flag = true;
                for (var i = 0; i < j_tbs.length; i++) {
                    if (!j_tbs[i].checked) {
                        flag = false;
                        break;
                    }
                }
                j_cbAll.checked = flag;
            } 
        }
    </script>
</body>
</html>

效果

JavaScript从零开始 学习记录(三)_第32张图片

自定义属性的操作

获取属性值

  • element.属性 获取属性值
  • element.getAttribute(‘属性’)

区别:

  • element.属性 获取内置属性值(元素本身自带的属性)
  • element.getAtrribute(‘属性’) 主要获取自定义的属性(标准)

设置属性值

  • element.属性 = ‘值’ 设置内置属性值
  • element.setAttribute(‘属性’, ‘值’) 主要针对于自定义属性(内置属性和自定义属性都可)

移除属性

  • element.removeAttribute(‘属性’)

JavaScript从零开始 学习记录(三)_第33张图片
JavaScript从零开始 学习记录(三)_第34张图片

tab栏切换

应用实例:https://dianqi.suning.com/?safp=

案例分析

  1. Tab栏切换有两个大的模块
  2. 上面的模块为导航栏,下面的模块为内容区
  3. 下面的模块内容会随上面的选项卡变化,所以下面的模块变化写到点击事件里面
  4. 规律:下面的模块显示内容和上面鼠标经过的选项卡一一对应,相互匹配
  5. 核心思路:给上面的所有li添加自定义属性,属性值从0开始编号
  6. 但鼠标经过li时,让内容模块显示对应的序号内容,其余隐藏(排他思想)

难点

  1. 首先是鼠标经过时图片和文字的切换,尤其是图片,实现还不够完整
  2. 因为写的样式有点多,所以最好一层层向下写好选择器
  3. 仿照写的,所有源码(除了框架)都是一步步仿照来的,没有任何取巧,才制作出这样的效果
  4. 默认会显示导航栏中第一个选项卡内容,这一点如果第一次实现需要了解下

效果
JavaScript从零开始 学习记录(三)_第35张图片

观察细点就会发现有点瑕疵,和原效果有差距,但确实尽力只能做到这一步了

源码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .hot-tab {
            position: relative;
            width: 840px;
            margin: 10px auto;
            background: #fff;
        }

        .hot-tab .tab-nav {
            position: relative;;
            width: 100%;
            height: 86px;
            margin-bottom: 20px;
            background: #ccc;
            border-bottom: 2px solid #3664db;
        }

        ul {
            margin: 0;
            padding: 0;
        }

        ul, li {
            list-style: none;
        }
        
        .hot-tab .tab-nav li {
            position: relative;
            float: left;
            width: 140px;
            height: 86px;
            text-align: center;
            background: #fff;
        }
        
        .hot-tab .tab-nav li img {
            display: inline-block;
            width: 35px;
            height: 35px;
            margin-top: 10px;
            margin-bottom: 5px;
        }

        .hot-tab .tab-nav li span {
            display: block;
            height: 22px;
            color: #333;
            overflow: hidden;
        }

        .hot-tab .tab-nav li em {
            position: absolute;
            display: none;
            content: '';
            width: 0;
            height: 0;
            bottom: -2px;
            left: 50%;
            margin-left: -12px;
            border-left: 12px solid transparent;
            border-right: 12px solid transparent;
            border-bottom: 8px solid #fff;
        }

        .hot-tab .tab-content-wrap {
            position: relative;
        }

        .hot-tab .tab-content-wrap .item {
            position: relative;
            width: 1190px;
            height: 340px;
            left: 0;
            top: 0;
            overflow: hidden;
            display: none;
        }

        .hot-tab .tab-content-wrap .defatult_c {
            display: block;
        }

        .hot-tab .tab-nav .default_n {
            background: #3664db;
        }

        .hot-tab .tab-nav .default_n span {
            color: #fff;
        }

        .hot-tab .tab-nav .cur {
            background: #3664db;
        }

        .hot-tab .tab-nav .cur span {
            color: #fff;
        }

        .hot-tab .tab-nav .cur em {
            display: block;
        }
    </style>
</head>
<body>
    <div class="hot-tab">
        <div class="tab-nav">
            <ul class="clearfix">
                <li class="default_n">
                    <img src="../img/tab-hot-h.png" c-src="../img/tab-hot.png" d-src="../img/tab-hot-h.png" alt="今日必抢">
                    <span>今日必抢</span>
                    <em></em>
                </li>
                <li>
                    <img src="../img/tab-kt.png" c-src="../img/tab-kt.png" d-src="../img/tab-kt-h.png" alt="空调">
                    <span>空调</span>
                    <em></em>
                </li>
                <li>
                    <img src="../img/hot-ds.png" c-src="../img/hot-ds.png" d-src="../img/hot-ds-h.png" alt="电视">
                    <span>电视</span>
                    <em></em>
                </li>
                <li>
                    <img src="../img/hot-rs.png" c-src="../img/hot-rs.png" d-src="../img/hot-rs-h.png" alt="热水器">
                    <span>热水器</span>
                    <em></em>
                </li>
                <li>
                    <img src="../img/hot-bx.png" c-src="../img/hot-bx.png" d-src="../img/hot-bx-h.png" alt="冰箱">
                    <span>冰箱</span>
                    <em></em>
                </li>
                <li>
                    <img src="../img/hot-xy.png" c-src="../img/hot-xy.png" d-src="../img/hot-xy-h.png" alt="洗衣机">
                    <span>洗衣机</span>
                    <em></em>
                </li>    
            </ul>
        </div>
        <div class="tab-content-wrap">
            <div class="item defatult_c">今日必抢模块内容</div>
            <div class="item">空调模块内容</div>
            <div class="item">电视模块内容</div>
            <div class="item">热水器模块内容</div>
            <div class="item">冰箱模块内容</div>
            <div class="item">洗衣机模块内容</div>
        </div>
    </div>
    <script>
        // 获取元素
        var tab_nav = document.querySelector('.tab-nav');
        var lis = tab_nav.querySelectorAll('li');
        var items = document.querySelectorAll('.item');
        // for循环绑定鼠标经过和离开事件
        for (var i = 0; i < lis.length; i++) {  
            // 开始给6个li 设置索引号
            lis[i].setAttribute('index', i);  
            lis[i].onmouseover = function() {
                // 干掉其他人
                for (var i = 0; i < lis.length; i++) {
                    lis[i].className = '';
                }
                this.className = 'cur';
                var img = this.querySelector('img'); 
                img.src = img.getAttribute('d-src');
                // 显示内容模块
                var index = this.getAttribute('index');
                // 干掉所有人
                for (var i = 0; i < items.length; i++) {
                    items[i].style.display = 'none';
                }
                // 留下我自己
                items[index].style.display = 'block';
            }
            lis[i].onmouseout = function() {
                var span = this.querySelector('span');
                var img = this.querySelector('img');
                img.src = img.getAttribute('c-src');
            }
        }
    </script>
</body>
</html>

最大收获就是有了仿照网页的经验,之前有,但都是跟着视频里老师一步步敲的,这次从头到尾都是独立分析的,其次对之前的知识进行了一次回顾,还阔以…

H5自定义属性

自定义属性目的:为了保存并使用数据,有些数据可以保存到页面中而不用保存到数据库中

但有些自定义属性容易引起歧义,不容易判断是元素的内置属性还是自定义属性

H5规定自定义属性data-开头作为属性名且赋值,只能

获取H5自定义属性

  • H5新增获取自定义属性的方法 element.dataset[‘自定义属性名’],有兼容性问题ie11以上兼容
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div getTime="20" data-index="2" data-list-name="andy"></div>
    <script>
        var div = document.querySelector('div');
        console.log(div.getAttribute('getTime'));
        // h5新增的获取自定义属性的方法 只能获取data-开头的
        console.log(div.dataset);
        console.log(div.dataset.index);
        console.log(div.dataset['index']);
        // 如果自定义属性里面有多个-链接的单词,获取时采用驼峰命名法
        console.log(div.dataset.listName);
    </script>
</body>
</html>

JavaScript从零开始 学习记录(三)_第36张图片

节点操作

获取元素通常使用两种方式

利用DOM提供的方法获取元素

  • document.getElementById()
  • document.getElementByTagName()
  • document.querySelector()等

逻辑性不强,繁琐

利用节点层级关系获取元素

  • 利用父子兄节点关系获取元素
  • 逻辑性强,但兼容性稍差

这两种方式都可以获取元素节点,但节点操作更简单

网页中所有内容都是节点(标签、属性、文本、注释等),在DOM中,节点使用node来表示

HTML DOM树中所有节点均可通过JavaScript进行访问

一般来讲,节点至少拥有nodeType(节点类型)、nodeName(节点名称)和nodeValue(节点值)这三个基本属性

  • 元素节点 nodeType为1
  • 属性节点 nodeType为2
  • 文本节点nodeType为3(文本节点包含文字、空格、换行等)

在实际开发中,节点操作主要操作元素节点

节点层级

利用DOM树可以把节点划分为不同的层级关系,常见的父子兄层级关系

JavaScript从零开始 学习记录(三)_第37张图片
子节点获取

parentNode.childNodes(标准)parentNode.children(非标准)

parentNode.children是一个只读属性,返回所有的子元素节点。它只返回子元素节点,其余节点不返回

虽然parentNode.children是一个非标准,但得到了各浏览器的支持,因而可以放心使用

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <!-- 节点的优点 -->
    <div>我是div</div>
    <span>我是span</span>
    <ul>
        <li>我是li</li>
        <li>我是li</li>
        <li>我是li</li>
        <li>我是li</li>
    </ul>
    <ul>
        <li>我是li</li>
        <li>我是li</li>
        <li>我是li</li>
        <li>我是li</li>
    </ul>

    <div class="box">
        <span class="erweima">x</span>
    </div>
    <script>
        var ul = document.querySelector('ul');
        // 子节点 childNodes 所有的子节点 包含 元素节点、文本节点等
        console.log(ul.childNodes);
        console.log(ul.childNodes[0].nodeType);
        console.log(ul.childNodes[1].nodeType);
        // children 获取所有的子元素节点 实际开发常用的
        console.log(ul.children);
    </script>
</body>
</html>

JavaScript从零开始 学习记录(三)_第38张图片
获取第一个子节点和最后一个子节点

parentNode.firstChild返回第一个子节点,找不到则返回null。支持所有节点

parentNode.lastChild返回最后一个子节点,找不到则返回null。支持所有节点

parentNode.firstElementChild返回第一个子元素节点,找不到则返回null

parentNode.lastElementChild返回最后一个元素节点,找不到则返回null

注意: 这两个方法有兼容性问题,IE9以上才支持

实际开发

JavaScript从零开始 学习记录(三)_第39张图片

新浪下拉菜单

应用实例:https://www.sina.com.cn/
JavaScript从零开始 学习记录(三)_第40张图片

效果

JavaScript从零开始 学习记录(三)_第41张图片

案例分析

  1. 导航栏里面的li都要有鼠标经过效果,所以需要循环注册鼠标事件
  2. 核心原理:当鼠标经过li里面的 第二个孩子 ul显示,当鼠标离开,ul隐藏

源码如下

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }

        a {
            text-decoration: none;
            font-size: 14px;
        }
        .nav {
            margin: 100px;
        }

        ul, li {
            list-style: none;
        }

        .nav>li {
            position: relative;
            float: left;
            width: 120px;
            height: 40px;
            text-align: center;
        }

        .nav li a {
            display: block;
            width: 100%;
            height: 100%;
            line-height: 40px;
            color: #333;
        }

        .nav .arrow {
            display: inline-block;
            width: 8px;
            height: 5px;
            margin: 0 0 0 5px;
            font-size: 12px;
            line-height: 13px;
            background: url(/第三阶段/img/xl.png) 0 -977px no-repeat; /* 前一个代表靠左距离值(可为正可为负),第二个数值代表靠上距离值(可为正可为负) */
        }

        .nav>li>a:hover {
            color: #ff8400;
            background-color: #EDEEF0
        }

        .nav ul {
            display: none;
            border-left: 1px solid #fecc5b;
            border-right: 1px solid #fecc5b;
        }

       .nav ul li {
            border-bottom: 1px solid #fecc5b;
       } 
       
       .nav ul li:hover {
            background: #FFF5DA;
       }
    </style>
</head>
<body>
    <ul class="nav">
        <li>
            <a href="#">
                微博
                <span class="arrow"></span>
            </a>
            <ul>
                <li>
                    <a href="">私信</a>
                </li>
                <li>
                    <a href="">评论</a>
                </li>
                <li>
                    <a href="">@我</a>
                </li>
            </ul>
        </li>
        <li>
            <a href="#">
                博客
                <span class="arrow"></span>    
            </a>
            <ul>
                <li>
                    <a href="">博客评论</a>
                </li>
                <li>
                    <a href="">未读提醒</a>
                </li>    
            </ul>
        </li>
        <li>
            <a href="#">
                邮箱
                <span class="arrow"></span>
            </a>
            <ul>
                <li>
                    <a href="">免费邮箱</a>
                </li>
                <li>
                    <a href="">VIP邮箱</a>
                </li>
                <li>
                    <a href="">企业邮箱</a>
                </li>
                <li>
                    <a href="">新浪邮箱客户端</a>
                </li>    
            </ul>
        </li>
    </ul>
    <script>
        // 获取元素
        var nav = document.querySelector('.nav');
        var lis = nav.children; // 得到3个li
        // 循环注册事件
        for (var i = 0; i < lis.length; i++) {
            lis[i].onmouseover = function() {
                this.children[1].style.display = 'block';
            }
            lis[i].onmouseout = function() {
                this.children[1].style.display = 'none';
            }
        }
    </script>
</body>
</html>

兄弟节点

node.nextSibling返回当前元素的下一个兄弟节点,找不到返回null(包含所有节点)

node.previousSibling返回当前元素上一个兄弟节点,找不到则返回null(包含所有节点)

node.nextElementSibling返回当前元素下一个兄弟元素节点,找不到则返回null

node.previousElementSibling返回当前元素上一个兄弟元素节点,找不到则返回null

注意: 这两个方法有兼容性问题,IE9以上才支持

如何解决兼容性问题

封装一个兼容性函数

function getNextElementSibling(element) {
	var el = element;
	while (el = el.nextSibling) {
		if (el.nodeType === 1) {
			return el;
		}
	}
	return null;
}

创建和添加节点

document.createElement('tagName')方法创建由tagName指定的HTML元素。因为这些元素原先不存在,是根据需求动态生成的,所以也称为动态创建元素节点

node.appendChild(child)方法将一个节点添加到指定父节点的子节点列表末尾。类似于css里面的after伪元素

node.insertBefore(child,指定元素)方法将一个节点添加到父节点的指定子节点前面。类似于css里面的before伪元素

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <ul>
        <li>123</li>
    </ul>
    <script>
        // 创建节点之元素节点
        var li = document.createElement('li');
        // 添加节点
        var ul = document.querySelector('ul');
        ul.appendChild(li);
        // 添加节点 node.insertBefore(child, 指定元素)
        var lili = document.createElement('li');
        ul.insertBefore(lili, ul.children[0]);
        // 页面添加一个新元素:1. 创建元素 2. 添加元素
    </script>
</body>
</html>

简单版发布留言

  1. 核心思路:点击按钮之后,就动态创建一个p,添加到div里面
  2. 创建p的同时,把文本域里面的值通过p.innerHTML赋值给p
  3. 如果想要新的留言后面显示就用apendChild 如果想要前面的显示就用insertBefore

效果

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>留言板</title>
    <link rel="stylesheet" href="./CSS/ly.css">
</head>
<body>
    <!-- 发布留言的主题 -->
    <div class="wrap">
        <div class="wrap-head">
            <div class="head-logo">
                <img src="/第三阶段/img/logo.png" alt="logo">
            </div>
            <div class="head-txt">
                <a class="title-txt" href="https://mp.weixin.qq.com/s/0pdLlt_754Vehg5O1_K1xw">真经亦难趣</a>
            </div>
        </div>
        <div class="main-txt">
            <textarea rows="" cols="" class="main-area"></textarea>
        </div>
        <div class="wrap-footer">
            <div class="wrap-icon">
                <ul>
                    <li>
                        <img src="/第三阶段/img/bq.png" alt="">
                        <a href="javascript:void(0)">表情</a>
                    </li>
                    <li>
                        <img src="/第三阶段/img/tp.png" alt="">
                        <a href="javascript:void(0)">图片</a>
                    </li>
                    <li>
                        <img src="/第三阶段/img/sp.png" alt="">
                        <a href="javascript:void(0)">视频</a>
                    </li>
                    <li>
                        <img src="/第三阶段/img/wz.png" alt="">
                        <a href="javascript:void(0)">文章</a>
                    </li>
                </ul>
            </div>
            <div class="wrap-footer-btn">
                <div class="release-btn">
                    <button>发布</button>
                </div>
            </div>
        </div>  
    </div>
    <!-- 显示留言主体 -->
    <div class="show">
        <div class="show-txt">
        </div>
    </div>
    <script>
        // 获取元素
        var btn = document.querySelector('button');
        var text = document.querySelector('textarea');
        var show = document.querySelector('.show');
        var showTxt = document.querySelector('.show-txt');
        var showTime = document.querySelector('.show-time');
        // 注册事件
        btn.onclick = function() {
            if (text.value == '') {
                alert('您没有输入内容');
                return false;
            } else {
                var date = new Date();
                show.style.display = 'block';
                var p = document.createElement('p');
                var span = document.createElement('span');
                var i = document.createComment('i');
                p.innerHTML = text.value + "x";
                text.value = "";
                span.innerHTML = date;
                showTxt.insertBefore(p, showTxt.children[0]);
                showTxt.insertBefore(span, showTxt.children[1]);
            }
        }
    </script>
</body>
</html>

CSS源码

* {
    margin: 0;
    padding: 0;
}

a {
    text-decoration: none;
    font-size: 14px;
}

ul {
    list-style: none;
}

/* 最外层 */
.wrap {
    width: 1000px;
    height: 245px;
    margin: 20px auto;
    border-radius: 4px;
    border: 1px solid #ddd;
    padding: 0 10px;
}

.wrap .wrap-head {
    width: 100%;
    height: 40px;
    padding-top:4px;
    overflow: hidden;
}

.wrap .wrap-head .head-logo {
    width: 40%;
    float: left;
}

.wrap .wrap-head .head-logo img {
    width: 60px;
    height: 60px;
}

.wrap .wrap-head .head-txt {
    padding: 20px 0;
    width: 60%;
    float: right;
}

.wrap .wrap-head .head-txt a {
    color: #3C97EF;
    text-align: right;
    display: block;
    width: 100%;
}

/* 内层设计,输入框 */
.wrap .main-txt {
    border: 1px solid #ccc;
    width: 99%;
    height: 125px;
    margin: 6px 0 0;
    padding: 5px;
    box-shadow: 0 0 3px 0 rgba(0, 0, 0, 0.15) inset;
}

.wrap .main-txt textarea {
    border: none;
    width: 100%;
    height: 66px;
    outline: none;
    resize: none;
    color: #333;
}

/* 下层设计 */
.wrap .wrap-footer {
    width: 100%;
    height: 40px;
    margin: 6px 0;
    overflow: hidden;
}

.wrap .wrap-footer .wrap-icon {
    width: 65%;
    float: left;
    margin-top: 10px;
}

.wrap .wrap-footer .wrap-icon ul li {
    display: inline-block;
    margin-right: 15px;
    cursor: pointer;
}

.wrap .wrap-icon a {
    font-size: 12px;
    color: #333;
    height: 20px;
    margin-left: 5px;
    display: block;
    width: 25px;
    float: right;
    line-height: 20px;
}

.wrap .wrap-footer .wrap-icon a:hover {
    color: #eb7350;
}

.wrap .wrap-footer .wrap-icon img {
    width: 20px;
    height: 20px;
}

.wrap .wrap-footer .wrap-footer-btn {
    width: 35%;
    float: right;
    overflow: hidden;
    margin-top: 5px;
}

.wrap .wrap-footer .wrap-footer-btn .release-btn {
    float: right;
}

.wrap .wrap-footer .wrap-footer-btn button {
    position: relative;
    transition: background 400ms;
    color: #fff;
    background-color: #6A84DA;
    padding: 0.2rem 1rem;
    font-size: 1.2rem;
    overflow: hidden;
    outline: 0;
    border: 0;
    border-radius: 0.25rem;
    box-shadow: 0 0 0.6rem rgba(0, 0, 0, 0.3);
    cursor: pointer;
    z-index: 1;
}

.wrap .wrap-footer .wrap-footer-btn button::before {
    content: "";
    position: absolute;
    z-index: -1;
    top: 50%;
    left: 50%;
    width: 1rem;
    height: 1rem;
    transform: translate3d(-50%,-50%,0) scale(0,0);
    border-radius: 0.4rem;
    background-color: #7886af;
    transform-origin: center;
    transition: ease-in-out .5s;
}

.wrap .wrap-footer .wrap-footer-btn button:hover::before {
    transform: translate3d(-50%,-50%,0) scale(15,15);
}


/* 后期添加的留言框 */
.show {
    width: 1000px;
    margin: 20px auto;
    display: none;
}

.show .show-txt {
    width: 100%;
    color: #444;
    border-radius: 4px;
}

.show .show-txt p {
    word-wrap: break-word;
    margin-top: 15px;
    padding-left: 15px;
    padding-right: 25px;
    border: 1px solid #ddd;
    position: relative;
}

.show .show-txt p a {
    position: absolute;
    color: #aaa;
    top: 0;
    right: 0;
}

.show .show-txt span {
    font-size: 12px;
    color: #808080;
    margin-top: 10px;
}

删除节点

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

JavaScript从零开始 学习记录(三)_第42张图片

JavaScript从零开始 学习记录(三)_第43张图片

删除留言

案例分析

  1. 当把文本域里面的值赋值给p的时候,就多添加一个删除的链接
  2. 需要把所有的链接获取过来,当点击链接的时候,删除当前链接所在的p

基于简单版发布留言案例进行修改

效果

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>留言板</title>
    <link rel="stylesheet" href="./CSS/ly.css">
</head>
<body>
    <!-- 发布留言的主题 -->
    <div class="wrap">
        <div class="wrap-head">
            <div class="head-logo">
                <img src="/第三阶段/img/logo.png" alt="logo">
            </div>
            <div class="head-txt">
                <a class="title-txt" href="https://mp.weixin.qq.com/s/0pdLlt_754Vehg5O1_K1xw">真经亦难趣</a>
            </div>
        </div>
        <div class="main-txt">
            <textarea rows="" cols="" class="main-area"></textarea>
        </div>
        <div class="wrap-footer">
            <div class="wrap-icon">
                <ul>
                    <li>
                        <img src="/第三阶段/img/bq.png" alt="">
                        <a href="javascript:void(0)">表情</a>
                    </li>
                    <li>
                        <img src="/第三阶段/img/tp.png" alt="">
                        <a href="javascript:void(0)">图片</a>
                    </li>
                    <li>
                        <img src="/第三阶段/img/sp.png" alt="">
                        <a href="javascript:void(0)">视频</a>
                    </li>
                    <li>
                        <img src="/第三阶段/img/wz.png" alt="">
                        <a href="javascript:void(0)">文章</a>
                    </li>
                </ul>
            </div>
            <div class="wrap-footer-btn">
                <div class="release-btn">
                    <button>发布</button>
                </div>
            </div>
        </div>  
    </div>
    <!-- 显示留言主体 -->
    <div class="show">
        <div class="show-txt">
        </div>
    </div>
    <script>
        // 获取元素
        var btn = document.querySelector('button');
        var text = document.querySelector('textarea');
        var show = document.querySelector('.show');
        var showTxt = document.querySelector('.show-txt');
        var showTime = document.querySelector('.show-time');
        // 注册事件
        btn.onclick = function() {
            if (text.value == '') {
                alert('您没有输入内容');
                return false;
            } else {
                var date = new Date();
                show.style.display = 'block';
                var p = document.createElement('p');
                var span = document.createElement('span');
                var i = document.createComment('i');
                p.innerHTML = text.value + '

'
+ "x"; text.value = ""; span.innerHTML = date; showTxt.insertBefore(p, showTxt.children[0]); p.appendChild(span, p.children[0]); var as = showTxt.querySelectorAll('a'); // 注册删除事件 for (var i = 0; i < as.length; i++) { as[i].onclick = function() { showTxt.removeChild(this.parentNode); } } } } </script> </body> </html>

CSS源码

* {
    margin: 0;
    padding: 0;
}

a {
    text-decoration: none;
    font-size: 14px;
}

ul {
    list-style: none;
}

/* 最外层 */
.wrap {
    width: 1000px;
    height: 245px;
    margin: 20px auto;
    border-radius: 4px;
    border: 1px solid #ddd;
    padding: 0 10px;
}

.wrap .wrap-head {
    width: 100%;
    height: 40px;
    padding-top:4px;
    overflow: hidden;
}

.wrap .wrap-head .head-logo {
    width: 40%;
    float: left;
}

.wrap .wrap-head .head-logo img {
    width: 60px;
    height: 60px;
}

.wrap .wrap-head .head-txt {
    padding: 20px 0;
    width: 60%;
    float: right;
}

.wrap .wrap-head .head-txt a {
    color: #3C97EF;
    text-align: right;
    display: block;
    width: 100%;
}

/* 内层设计,输入框 */
.wrap .main-txt {
    border: 1px solid #ccc;
    width: 99%;
    height: 125px;
    margin: 6px 0 0;
    padding: 5px;
    box-shadow: 0 0 3px 0 rgba(0, 0, 0, 0.15) inset;
}

.wrap .main-txt textarea {
    border: none;
    width: 100%;
    height: 66px;
    outline: none;
    resize: none;
    color: #333;
}

/* 下层设计 */
.wrap .wrap-footer {
    width: 100%;
    height: 40px;
    margin: 6px 0;
    overflow: hidden;
}

.wrap .wrap-footer .wrap-icon {
    width: 65%;
    float: left;
    margin-top: 10px;
}

.wrap .wrap-footer .wrap-icon ul li {
    display: inline-block;
    margin-right: 15px;
    cursor: pointer;
}

.wrap .wrap-icon a {
    font-size: 12px;
    color: #333;
    height: 20px;
    margin-left: 5px;
    display: block;
    width: 25px;
    float: right;
    line-height: 20px;
}

.wrap .wrap-footer .wrap-icon a:hover {
    color: #eb7350;
}

.wrap .wrap-footer .wrap-icon img {
    width: 20px;
    height: 20px;
}

.wrap .wrap-footer .wrap-footer-btn {
    width: 35%;
    float: right;
    overflow: hidden;
    margin-top: 5px;
}

.wrap .wrap-footer .wrap-footer-btn .release-btn {
    float: right;
}

.wrap .wrap-footer .wrap-footer-btn button {
    position: relative;
    transition: background 400ms;
    color: #fff;
    background-color: #6A84DA;
    padding: 0.2rem 1rem;
    font-size: 1.2rem;
    overflow: hidden;
    outline: 0;
    border: 0;
    border-radius: 0.25rem;
    box-shadow: 0 0 0.6rem rgba(0, 0, 0, 0.3);
    cursor: pointer;
    z-index: 1;
}

.wrap .wrap-footer .wrap-footer-btn button::before {
    content: "";
    position: absolute;
    z-index: -1;
    top: 50%;
    left: 50%;
    width: 1rem;
    height: 1rem;
    transform: translate3d(-50%,-50%,0) scale(0,0);
    border-radius: 0.4rem;
    background-color: #7886af;
    transform-origin: center;
    transition: ease-in-out .5s;
}

.wrap .wrap-footer .wrap-footer-btn button:hover::before {
    transform: translate3d(-50%,-50%,0) scale(15,15);
}


/* 后期添加的留言框 */
.show {
    width: 1000px;
    margin: 20px auto;
    display: none;
}

.show .show-txt {
    width: 100%;
    color: #444;
    border-radius: 4px;
}

.show .show-txt p {
    word-wrap: break-word;
    margin-top: 15px;
    padding-left: 15px;
    padding-right: 25px;
    border: 1px solid #ddd;
    position: relative;
}

.show .show-txt p a {
    position: absolute;
    color: #aaa;
    top: 0;
    right: 0;
}

.show .show-txt p span {
    font-size: 12px;
    color: #808080;
    margin-top: 10px;
}


复制节点

node.cloneNode()方法返回方法调用者(节点)的一个副本,该副本被称为克隆节点/拷贝节点

注意: 如果括号参数为空或false,则为浅拷贝,即只克隆复制节点本身,不克隆里面的子节点

JavaScript从零开始 学习记录(三)_第44张图片
JavaScript从零开始 学习记录(三)_第45张图片

动态生成表格

案例分析

  1. 因为表中的数据是动态的,需要JS动态生成,这里模拟数据,自己定义数据。数据采取对象形式存储
  2. 所有数据都是放到tbody中的行里面
  3. 行数对应对象数
  4. 最后一列单元格是删除,需要单独创建单元格
DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Documenttitle>
    <style>
        table {
            width: 500px;
            margin: 100px auto;
            border-collapse: collapse;
            text-align: center;
        }

        td,
        th {
            border: 1px solid #333;
        }

        thead tr {
            height: 40px;
            background-color: #ccc;
        }
    style>
head>
<body>
    <table cellspacing="0">
        <thead>
            <tr>
                <th>姓名th>
                <th>科目th>
                <th>成绩th>
                <th>操作th>
            tr>
        thead>
        <tbody>
        tbody>
    table>
    <script>
        var datas = [{
            name: '魏珞樱',
            subject: 'JavaScript',
            score: 100
        },{
            name: '弘历',
            subject: 'JavaScript',
            score: 98
        },{
            name: '傅恒',
            subject: 'JavaScript',
            score: 99
        },{
            name: '明玉',
            subject: 'JavaScript',
            score: 88
        }];
        var tbody = document.querySelector('tbody');
        for (var i = 0; i < datas.length; i++) {
            var tr = document.createElement('tr');
            tbody.append(tr);
            // 行里面创建单元格 单元格的数量取决于每个对象里面的属性个数
            for (var k in datas[i]) {
                // 创建单元格
                var td = document.createElement('td');
                // 把对象里面的属性值 给 td
                td.innerHTML = datas[i][k];
                tr.appendChild(td);
            } 
            // 创建最后一列单元格
            var td = document.createElement('td');
            td.innerHTML = '删除';
            tr.appendChild(td);
        }
        // 获取所有的 a元素
        var as = document.querySelectorAll('a');
        for (var i = 0; i < as.length; i++) {
            as[i].onclick = function() {
                // 找到 a元素的爷爷
                tbody.removeChild(this.parentNode.parentNode);
            }
        }
    script>
body>
html>

效果

在这里插入图片描述

动态创建元素

  • document.write()
  • document.innerHTML()
  • document.createElement()

注意:

document.write是直接将内容写入页面的内容流,但是文档流执行完毕,则它会导致页面全部重绘

效果

JavaScript从零开始 学习记录(三)_第46张图片

DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Documenttitle>
head>
<body>
    <button>点击button>
    <p>abcp>
    <script>
        // 三种创建元素的方式
        var btn = document.querySelector('button');
        btn.onclick = function() {
            document.write('
123
'
); }
script> body> html>

innerHTML是将内容写入某个DOM节点,不会导致页面全部重绘

innerTHML创建多个元素效率更高(不拼接字符串,采取数组形式拼接),结构稍微复杂,但效率更高

createElement()创建多个元素效率稍低一点,但结构更清晰

总结:不同浏览器下,innerHTML效率要比createElement

DOM重点核心

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

课程目标

  • 能够写出元素注册事件的两种方式
  • 能够说出删除事件的两种方式
  • 能够说出DOM事件流的三个阶段
  • 能够利用事件对象完成跟随鼠标案例
  • 能够封装阻止冒泡的兼容性函数
  • 能够说出事件委托的原理
  • 能够说出常用的鼠标和键盘事件

注册事件(绑定事件)

给元素添加事件,称为注册事件绑定事件

注册事件有两种方式:传统方式和方法监听注册方法

传统注册方式

  • 利用on开头的事件onclick
  • btn.onclick = function() {}
  • 特点:注册事件的唯一性
  • 同一个元素同一事件只能设置一个处理函数,最后注册的处理函数将会覆盖前面的注册的处理函数

方法监听注册方式

  • w3c标准 推荐方式
  • addEventListener() 它是一个方法
  • IE9之前的IE不支持此方法,可使用attachEvent()代替
  • 特点:同一个元素同一个事件可以注册多个监听器
  • 按注册顺序依次执行

eventTarget.addEventListener(type, listener[, useCapture])

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

该方法接收三个参数:

  • type: 事件类型字符串,比如click、mouseover,注意这里不要带on
  • listener: 事件处理函数,事件发生时,会调用该监听函数
  • useCapture: 可选参数,一个布尔值,默认是false

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

该方法接收两个参数:

  • eventNameWithOn: 事件类型字符串,比如onclick、onmouseover,这里带on
  • callback: 事件处理函数,当目标触发事件时回调函数被调用

兼容性处理的原则:首先照顾大多数浏览器,再处理特殊浏览器

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <button>传统注册事件</button>
    <button>方法监听注册事件</button>
    <button>ie9 attachEvent</button>
    <script>
        var btns = document.querySelectorAll('button');
        // 传统方式注册事件
        btns[0].onclick = function() {
            alert('hi');
        }
        btns[0].onclick = function() {
            alert('how are you');
        }
        // 事件监听注册事件 里面的事件类型是字符串 必定加引号
        btns[1].addEventListener('click', function() {
            alert(22);
        })
        btns[1].addEventListener('click', function() {
            alert(33);
        })
        // attachEvent ie9以前的版本支持
        btns[2].attachEvent('onclick', function() {
            alert(11);
        })
    </script>
</body>
</html>

效果
JavaScript从零开始 学习记录(三)_第47张图片

删除事件(解绑事件)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        div {
            width: 100px;
            height: 100px;
            background: pink;
        }
    </style>
</head>
<body>
    <div>1</div>
    <div>2</div>
    <div>3</div>
    <script>
        var divs = document.querySelectorAll('div');
        divs[0].onclick = function() {
            alert(11);
            // 传统方式删除事件
            divs[0].onclick = null;
        }
        divs[1].addEventListener('click', fn) // 里面的fn 不需要调用加小括号

        function fn() {
            alert(22);
            divs[1].removeEventListener('click', fn);
        }
        
        divs[2].attachEvent('onclick', fn1);
        function fn1() {
            alert(33);
            divs[2].datachEvent('onclick', fn1);
        }

    </script>
</body>
</html>

JavaScript从零开始 学习记录(三)_第48张图片

DOM事件流

事件流描述的是从页面中接收事件的顺序

事件发生时会在元素节点之间按照特定的顺序传播,这个传播过程DOM事件流

比如给一个div注册点击事件:

DOM事件流分为三个阶段:

  1. 捕获阶段
  2. 当前目标阶段
  3. 冒泡阶段

JavaScript从零开始 学习记录(三)_第49张图片

  • 事件冒泡:IE最早提出,事件开始时由最具体的元素接收,然后逐级向上传播到DOM最顶层节点的过程
  • 事件捕获:网景最早提出,由DOM最顶层节点开始,然后逐级向下传播到最具体的元素接收过程

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

JavaScript从零开始 学习记录(三)_第50张图片

DOM事件流代码验证

事件发生时会在元素节点之间按照特定的顺序传播,这个传播过程即DOM事件流

注意:

  1. JS代码中只能执行捕获或者冒泡其中的一个阶段
  2. onclick 和 attachEvent 只能得到冒泡阶段
  3. addEventListener(type, listener[, useCapture])第三个参数如果是true,表示在事件捕获阶段调用事件处理程序,如果是false(不写默认就是false),表示在事件冒泡阶段调用事件处理程序
  4. 实际开发中很少使用事件捕获,更关注事件冒泡
  5. 有些事件是没有冒泡的,比如onblur、onfoucs、onmouseenter、onmouseleave
  6. 事件冒泡有利有弊
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .father {
            overflow: hidden;
            width: 300px;
            height: 300px;
            margin: 100px auto;
            background-color: pink;
            text-align: center;
        }
        
        .son {
            width: 200px;
            height: 200px;
            margin: 50px;
            background-color: purple;
            line-height: 200px;
            color: #fff;
        }
    </style>
</head>
<body>
    <div class="father">
        <div class="son">son盒子</div>
    </div>
    <script>
        // 捕获阶段 document -> html -> body -> father -> son
        var son = document.querySelector('.son');
        son.addEventListener('click', function() {
            alert('son');
        }, true)
        var father = document.querySelector('.father');
        father.addEventListener('click', function(){
            alert('father');
        }, true)
        // 冒泡阶段
        var son = document.querySelector('.son');
        son.addEventListener('click', function() {
            alert('son');
        }, false)
        var father = document.querySelector('.father');
        father.addEventListener('click', function(){
            alert('father');
        }, false)
        document.addEventListener('click', function() {
            alert('document');
        }, false)
    </script>
</body>
</html>

效果

JavaScript从零开始 学习记录(三)_第51张图片

事件对象

官方释义:event对象代表事件的状态,比如键盘按键的状态、鼠标的位置、鼠标按钮的状态

简单理解:事件发生后,跟事件相关的一系列信息数据的集合都放到这个对象里面,这个对象就是事件对象event,它有很多属性和方法

比如:

  1. 谁绑定了这个事件
  2. 鼠标触发事件的话,会得到鼠标的相关信息,如鼠标位置
  3. 键盘触发事件的话,会得到键盘的相关信息,如按了哪个键

这个event是个形参,系统帮助我们设定为事件对象,不需要传递实参过去

当注册事件时,event对象就会被系统自动创建,并依次传递给事件监听器(事件处理函数)

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

  • 标准浏览器中时浏览器给方法传递参数,只要定义形参e就可以获取到
  • 在IE6~8中,浏览器不会给方法传递参数;如果需要的话,需要到window.event中获取参数

解决:e = e || window.event;

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div>123</div>
    <script>
        // 事件对象
        var div = document.querySelector('div');
        // 事件对象 是 事件的一系列相关数据的集合 跟事件相关 比如鼠标点击里面就包含了鼠标的相关信息,如鼠标坐标;如果是键盘事件,里面就包含键盘的相关信息,如判断用户按下了那个键
        div.onclick = function(event) {
            console.log(event);
        }
        // 事件对象名称可自定义
        div.addEventListener('click', function(e) {
            console.log(e);
        })
        // 事件对象也是有兼容性问题的
    </script>
</body>
</html>
事件对象属性方法 说明
e.target 返回触发事件的对象 标准
e.srcElement 返回触发事件的对象 非标准 ie6~8使用
e.type 返回事件的类型 比如click mouseover 不带on
e.cancelBubble 该属性阻止冒泡 非标准 ie6~8使用
e.returnValue 该属性 阻止默认事件(默认行为)非标准 ie6~8使用 比如不让链接跳转
e.preventDefault() 该方法 阻止默认事件(默认行为)标准 比如不让链接跳转
e.stopPropagation() 阻止冒泡 标准
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        div {
            height: 100px;
            width: 100px;
            background: pink;
        }
    </style>
</head>
<body>
    <div>123</div>
    <ul>
        <li>abc</li>
        <li>abc</li>
        <li>abc</li>
    </ul>
    <script>
        // 常见事件对象的属性和方法
        var div = document.querySelector('div');
        // e.target 返回的是触发事件对象(元素)this 返回的是绑定事件对象(元素)
        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.target);
        })
        // 了解兼容性
        // div.onclick = function(e) {
        //     e = e || window.event;
        //     var target = e.target || e.srcElement;
        //     console.log(target);
        // }
    </script>
</body>
</html>

阻止默认行为

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div>123</div>
    <a href="https://www.baidu.com">百度</a>
    <form action="https://www.baidu.com">
        <input type="submit" value="提交" name="sub">
    </form>
    <script>
        // 返回事件类型
        var div = document.querySelector('div');
        div.addEventListener('click', fn);
        div.addEventListener('mouseover', fn);
        div.addEventListener('mouseout', fn);
        function fn(e) {
            console.log(e.type);
        }
        // 阻止默认行为(事件)让链接不跳转 或 让提交按钮先不提交
        var a = document.querySelector('a');
        a.addEventListener('click', function(e) {
            e.preventDefault();
        })
        a.onclick = function(e) {
            // 普通浏览器 e.preventDefault(); 方法
            // e.preventDefault();
            // 低版本浏览器 ie6~8 returnValue 属性
            // e.returnValue;
            // 可以利用 return false 来阻止默认行为 无兼容性问题 只限于传统注册方式
            return false;
        }
    </script>
</body>
</html>

阻止事件冒泡

事件冒泡:开始时由最具体元素接收,然后逐级向上传播到DOM最顶层节点
事件冒泡本身的特性:有利有弊

阻止事件冒泡

  • 标准写法:利用事件对象里面的stopProgation()方法
  • 非标准写法:IE6~8 利用事件对象cancelBubble属性
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .father {
            overflow: hidden;
            width: 300px;
            height: 300px;
            margin: 100px auto;
            background-color: pink;
            text-align: center;
        }
        
        .son {
            width: 200px;
            height: 200px;
            margin: 50px;
            background-color: purple;
            line-height: 200px;
            color: #fff;
        }
    </style>
</head>
<body>
    <div class="father">
        <div class="son">son盒子</div>
    </div>
    <script>
        // 冒泡阶段
        var son = document.querySelector('.son');
        son.addEventListener('click', function(e) {
            alert('son');
            e.stopPropagation(); 
        }, false)
        var father = document.querySelector('.father');
        father.addEventListener('click', function(){
            alert('father');
        }, false)
        document.addEventListener('click', function() {
            alert('document');
        }, false)
    </script>
</body>
</html>

事件委托

事件冒泡本身的特性,会带来坏处,也会带来好处,需要灵活掌握

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

事件委托的原理

不是每个子节点单独设置事件监听器,而是事件监听器设置在其父节点上,然后利用冒泡原理影响设置每个子节点

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

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <ul>
        <li>知否知否,点我应有弹框在手!</li>
        <li>知否知否,点我应有弹框在手!</li>
        <li>知否知否,点我应有弹框在手!</li>
        <li>知否知否,点我应有弹框在手!</li>
        <li>知否知否,点我应有弹框在手!</li>
    </ul>
    <script>
        // 事件委托的核心原理:给父节点添加监听器,利用事件冒泡影响每一个子节点
        var ul = document.querySelector('ul');
        ul.addEventListener('click', function(e) {
            alert('知否知否,点我应有弹框在手!');
            e.target.style.background = 'pink';
        })
    </script>
</body>
</html>

常用鼠标事件

禁止鼠标右键菜单

contextmenu主要控制应该何时显示上下文菜单,主要用于程序员取消默认的上下文菜单

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    我是一段不愿意分享的文字
    <script>
        // 禁用右键菜单
        document.addEventListener('contextmenu', function(e) {
            e.preventDefault();
        })
        // 禁止选中文字
        document.addEventListener('selectstart', function(e) {
            e.preventDefault();
        })
    </script>
</body>
</html>

获得鼠标在页面中的坐标

event对象代表事件的状态,跟事件相关的一系列信息的集合。现阶段主要用鼠标事件对象MouseEvent和键盘事件对象KeyboardEvent

鼠标事件对象 说明
e.clientX 返回鼠标相对于浏览器窗口可视区的X坐标
e.clientY 返回鼠标相对于浏览器窗口可视区的Y坐标
e.pageX 返回鼠标相对于文档页面的X坐标 IE9+ 支持
e.pageY 返回鼠标相对于文档页面的Y坐标 IE9+ 支持
e.screenX 返回鼠标相对于电脑屏幕的X坐标
e.screenY 返回鼠标相对于电脑屏幕的Y坐标
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        // 鼠标事件对象 MouseEvent
        document.addEventListener('click', function(e) {
            console.log(e);
            // client 鼠标在可视区的x和y坐标
            console.log(e.clientX);
            console.log(e.clientY);
            console.log('--------------------');
            // page 鼠标在页面文档的x和y坐标
            console.log(e.pageX);
            console.log(e.pageY);
            console.log('-------------------');
            // screen 鼠标在电脑屏幕的x和y坐标
            console.log(e.screenX);
            console.log(e.screenY);
        })
    </script>
</body>
</html>

跟随鼠标的天使

案例分析

  1. 鼠标不断的移动,使用鼠标移动事件:mousemove
  2. 在页面中移动,给document注册事件
  3. 图片要移动距离,而且不占位置,使用绝对定位即可
  4. 核心原理:每次鼠标移动,都会获得最新的鼠标坐标,把这个x和y坐标作为图片的top和left值就可以移动图片了
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        img {
            position: absolute;
        }
    </style>
</head>
<body>
    <img src="/第三阶段/img/angel.gif" alt="">
    <script>
        var pic = document.querySelector('img');
        document.addEventListener('mousemove', function(e) {
            var x = e.pageX;
            var y = e.pageY;
            console.log('x坐标是' + x, 'y坐标是' + y);
            // 坐标单位莫忘添
            pic.style.left = x - 45 + 'px';
            pic.style.top = y - 40 + 'px';
        });
    </script>
</body>
</html>

效果
JavaScript从零开始 学习记录(三)_第52张图片

常用键盘事件

事件除了使用鼠标触发,还可以使用键盘触发

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

注意:

  1. 如果使用addEventListener不需要加on
  2. onkeypress和前面2个的区别是:不识别功能键,如左右箭头、shift等
  3. 三个事件的执行顺序:keydown --> keypress --> keyup
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        // keyup 按键弹起时触发
        document.addEventListener('keyup', function() {
            console.log('我弹起了');
        })
        // keydown 按键按下时触发
        document.addEventListener('keydown', function() {
            console.log('我按下了down');
        })
        // keypress 按键按下时触发
        document.addEventListener('keypress', function() {
            console.log('我按下了press');
        })
    </script>
</body>
</html>

键盘事件对象

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

注意: onkeydown 和 onkeyup 不区分字母大小写,onkeypress区分字母大小写

以下是搬运@梦里逆天 博主 所列出的按键与之对应的ASCII值

字母和数字键的键码值(keyCode)
按键 键码 按键 键码 按键 键码 按键 键码
A 65 J 74 S 83 1 49
B 66 K 75 T 84 2 50
C 67 L 76 U 85 3 51
D 68 M 77 V 86 4 52
E 69 N 78 W 87 5 53
F 70 O 79 X 88 6 54
G 71 P 80 Y 89 7 55
H 72 Q 81 Z 90 8 56
I 73 R 82 0 48 9 57
数字键盘上的各键键码值(keyCode) 功能键键码值(keyCode)
按键 键码 按键 键码 按键 键码 按键 键码
0 96 8 104 F1 112 F9 120
1 97 9 105 F2 113 F10 121
2 98 * 106 F3 114 F11 122
3 99 + 107 F4 115 F12 123
4 100 Enter 108 F5 116    
5 101 - 109 F6 117    
6 102 . 110 F7 118    
7 103 / 111 F8 119    
控制键键码值(keyCode)
按键 键码 按键 键码 按键 键码 按键 键码
BackSpace 8 Esc 27 Right Arrow 39 -_ 189
Tab 9 Spacebar 32 Dw Arrow 40 .> 190
Clear 12 Page Up 33 Insert 45 /? 191
Enter 13 Page Down 34 Delete 46 `~ 192
Shift 16 End 35 Num Lock 144 [{ 219
Control 17 Home 36 ;: 186 \| 220
Alt 18 Left Arrow 37 =+ 187 ]} 221
Cape Lock 20 Up Arrow 38 ,< 188 '" 222
多媒体键码值(keyCode)
按键 键码 按键 键码
音量加 175 浏览器 172
音量减 174 邮件 180
停止 179 搜索 170
静音 173 收藏 171
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        // 键盘事件对象中的keyCode属性可以得到相应键的ASCII码值
        // keyup 和 keydown 事件不区分字母大小写 a 和 A 得到的都是65
        document.addEventListener('keyup', function(e) {
            console.log('up:' + e.keyCode);
            if (e.keyCode === 65) {
                alert('您按下了a键')
            } else {
                alert('您没有按下a键')
            }
        })
        document.addEventListener('keypress', function(e) {
            console.log('press:' + e.keyCode);
        })
    </script>
</body>
</html>

效果

JavaScript从零开始 学习记录(三)_第53张图片

注意:

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

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

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

JavaScript从零开始 学习记录(三)_第54张图片

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <input type="text">
    <script>
        var search = document.querySelector('input');
        document.addEventListener('keyup', function(e) {
            if (e.keyCode === 83) {
                search.focus();
            }
        })
    </script>
</body>
</html>

模拟京东快递单号查询

案例分析

JavaScript从零开始 学习记录(三)_第55张图片
注意: keydown和keypress在文本框里面的特点:两个事件触发的时候,文字还没有落入文本框中

应用实例:

JavaScript从零开始 学习记录(三)_第56张图片
效果:

JavaScript从零开始 学习记录(三)_第57张图片

源码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }
        
        .search {
            position: relative;
            width: 178px;
            margin: 100px;
        }
        
        .con {
            display: none;
            position: absolute;
            top: -40px;
            width: 171px;
            border: 1px solid rgba(0, 0, 0, .2);
            box-shadow: 0 2px 4px rgba(0, 0, 0, .2);
            padding: 5px 0;
            font-size: 18px;
            line-height: 20px;
            color: #333;
        }
        
        .con::before {
            content: '';
            width: 0;
            height: 0;
            position: absolute;
            top: 28px;
            left: 18px;
            border: 8px solid #000;
            border-style: solid dashed dashed;
            border-color: #fff transparent transparent;
        }  
    </style>
</head>
<body>
    <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');
        jd_input.addEventListener('keyup', function() {
            // console.log('输入内容啦');
            if (this.value == '') {
                con.style.display = 'none';
            } else {
                con.style.display = 'block';
                con.innerText = this.value;
            }
        })
        // 当失去焦点,就隐藏这个con盒子
        jd_input.addEventListener('blur', function() {
            con.style.display = 'none';
        })
        // 获得焦点,就显示这个con盒子
        jd_input.addEventListener('focus', function() {
            if (this.value !== '') {
                con.style.display = 'block';
            }
        })
    </script>
</body>
</html>

课程目标

  • 能够说出什么是BOM
  • 能够知道浏览器的顶级对象window
  • 能够写出页面加载事件以及注意事项
  • 能够写出两种定时器函数并说出区别
  • 能够说出JS执行机制
  • 能够使用location对象完成页面之间的跳转
  • 能够知晓navigator对象涉及的属性
  • 能够使用history提供的方法实现页面刷新

BOM概述

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

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

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

JavaScript从零开始 学习记录(三)_第58张图片

BOM比DOM更大且包含DOM

JavaScript从零开始 学习记录(三)_第59张图片

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

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

在调用的时候可以省略window,前面学习的对话框都属于window对象方法,如alert()、prompt()等

注意: window下的一个特殊属性window.name

窗口加载事件

window.onload = function() {}window.addEventListener('load', function(){});

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

注意:

  • 有了window.onload就可以把JS代码写到页面元素的上方,因为onload是等页面内容全部加载完毕,再去执行处理函数
  • window.onload传统注册事件方式只能写一次,如果有多个,以最后一个window.onload为准
  • 如果使用addEventListener没有限制
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <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加载完毕,不包含图片 flash css 等就可以执行 加载速度快于load
    </script>
    <button>点击</button>
</body>
</html>

document.addEventListener('DOMContentLoaded', function() {})

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

IE9以上支持

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

调整窗口大小事件

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

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

注意

  • 只要窗口大小发生像素变化,就会触发这个事件
  • 经常利用这个事件完成响应式布局。window.innerWidth 当前屏幕的宽带
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        div {
            width: 200px;
            height: 200px;
            background: pink;
        }
    </style>
</head>
<body>
    <script>
        window.addEventListener('load', function() {
            var div = document.querySelector('div');
            window.addEventListener('resize', function() {
                console.log('变化了');
                if (window.innerWidth <= 800) {
                    div.style.display = 'none';
                }
            })
        })
    </script>
    <div></div>
</body>
</html>

定时器

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

  • setTimeout()
  • setInterval()

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

setTimeout()方法用于设置一个定时器,该定时器在到点儿后执行调用函数

** 注意**

  • window可以省略
  • 调用函数可以直接写函数或者函数名
  • 延迟的毫秒数默认为0,如果写,必须是毫秒
  • 定时器可能有很多,经常给定时器赋值一个标识符
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        // setTimeout 在调用时可以省略
        // 延时时间单位是毫秒,但可以省略,如果省略默认为0
        // 页面中可能有很多定时器,因而给定时器加标识符
        setTimeout(function() {
            console.log('时间到了');
        }, 2000)
        function callback() {
            console.log('爆炸了');
        }
        var timer1 = setTimeout(callback, 3000);
        var timer2 = setTimeout(callback, 5000);
    </script>
</body>
</html>

回调函数

setTimeout()这个调用函数也称为回调函数callback

普通函数是按照代码顺序直接调用,而这个函数,需要等待时间,时间到了才去调用这个函数,因此称为回调函数

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <img src="/第三阶段/img/ad.jpg" alt="广告" class="ad">
    <script>
        var ad = document.querySelector('.ad');
        setTimeout(function() {
            ad.style.display = 'none';
        }, 5000)
    </script>
</body>
</html>

清除定时器

window.clearTimeout(timeoutID)

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

注意

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

效果

JavaScript从零开始 学习记录(三)_第60张图片

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <button>点击停止定时器</button>
    <script>
        var btn = document.querySelector('button');
        var timer = setTimeout(function() {
            alert('爆炸了');
        }, 5000)

        btn.addEventListener('click', function() {
            clearTimeout(timer);
        })
    </script>
</body>
</html>

setInterval

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

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

注意

  • window可以省略
  • 这个调用函数可以直接写函数或函数名
  • 间隔的毫秒数省略默认是0,如果写,必须是毫秒,表示每隔多少毫秒就自动调用这个函数
  • 定时器可能有很多,经常给定时器赋值一个标识符
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        setInterval(function() {
            console.log('继续输出');
        }, 1000)
        // setTimeout 延时时间到了,就去调用这个回调函数,只调用一次 就结束了这个定时器
        // setInterval 每隔一个延时时间,就去调用这个回调函数,会调用很多次,重复调用这个函数
    </script>
</body>
</html>

定时器

案例分析

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

应用实例

https://www.jd.com/

JavaScript从零开始 学习记录(三)_第61张图片

效果

JavaScript从零开始 学习记录(三)_第62张图片

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>倒计时</title>
    <style>
        div {
            margin: 200px;
        }
        
        span {
            display: inline-block;
            width: 40px;
            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>
        // 获取元素
        var hour = document.querySelector('.hour'); 
        var minute = document.querySelector('.minute');
        var second = document.querySelector('.second');
        var inputTime = +new Date('2023-3-19 18:00:00'); // 返回用户输入时间总的毫秒数
        countDown();
        // 开启定时器
        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;
            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;
        }

    </script>
</body>
</html>

清除定时器

效果

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <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;
        begin.addEventListener('click', function() {
            timer = setInterval(function() {
                console.log('ni hao ma');
            }, 1000)
        })
        stop.addEventListener('click', function() {
            clearInterval(timer);
        })
    </script>
</body>
</html>

发送短信案例

案例分析

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

效果

JavaScript从零开始 学习记录(三)_第63张图片

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    手机号码:<input type="number"> <button>发送</button>
    <script>
        var btn = document.querySelector('button');
        var time = 5;
        btn.addEventListener('click', function() {
            btn.disabled = true;
            var timer = setInterval(function() {
                if (time == 0) {
                    // 清除定时器和复原按钮
                    clearInterval(timer);
                    btn.disabled = false;
                    btn.innerHTML = '发送';
                    time = 5;
                } else {
                    btn.innerHTML = '还剩下' + time + '秒'
                    time--; 
                }
            },1000)
        })
    </script>
</body>
</html>

this指向问题

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <button>点击</button>
    <script>
        // 全局作用域或普通函数中this指向全局对象window
        console.log(this);

        function fn() {
            console.log(this);
        }

        fn();

        window.setTimeout(function() {
            console.log(this);
        }, 1000)

        // 方法调用中谁调用this就指向谁
        var o = {
            sayHi: function() {
                console.log(this);
            }
        }

        o.sayHi();
        var btn = document.querySelector('button');
        btn.onclick = function() {
            console.log(this);
        }

        // 构造函数中this指向构造函数的实例
        function Fun() {
            console.log(this);
        }
        var fun = new Fun();
    </script>
</body>
</html>

JS的同步和异步

JS是单线程

JavaScript语言的一大特点就是单线程,即同一个时间只能做一件事。这是因为JavaScript这门脚本语言诞生的使命所致——JavaScript是为处理页面中用户的交互,以及操作DOM而诞生的。如对某个DOM元素进行添加和删除操作,不能同时进行,应先进行添加,之后再删除

单线程就意味着,所有任务需要排队,前一个任务结束,后一个任务才执行,这样导致的问题就是:如果JS执行时间较长,这样就会造成页面渲染不连贯又或者页面渲染加载阻塞

利用多核CPU计算能力,HTML5提出Web worker标准,允许JavaScript脚本创建多个线程,于是,JS中出现了同步和异步

同步

前一个任务结束后再执行后一个任务,程序的执行顺序与任务的排列顺序是一致的、同步的

异步

在做一件事情时,因为这件事情花费很长时间,在做这件事的同时,还可以去处理其他事情

本质区别:在流水线上各个流程执行顺序不同

同步任务

同步任务都在主线程上执行,形成一个执行栈

异步任务

JS的异步是通过回调函数实现的

一般而言,异步任务有以下三种类型:

  • 普通事件,如click、resize等
  • 资源加载,如load、error等
  • 定时器,包括setInterval、setTimeout等

异步任务相关回调函数添加到任务队列中(任务队列也称为消息队列)

JS执行机制

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

JavaScript从零开始 学习记录(三)_第64张图片
JavaScript从零开始 学习记录(三)_第65张图片

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

location对象

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

统一资源定位符(Uniform Resource Locator,URL)是互联网上标准资源的地址。互联网上的每个文件都有一个唯一的URL,包含的信息指出文件的位置以及浏览器应该怎么处理它

URL的一般语法格式为

protocol://host[:port]/path/[?query]#fragment

实例

http://www.itcast.cn/index.html?name=andy&age=18#link

组成 说明
protocol 通信协议 常用的http、ftp、maito等
host 主机(域名)
port 端口号 可选 省略时使用方案的默认端口 如http的默认端口为80
path 路径 由零或多个’/'符号隔开的字符串,一般用来表示主机上的一个目录或文件地址
query 参数 以键值对的形式,通过&符号分隔开来
fragment 片段 #后面内容 常见于链接 锚点
location对象属性 返回值
location.href 获取或设置 整个URL
location.host 返回主机(域名)
location.port 返回端口号 如果未写返回 空字符串
location.pathname 返回路径
location.search 返回参数
location.hash 返回片段 #后面内容 常见于链接 锚点

登录跳转

效果

JavaScript从零开始 学习记录(三)_第66张图片

DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Documenttitle>
head>
<body>
    <form action="index.html">
        用户名:<input type="text" name="uname">
        <input type="submit" value="登录">    
    form>
body> 
html>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div></div>
    <script>
        // 先去掉? substr('起始的位置', 截取几个字符)
        var params = location.search.substr(1);
        console.log(location.search);
        // 利用=把字符串分割为数组split('=')
        var arr = params.split('=');
        console.log(arr[1]);
        var div = document.querySelector('div');
        // 把数据写入到div中
        div.innerHTML = arr[1] + ' 欢迎您';
    </script>
</body>
</html>

location常见方法

location对象方法 返回值
location.assign() 跟href一样,可以跳转页面(也称为重定向页面)
location.replace() 替换当前页面,因为不记录历史,所以不能后退页面
location.reload() 重新加载页面,相当于刷新按钮或f5 如果参数为true 强制刷新 ctrl+f5
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <button>点击</button>
    <script>
        var btn = document.querySelector('button');
        btn.addEventListener('click',function() {
            // 记录浏览历史
            // location.assign('https://www.itcast.cn');
            // 不记录浏览历史
            // location.replace('https://www.itcast.cn');
            location.reload(true);
        })
    </script>
</body>
</html>

navigator对象

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

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

history对象

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

history对象方法 作用
back() 可以后退功能
forward() 前进功能
go(参数) 前进后退功能 参数如果是1 前进1个页面 如果是-1 后退1个页面
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <a href="Hlist.html">点击我前往列表页</a>
    <button>前进</button>
    <script>
        var btn = document.querySelector('button');
        btn.addEventListener('click', function() {
            // history.forward();
            history.go(1);
        })
    </script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <a href="Hindex.html">点击我前往首页</a>
    <button>后退</button>
    <script>
        var btn = document.querySelector('button');
        btn.addEventListener('click', function() {
            // history.back();
            history.go(-1);
        })
    </script>
</body>
</html>

结语

终于学完了这部分内容,进度虽然缓慢,但还好效果还是可以的,之后就放慢看视频进度,研究研究油猴脚本书写

我知道世界是多元的,因而想用一生去证实,人间是否留有我驻足之地

你可能感兴趣的:(JavaScript,javascript,学习,前端)