加载页面中...
07-08DOM和BOM | lwstkhyl

07-08DOM和BOM

js基础第二部分:DOM对象、定时器、事件和BOM对象

写在前面:本篇是对之前我的txt版笔记的总结汇总,基于b站课程黑马程序员前端JavaScript入门到精通(例子中使用constlet的部分)以及尚硅谷JavaScript基础&实战(例子中使用var的部分)

DOM

DOM对象:浏览器根据HTML标签生成的js对象,包括所有的标签属性;document对象:是DOM里提供的对象,用来访问和操作页面内容,网页的所有内容都在其中

注意:浏览器加载页面时,按照自上而下执行代码。如果将<script>标签写到<body>上面,在代码执行时,页面还没加载(元素没被创建),代码无法获取到元素,可能会发生错误。因此一般都将<script>标签写到<body>下面

获取DOM对象

根据CSS选择器
  • dom.querySelector("CSS选择器")表示在dom元素中选择第一个符合CSS选择器的元素

  • dom.querySelectorAll("CSS选择器")表示在dom元素中选择所有符合CSS选择器的元素

一般情况下都是在整个页面中选择,因此常使用document.querySelector("CSS选择器")document.querySelectorAll("CSS选择器")。以下都用document.来指代dom对象

const box = document.querySelector('div'); //选择第一个div标签,若没有选择到则返回null
const boxs = document.querySelectorAll('div'); //选择所有的div标签,以NodeList伪数组的形式返回

NodeList:有长度和索引,但没有pop和push等方法,可以进行使用与数组相同的方法进行遍历操作

get系列方法
document.getElementById('a'); //获取第一个id为a的元素
document.getElementsByClassName('a'); //获取页面中所有类名为a的元素
document.getElementsByTagName('div'); //获取页面中所有div标签元素

操作元素内容

  • 对象.innerText属性该属性只操作于纯文本,不会解析HTML标签

    console.log(box.innerText); //获取文字内容
    box.innerText = "修改box里面的内容"; //直接进行修改
    
  • 对象.innerHTML属性该属性会解析HTML标签

    <div class="box">内容</div>
    <script>
        const box = document.querySelector('.box');
        console.log(box.innerHTML); //内容
        box.innerHTML = "<strong>更改内容</strong>"; //会发现有加粗的效果
    </script>
    

操作元素属性

标签属性

指标签内自带的属性,如href、title、src等

对象.属性 = 值

const img = document.querySelector('img');
img.src = "new.png";
img.title = "新图片";

例:页面刷新时随机更换图片

const img = document.querySelector('img');
const max = 6, min = 1;
const random = Math.floor(Math.random() * (max - min + 1) + min);
img.src = `${random}.png`;
样式属性

指在CSS中可以更改的属性

对象.style.样式属性 = 值

const box = document.querySelector(".box");
box.style.width = "200px"; //注意长度单位要写px
box.style.border = '5px dashed black';

对于属性中有“-”的情况,有两种解决方案:

  • 将属性写成驼峰命名形式:box.style.backgroundColor

  • 使用[]来根据key取value:box.style["background-color"]

例:设置整个页面的背景图片

document.body.style.backgroundImage = 'url(xxx.png)';
类属性

修改某个元素的类名,适用于修改样式较多的情况

对象.className = '类名'

<style>
    .new_div{
        /*要修改的CSS样式*/
    }
</style>
<body>
    <div class="old_div">div</div>
</body>
<script>
    const div = document.querySelector("div"); //获取元素
    div.className = 'new_div'; //给div新的类名,并覆盖前面的类样式
</script> 

如果想继承之前的类名,在之前类CSS样式基础上增加新属性,就需要写成div.className = 'old_div new_div'形式,很不方便

通过classList控制类名,解决className属性易覆盖的问题:

const div = document.querySelector("div"); //获取元素
div.classList.add('new_div'); //增加类名,相当于div.className = 'old_div new_div'
div.classList.remove('new_div'); //删除类名
div.classList.toggle('old_div'); //切换类名,如果div已经有了old_div就将其删去,没有就把它加上
尺寸及位置属性
  • client系列获取元素宽高(不包括border、margin和滚动条,只包括content和padding):clientWidth/clientHeight,得到的是数值型(单位为px,下同),只读

    const div = document.querySelector('.scroll');
    console.log(div.clientWidth); //获取元素宽度
    console.log(div.clientHeight); //获取元素高度
    
  • offset系列

    • 获取元素尺寸(包括content、padding、border和滚动条):offsetWidth/offsetHeight

    • 获取元素位置(距最近有定位的祖先元素的左/上距离):offsetLeft/offsetTop

    数值型,只读,使用方式同上

    有定位的祖先元素:使用相对/绝对定位的祖先元素,如果该元素没有这样的父级元素,offsetLeft/offsetTop指的就是与页面左侧/顶部的距离

  • scroll系列:scrollTopscrollLeft表示元素被卷去的距顶部/左边的距离

    卷去:滚动条下拉,元素块上移,此时元素顶部会被覆盖(不可见,被卷入页面上方)一段距离,该距离就是卷去的距离

    const div = document.querySelector('.scroll');
    console.log(div.scrollTop); //div元素内的滚动距离
    console.log(document.documentElement.scrollTop); //整个页面的滚动距离
    //这里写法特殊,不是window.scrollTop
    

    数值型、可读写的(赋值的时候也是直接给数字)

    滚动到顶部document.documentElement.scrollTop = 0;window.scrollTo(0,0);


    注意:使用更改document.documentElement.scrollTop的方法设置页面位置时,不能:

    let n = document.documentElement.scrollTop;  
    n = 200;   
    

    只能:

    document.documentElement.scrollTop=200;
    
  • 元素的getBoundingClientRect()方法:返回元素的宽高以及相对于视口(浏览器窗口边框)的位置,如

    const div = document.querySelector('div');
    console.log(div.getBoundingClientRect());
    

    返回一个DOMRect对象,它的属性包括:

    • width元素宽度

    • height元素高度(不包括border和margin,只包括content和padding)

    • top元素顶部与视口顶部距离

    • left元素左边与视口左边距离(可以为负数,表示部分元素被遮盖)

    数值型,只读

表单属性
<body>
    <input type="text">
</body>
<script>
    const input = document.querySelector('input');
    console.log(input.value); //获取表单里面的值
    input.value = "新值"; //修改表单里面的数据
    input.type = 'password'; //修改表单属性
</script> 

对于表单中添加后有效果、移除后无效果的属性(如disabled checked等),用bool值表示,true表示添加、false表示移除

<body>
    <input type="checkbox">
</body>
<script>
    const input = document.querySelector('input');
    console.log(input.checked); //判断是否勾选
    input.checked = true; //改变勾选状态
</script> 
<body>
    <button>
</body>
<script>
    const btn = document.querySelector('button');
    console.log(btn.disabled); //按钮是否禁用--为true禁用,为false不禁用(默认)
    btn.disabled = true; //禁用按钮
</script> 
自定义属性

标签中以data-开头的属性,如<div data-id="1" data-sm="a">1</div>

对象.dataset.自定义属性名

const one = document.querySelector('div');
console.log(one.dataset); //输出该标签里面所有的自定义属性(键值对形式)
console.log(one.dataset.id); //获取自定义属性data-id
one.dataset.id = "new"; //改变自定义属性data-id

定时器

循环执行定时器

创建

setInterval(函数,间隔时间)间隔时间单位为ms,表示隔多长时间执行一次传入函数,返回一个id数字,标记页面中定时器函数序列。打开网页时不会立即执行,而是等待间隔时间后开始第一次执行

有两种传入函数的方式:

  • setInterval(函数名,间隔时间)(常用)

  • setInterval('函数名()',间隔时间)

function func() {
    console.log("执行了func函数");
}
setInterval(func, 1000); //开启定时器
setInterval('func()', 1000); //也可以

如果需要传参,就用函数嵌套的方式:

function func(content) {
    console.log(content);
}
let cont = "abc";
setInterval(function () {
    func(cont);
}, 1000);
暂停

clearInterval(timer_id)其中timer_id为setInterval函数返回的id数字

let timer_1 = setInterval(func, 1000); //注意此处不能声明为const,因为后面开启定时器时要对timer_1重新赋值
let timer_2 = setInterval(func, 1500);
console.log(timer_1, timer_2); //1  2
clearInterval(timer_1); //关闭timer_1定时器
clearInterval(timer_2);
timer_2 = setInterval(func, 1500); //开启timer_2定时器  
console.log(timer_2); //3  注意这里不是1,timer_id不是页面中正在运行几个定时器,而是总共启动了几次定时器

例:倒计时结束后可点击按钮

<body>
    <!-- 开始时要把按钮禁用 -->
    <button disabled></button>
</body>
<script>
    const btn = document.querySelector('button');
    let time = 5; //初始值
    btn.innerHTML = `我已阅读用户协议(${time})`;
    let timer = setInterval(function () {
        time--;
        btn.innerHTML = `我已阅读用户协议(${time})`;
        if (time === 0) {
            btn.disabled = false;
            clearInterval(timer); //关闭定时器
            btn.innerHTML = "我已阅读用户协议";
        }
    }, 1000); //每隔1秒更新一次
</script>

注意if函数一定要写到定时器函数里面,因为这个判断语句也是要循环运行的。如果写在外面,就只会在最开始执行一次,此时time=5,不会停止定时器

延时函数

setTimeout(回调函数,等待的毫秒数)创建,只执行一次,表示等待多少秒后执行回调函数,不会像setInterval()一直执行,返回定时器id

清除延时函数:clearTimeout(定时器id)

let timer = setTimeout();  
clearTimeout(timer);

一般情况下都不需要清除(因为它只执行一次),特殊情况(如递归调用延时函数)时需要清除

注意:延时函数后面的代码会先执行(就算延时时间设为0),因为延时函数内的回调函数需等待一段时间才执行

let timer = setTimeout(function () {
    console.log("调用setTimeout");
},0);
console.log("hello");  //先"hello"再"调用setTimeout"

事件

常用事件种类:

  • 鼠标事件–click点击 mouseenter鼠标经过 mouseleave鼠标离开

  • 焦点事件–focus获得焦点 blur失去焦点

    鼠标移入输入框时出现光标(获得焦点),鼠标移出时光标消失(失去焦点)

    常见的应用:鼠标移入搜索框时,出现下拉栏用于快捷输入

  • 键盘事件–keydown按下按键(按下时会一直发送keydown事件信号) keyup抬起按键

  • 文本事件–input用户向表单输入信息,当文本框中内容改变时触发

  • 页面事件–scroll页面滚动

事件监听

元素对象.addEventListener('事件类型',要执行的函数)

三要素:

  • 事件源–哪个dom元素被触发了,即上面的元素对象

  • 事件类型–用什么方式触发(click等)

  • 事件调用的函数–触发后要做什么

例如:

const btn = document.querySelector("button");
btn.addEventListener('click', function () {
    alert("点击了按钮");
});
btn.addEventListener('mouseover', function () {
    console.log("鼠标经过按钮");
});

以前的写法:btn.onclick = function(){...}

缺点:如果一个对象同一个事件绑定了多个function()onclick属性因为是赋值方式传递,只能执行最后一个function()。而用addEventListener函数可以为同一对象的同一事件添加多个处理函数

更多的例子:

const input = document.querySelector('input');
input.addEventListener('focus',function(){
    console.log("获得焦点");
});
input.addEventListener('blur',function(){
    console.log("失去焦点");
});
input.addEventListener('input',function(){ //向表单中输入内容
    console.log(input.value); //内容改变时获取内容
});

解绑事件

  • 使用on系列方法的事件绑定(如btn.onclick=...;),只需重写onclick将之前的覆盖:btn.onclick = null;

  • addEventListener方法的事件,必须使用元素对象.removeEventListener(事件类型,与事件监听相同的事件处理函数)的方式。

    因为必须传入同名的事件处理函数,所以使用匿名函数创建的事件监听无法解绑

function func(){
    console.log("son被点击");
}
son.addEventListener('click', func);
son.removeEventListener('click',func); //解绑事件

事件对象与环境对象

事件对象:也是一个对象,存储事件触发时的相关信息(如鼠标点击的位置,按下的是哪个键等等)

调用:事件监听绑定的回调函数的第一个参数,如input.addEventListener('input', function (event) {});中的event就是事件对象

事件对象常用属性:

  • type–当前的事件类型

  • clientX/clientY–获取光标相对浏览器可见窗口左上角的位置

  • offsetX/offsetY–获取光标相对当前dom元素左上角的位置

  • key–用户按下键的值

  • 更多关于光标位置的属性

例:

const input = document.querySelector('input');
input.addEventListener('input',function(){
    console.log(event.key); //获取按的是哪个键
});

环境对象:每个函数里面都有的this,谁调用该函数this就是谁

事件监听中传入函数的this就是事件源

阻止事件的默认行为

对于超链接、表单这种网页已经设置它们行为(如提交表单、跳转链接)的标签,可以使用e.preventDefault()阻止这种默认行为,其中e为事件对象

例如:

<body>
    <a href="http://www.baidu.com">百度一下</a>
</body>
<script>
    const a = document.querySelector('a');
    a.addEventListener('click',function(e){
        e.preventDefault(); //阻止默认行为
    });
</script>

此时点击链接就不会进行跳转

事件流与事件冒泡

事件流:事件完整执行过程中的流动路径,分为捕获和冒泡两个阶段

假设页面中有1个<div>

  • 冒泡(常用):从子元素到父元素–<div> -> <body> -> <html> -> Document即当一个元素触发事件后,会依次向上调用索引父级元素的同名事件

  • 捕获:从父元素到子元素–Document -> <html> -> <body> -> <div>

addEventListener可传入第三个参数(很少使用):

  • true表明事件在捕获阶段触发

  • false在冒泡阶段触发(默认值)

例:

<body>
    <div class="father">
        <div class="son"></div>
    </div>
</body>
<script>
    const father = document.querySelector('.father');
    const son = document.querySelector('.son');
    document.addEventListener('click', function () { //document表示整个页面
        console.log("document被点击");
    }, true);
    father.addEventListener('click', function () {
        console.log("father被点击");
    }, true);
    son.addEventListener('click', function () {
        console.log("son被点击");
    }, true);
</script>

输出:document被点击 father被点击 son被点击

若去掉上述代码addEventListener中的true,恢复为默认状态,则输出:son被点击 father被点击 document被点击


事件冒泡易导致事件影响到父级元素,要想把事件限制在当前元素内,就要阻止冒泡

语法:e.stopPropagation()其中e为事件对象

此方法可阻断事件流动传播,不仅阻止冒泡,也阻止捕获

更改son的事件监听为:

son.addEventListener('click', function (e) { 
    console.log("son被点击");
    e.stopPropagation(); //阻止冒泡
});

此时只输出son被点击


拓展:鼠标事件中mouseover-mouseoutmouseenter-mouseleave都可表示鼠标的进入和离开,区别是mouseover-mouseout有冒泡的属性,而后者没有。因此mouseenter-mouseleave更加常用

<body>
    <div class="father">
        <div class="son"></div>
    </div>
    <!-- CSS设置father和son的大小不同,son在father内 -->
</body>
<script>
    const father = document.querySelector('.father');
    father.addEventListener('mouseover', function () {
        console.log("鼠标经过father");
    });
    father.addEventListener('mouseout', function () {
        console.log("鼠标离开father");
    });
</script>

当鼠标从<div class="father">进入<div class="son">时,会输出:鼠标经过father 鼠标离开father 鼠标经过father

因为鼠标经过son时,虽然son没有给出mouseover对应的事件函数,但sonmouseover事件仍会被触发,同时因为冒泡而触发了fathermouseover事件,所以会又输出一个鼠标经过father

而正常情况下不想让鼠标进入son时触发“鼠标经过father”的事件。可以使用阻止冒泡,也可以使用mouseenter-mouseleave组替换mouseover-mouseout组,此时重复执行上面的操作,只会输出一次鼠标经过father

事件委托

利用事件冒泡的特性,给多个子元素的共同父元素注册事件,当触发子元素的事件时,会冒泡到父元素的同名事件

如实现一个无序列表中,点击其中的每个小li,当前li文字就变为红色

不用循环给每个li都注册点击事件,只要给其父元素ul注册即可,但要判断点击的是不是li:

<body>
    <ul>
        <li>第1个li</li>
        <li>第2个li</li>
        <li>第3个li</li>
        <li>第4个li</li>
        <li>第5个li</li>
        <p>不变色的p</p>
    </ul>
</body>
<script>
    const ul = document.querySelector('ul');
    ul.addEventListener('click', function (e) {
        const target = e.target; //获取点击的对象
        if (target.tagName == 'LI') //如果点击的是li标签(注意tagName对应的'LI'要大写)
            target.style.color = 'red'; //改变颜色
    });
</script>

此例中使用了事件对象属性e.target表示点击的是哪个标签,e.target.tagName是它的标签名称,注意该名称是大写的

其它事件

页面加载事件

若将js代码写到body上面,获取标签对象时会报错,因为对应标签还没有被创建

此时可以使用load加载事件:

window.addEventListener('load',function(){ //整个页面加载完成后执行
    document.querySelector('a').addEventListener('click',func);
}); 
// 或
a.addEventListener('load',function(){ //a标签加载完成后执行
    document.querySelector('a').addEventListener('click',func);
});

当初始的HTML文档完全加载后,document的DOMContentLoaded事件被触发,无序等待样式表、图像完全加载

document.addEventListener('DOMContentLoaded', function () {
    console.log('html加载完成');
});
页面滚动事件

可以给页面或某个元素加scroll事件,当该元素没有滚动条(禁止滚动)时不生效

const div = document.querySelector('.scroll');
div.addEventListener('scroll', function () {
    console.log(div.scrollTop);
}); //div元素内的滚动距离
window.addEventListener('scroll', function () {
    console.log(document.documentElement.scrollTop);
}); //整个页面的滚动距离
页面尺寸事件

resize是浏览器窗口大小发生变化时触发的事件

window.addEventListener('resize', function () {
    console.log("页面尺寸改变");
});

案例

判断滚动位置、元素滑动出现

案例描述:当页面滚动到<div class="sk">时,顶部导航栏<div class="header">从上到下从页面顶部滑出

关键1:如何判断页面滚动到sk模块–当页面被卷去的头部距离>=sk距页面顶端的距离时

关键2:如何让导航栏从上到下滑出–

  • 设置已知高度为80px.header初始定位方式为fixed,将top值设为-80px

  • 设置transition想让它滑多长时间;当想让它滑出时,就把top设为0px,让它从隐藏转为展示

const sk = document.querySelector('.sk');
const header = document.querySelector('.header');
window.addEventListener('scroll', function () {
    const n = document.documentElement.scrollTop;
    if (n >= sk.offsetTop) { //页面滚动到sk模块
        header.style.top = 0; //滑出
    }
    else {
        header.style.top = "-80px"; //滑入
    }
    // header.style.top = n >= sk.offsetTop ? 0 : "-80px"; //以上if语段相当于这个三元表达式
});
Date对象与计时器的结合

倒计时效果:用将来时间的时间戳减去现在时间的时间戳,将得到的剩余的时间戳转换为时分秒单位,并使用定时器进行更新

function get_time(second) { //将秒数转换成天时分秒
    //例:2天01时02分03秒
    let d = parseInt(second / 60 / 60 / 24);
    let h = parseInt(second / 60 / 60 % 24);
    h = h < 10 ? '0' + h : h;
    let m = parseInt(second / 60 % 60);
    m = m < 10 ? '0' + m : m;
    let s = parseInt(second % 60);
    s = s < 10 ? '0' + s : s;
    return `${d}${h}${m}${s}秒`;
}
function get_countdown(futher) //根据将来的时间戳作倒计时
{
    const now = +new Date(); //现在的时间戳
    const count = (futher - now) / 1000; //得到剩余的时间戳(转换成秒数以传入get_time函数)
    return get_time(count);
}
const div = document.querySelector('div');
const futher = +new Date("2024-2-7 18:30:00"); //将来的时间戳
div.innerHTML = get_countdown(futher); //设置初始值
let timer = setInterval(function () { //开启定时器,每1秒刷新1次
    div.innerHTML = get_countdown(futher);
}, 1000);

移动端事件简介

移动端事件即手机上浏览器的相关事件,也称M端事件

在Android和iOS上触屏事件:touch对象

常见的触屏事件:

  • touchstart手指触摸到一个DOM元素时触发

  • touchmove手指在一个DOM元素上滑动时触发

  • touchend手指从一个DOM元素上移开时触发

添加监听的方式与之前的相同:

const div = document.querySelector('div');
div.addEventListener('touchstart', function () {
    console.log('touch');
});
div.addEventListener('touchmove', function () {
    console.log('move');
});
div.addEventListener('touchend', function () {
    console.log('end');
});

在edge浏览器中,按f12后点击控制栏左上角第二个图标切换设备仿真即可用电脑模拟手机端网页的效果,并触发触摸事件(快捷键CTRL+shift+m,有可能被其它快捷键覆盖)

DOM节点

节点:构成HTML文档最基本单元

  • 元素节点:所有的标签,html标签是根节点

  • 属性节点:所有的标签属性

  • 文本节点:HTML标签中文本内容

对节点的操作以元素节点为主

查找节点

父节点

子元素.parentNode返回它最近的父节点DOM对象,若没有则返回null

<div class="dad">
    <div class="son"></div>
</div>
<script>
const son = document.querySelector('.baby');
const dad = son.parentNode;  //得到<div class="dad">
</script>
子节点

父元素.children以伪数组的形式返回所有的子节点(不包含孙节点)

<ul>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
</ul>
<script>
const ul = document.querySelector('ul');
const li_list =ul.children; //得到包含5个小li的伪数组
</script>
兄弟节点
  • 获取上一个兄弟节点:元素.previousElementSibling

  • 获取下一个兄弟节点:元素.nextElementSibling

<ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
</ul>
<script>
const li2 = document.querySelector('ul li:nth-child(2)');
const li1 = li2.previousElementSibling; //上一个兄弟节点li1
const li3 = li2.nextElementSibling; //下一个兄弟节点li3
</script>

增加节点

  • 创建节点document.createElement('标签名');,例如

    const new_li = document.createElement('li');
    

    这个新创建的节点是DOM对象,可以进行更改属性值等操作

  • 追加节点:插入到某个父元素中

    • 插入到父元素的最后:父元素.appendChild(要插入的元素)

    • 插入到父元素的前面:父元素.insertBefore(要插入的元素,插入到父元素的哪个子元素前面)

    const ul = document.querySelector('ul');
    const new_li = document.createElement('li');
    ul.appendChild(new_li); //将新创建的li加到ul的最后
    ul.insertBefore(new_li,ul.children[0]); //将新创建的li加到ul的最前面
    

    如果想要插入到页面中(以body作父元素):document.body.appendChild(new_li);

注意:如想在新创建的节点中再写标签,不一定要再创建节点,可以直接修改新创建节点的innerHTML值,例如

new_li.innerHTML = `<div> <p>我是new_li</p> </div>`;

生成的new_li:

<li>
    <div>
        <p>我是new_li</p>
    </div>
</li>

克隆节点

想复制的节点.cloneNode(bool)返回复制后的DOM对象

bool值为true则会包含想复制节点的内容文本和全部后代节点,为false(默认值)则不包含后代节点和内容文本,只包含想复制的节点标签

const new_li= li1.cloneNode(true); //复制li1及其内容文本和后代节点

删除节点

必须通过父元素删除,若不存在父子关系则删除不成功

父元素.removeChild(子元素)

const ul = document.querySelector('ul');
ul.removeChild(ul.children[0]); //删除ul的第一个li标签

删除节点和隐藏节点display:none;不同,隐藏节点还存在只是不显示,而删除就让html中彻底没有该元素了

BOM

BOM指浏览器对象模型

window对象是全局对象,是JS中的顶级对象

documentalert()console.log()等等都是window的属性,基本BOM的属性方法都是window的

所有通过var定义在全局作用域中的变量函数都属于window,constlet定义的不属于

调用window对象下的属性方法时可以省略window.

JS处理任务机制

JS是单线程语言,同一时间只能做一件事,易造成代码执行的阻塞。为解决这个问题,HTML5运行js时创建多个线程,出现了同步和异步。

同步:前一个任务结束后再执行下一个,执行顺序就是任务的排列顺序

异步:如果某个任务耗时很长,在处理该任务同时还可以执行其它任务,使执行顺序不同于任务的排列顺序

同步任务都在主线程上执行,形成一个执行栈;异步任务(如定时器、资源加载、各种事件)添加到任务队列/消息队列中

JS的执行机制:事件循环

  • 首先将任务分类:先执行执行栈中的同步任务,将异步任务放入任务队列中

  • 当执行栈中所有同步任务执行完毕,系统会按次序反复读取任务队列中的异步任务,当该异步任务需要被执行时(如定时器到了执行时间、触发了某个事件)就进入执行栈执行

  • 主线程不断重复获得任务、执行任务,这种机制称为事件循环eventloop

因此,在延时函数的例子中,即使延时时间为0,也会最后执行

location对象

属于window对象,拆分并保存了URL地址的各个部分

  • location.href当前页面的url地址,可以用于自动跳转页面,如location.href = 'http://baidu.com';就可以在打开页面时自动转到指定的网址

    例:5秒后自动跳转到链接

    <body>
        <a href="http://baidu.com">支付成功<span style="color: red;">5</span>秒钟后跳转到首页</a>
    </body>
    <script>
        const span = document.querySelector('span');
        let num = 5;
        let timer = setInterval(function () {
            num--;
            span.innerHTML = `${num}`;
            if (num == 0) {
                clearInterval(timer);
                location.href = 'http://baidu.com'; //倒计时结束后跳转
            }
        }, 1000);
    </script>
    
  • location.search指url地址后?后面的部分(即地址携带的参数)

  • location.hash指url地址后#后面的部分

  • location.reload()刷新页面 (相当于按f5/点击刷新按钮)

  • location.reload(true)强制刷新(相当于按CTRL+f5)

navigator对象记录了浏览器自身的相关信息

常用navigator.userAgent检测浏览器版本和平台,用于根据访问者的设备类型跳转对应网页(PC/移动端)等


histroy对象管理历史记录,作用类似于浏览器页面中前进/后退按钮

  • history.back()后退1个页面

  • history.forward()前进1个页面

  • history.go(-n)后退n个页面

  • history.go(n)前进n个页面

本地存储(重点)

即将数据存储在浏览器中,刷新页面后数据不丢失

分为localStoragesessionStorage

  • localStorage以键值对的形式存储信息,在f12->应用程序->本地存储->点击左侧小箭头展开中可以找到存储的信息

    • 存储数据localStorage.setItem(键,值)

    • 读取数据localStorage.getItem(键)

    • 删除数据localStorage.removeItem(键)

    • 更改某个键的值也是localStorage.setItem(键,新值),如果已有这个键就是更改,没有就是新增

    例:

    localStorage.setItem('name', 'abc'); //存储数据
    console.log(localStorage.getItem('name')); //abc
    localStorage.removeItem('name'); //删除数据name
    

    注意:本地存储只能存储字符串类型的数据,无论setItem的值是什么类型,都会转为字符串类型进行存储

  • sessionStorage用法和localStorage基本相同,区别是sessionStorage关闭浏览器窗口后数据消失,而localStorage只要不删数据就会一直存在,因此一般都使用localStorage


存储复杂数据类型:将数据封装到对象中,再转换成json字符串存储;取的时候,再把json字符串转换成对象按键取值

const obj = {
    name: 'abc',
    age: 18,
    gender: ""
}; //将数据封装到对象中
const obj_json = JSON.stringify(obj); //对象转json
localStorage.setItem('obj', obj_json); //存储json
const get_obj_json = localStorage.getItem('obj'); //取出json字符串
const get_obj = JSON.parse(get_obj_json); //json转成对象
console.log(get_obj['name']); //按键取值