JS进阶webAPIs

WebAPI

作用:通过使用js去操作html和浏览器

分类:

  1. DOM:文档对象模型
  2. BOM:浏览器对象模型

一、DOM基础

1.简介
(1)DOM

(Document Object Model)文档对象模型,是浏览器提供的一套专门用来操作网页内容的功能,即开发网页特效实现交互内容

(2)DOM树(文档树)

将HTML文档以树状结构直观表现出来,称之为DOM树,是描述网页内容关系的名词。

作用是用树状图表示了标签与标签之间的关系

(3)DOM对象

把网页内容当作对象处理,浏览器根据html标签生成js对象,所有标签属性都可以在这个对象上找到,修改这个对象的属性会自动映射到标签上。

所有对象的最上层,即DOM树的根上面还有一层,叫Document

document是DOM里提供的一个对象,网页所有内容都在document里面

<div>Hellodiv>
<script>
    let d=document.querySelector('div')
    console.dir(typeof d)
    d.innerHTML='World'
    d.style.color='red'
script>   
2.获取DOM元素

即通过js选择标签再对其进行相关操作

(1)通过CSS选择器来获取(常用)
①选择匹配的第一个元素—querySelector
document.querySelector('css选择器')
//参数可以包含一个或多个css选择器,返回匹配的第一个元素,一个HTMLElement对象,若没有匹配到返回null
<div>Hellodiv>
<div>Hello2div>
<script>
    //获取元素,输入qs会自动生成
    let d=document.querySelector('div')
	console.log(d)
	//输出结果:
Hello
d.style.color='red'
script>

querySelector

②选择匹配多个元素—querySelectorAll
document.querySelectorAll('css选择器')
//参数可以包含一个或多个css选择器,返回多个元素,即NodeList对象集合
<div>Hellodiv>
<div>Hello2div>
<script>
    //获取元素,输入qs会自动生成
    let dlist = document.querySelectorAll('div')
	console.log(dlist)
    //输出结果:NodeList(2) [div, div]
    for(let i=0;i<dlist.length;i++)
            dlist[i].style.color='red'
script>

querySelectorAll.png

注:querySelector可以直接操作修改,但是querySelectorAll获取的是一个数组,所以修改的时候需要进行遍历

(2)其他获取DOM方法(了解即可)
  • document.getElementsByTagName:获取页面上的某一种标签,获取的是一个选择集,不是数组,但是可以用下标的方式操作选择集里面的标签元素

  • document.getElementById:通过id获取标签,因为id只能使用一次,所以返回只有一个

  • document.getElementsByClassName:通过类名获取标签选择集

  • document.getElementsByName:通过name获取标签选择集

3.修改DOM元素内容
(1)document.write()方法

可以将文本追加到前,并且文本中的标签也会被解析,这一块在Javascript基础已经学过。

(2)对象.innerText属性

将文本内容添加/更新到任意标签位置,但文本中的标签不会被解析

<div>Hellodiv>
<script> 
    //获取元素,输入qs会自动生成    
    let d=document.querySelector('div')
	d.innerText='
World
'
script> 输出结果:将div标签中的文字更新为 <div>Worlddiv>
(3)对象.innerHTML属性

将文本内容添加/更新到任意标签位置,并且文本中的标签会被解析

<div>Hellodiv>
<script> 
    //获取元素,输入qs会自动生成    
    let d=document.querySelector('div')
	d.innerHTML='
World
'
script> 输出结果:将div标签中的文字更新为 World
4.修改DOM元素属性
(1)设置/修改元素常用属性

对象名.属性=值


<a href="https://www.baidu.com/">百度a>
<script> 
    //获取元素    
    let a=document.querySelector('a') 
    a.innerHTML='必应'   
    //修改元素属性
    a.href="https://cn.bing.com"
script>
(2)设置/修改元素样式属性
①通过style属性操作css
<div>Hellodiv>
<script>
    let d=document.querySelector('div')
    d.style.color='skyblue'
    d.style.width='300px'
    d.style.backgroundColor='white'
    document.body.style.backgroundColor='skyblue'
    //若设置body,则不需要获取,可以直接document.body
script>
  • 如果属性有-连接符,如background-color则转化成小驼峰,即backgroundColor

  • 赋值时css需要添加单位

②通过类名操作css

若修改的样式比较多,直接通过style修改比较繁琐,则可以通过css类名的形势去修改

<head>    
	<style>
        .box{
            color:white;
            width:300px;
            height: 200px;
            background-color:skyblue;
        }
    style>
head>
<body>
    <div>Hellodiv>
    <script>
        let d=document.querySelector('div')
        d.className='box'
        //将d设置成box类的类型
    script>
body>
  • 由于class是关键字,所以需要className去代替

  • className是使用新的值去替换旧的值,若需要添加一个类,需要保留之前的类名,比如原来标签类名为class="a",现在设置成class="b"了;想要保存则可以设置成class="a b"

  • 注:没有idName

③通过classList操作css
  • 追加一个类:元素.classList.add('类名')
  • 删除一个类:元素.classList.remove('类名')
  • 切换一个类:元素.classList.toggle('类名')
<div class='box'>Hellodiv>
<script>
    let d=document.querySelector('.box')
    d.classList.add('a')
    d.classList.add('b')
    //结果:
Hello
d.classList.remove('b') //结果:
Hello
d.classList.toggle('c') //结果:
Hello
d.classList.toggle('c') //结果:
Hello
script>

toggle切换指的是如果查询没有该类名则加上,若有则删除

(3)设置/修改表单元素属性

表单很多情况也需要修改属性,比如输入密码时的小眼睛,点击可以看到密码,其本质就是将表单类型从密码转变为文本框

  • 获取:DOM对象.属性名
  • 设置:DOM对象.属性名=新值
<input type="text" value="请输入">
<botton disabled>提交botton>
<input type="checkbox" class="check">
<script>
    // 1.获取元素
    let input=document.querySelector('input')
    // 2.取值或设置值,得到input中的值可以使用value
    input.type='password'
    // 启用按钮
    let btn=document.querySelector('botton')
    btn.disable=false//若等于true表示不能使用,若false表示可以启用
    //勾选复选框
    let checkbox=document.querySelector('.check')
    checkbox.checked=true
script>
5.定时器-间歇函数

定时器在javascript中的作用:

  1. 制作动画
  2. 异步操作
  3. 函数缓冲与节流
  • setTimeout(函数,间隔时间) 只执行一次的定时器

  • clearTimeout(变量名) 关闭只执行一次的定时器

  • setInterval(函数,间隔时间) 反复执行的定时器

  • clearInterval(变量名) 关闭反复执行的定时器

    间隔时间是毫秒,1000毫秒=1秒

(1)举个栗子1:创建一个时钟
<div class="clock">div>
<script> 
    let clockbox = document.querySelector('.clock');
    function timebox(){
        //提取当前时间
        let now = new Date();
        let year = now.getFullYear();
        let month = now.getMonth()+1;//month是从0-11
        let date = now.getDate();
        let week = now.getDay();//星期是从0-6
        let hour = now.getHours();
        let minute = now.getMinutes();
        let second = now.getSeconds();
        let str = '当前时间是:'+ year + '年'+month+'月'+date+'日 '+toweek(week)+' '+hour+':'+minute+':'+second;
        clockbox.innerHTML = str;
    }
    //提取星期,因为now.getDay();返回的是0-6
    function toweek(n){
        if(n==0) return '星期日'
        else if(n==1) return '星期一'
        else if(n==2) return '星期二'
        else if(n==3) return '星期三'
        else if(n==4) return '星期四'
        else if(n==5) return '星期五'
        else return '星期六'
    }
    timebox();
    let clock=setInterval(timebox,1000);
    clearInterval(clock);
script>
(2)举个栗子2:协议倒计时
<textarea style="width: 260px;">
         用户协议
    请您阅读完后点击确认
textarea>
<br>
<button class="btn" disabled>确认(6)button>
<script>
    //1.获取元素
    let btn=document.querySelector('.btn')
    //2.计算逻辑
    let count=6 //计数
    let time=setInterval(function(){
        count--
        btn.innerHTML=`确认(${count})`
        if(count==0)
        {
            //关闭定时器
            clearInterval(time)
            //开启按钮
            btn.disabled=false
            //更换文字
            btn.innerHTML=`确认`
        }

    },1000)
script>

协议定时器1.png

协议定时器2.png

二、DOM事件

1.事件
(1)事件

事件是在编程时系统内发生的动作或者发生的事情

(2)事件监听:(注册事件)

让程序检测是否有事件,若有事件触发则立即调用一个函数做出响应,也称为注册事件

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

①事件监听三要素
  • 事件源:DOM元素被事件触发,需要获取DOM元素

  • 事件:用什么方式触发

    注:事件是字符串

    事件类型:

    1. 鼠标触发:
      1. click鼠标点击
      2. mousemove鼠标移动
      3. mouseover 鼠标进入(进入子元素也触发)
      4. mouseout 鼠标离开(离开子元素也触发)
      5. mouseenter 鼠标进入(进入子元素不触发)尽量使用这个
      6. mouseleave 鼠标离开(离开子元素不触发)尽量使用这个
      7. hover同时为mouseenter和mouseleave事件指定处理函数
      8. scroll 滚动条的位置发生变化
    2. 焦点事件:表单获得光标
      1. focus获得焦点
      2. blur失去焦点
      3. submit用户递交表单
    3. 键盘事件:键盘触发
      1. keydown键盘按下触发
      2. keyup键盘抬起触发
    4. 文本事件:表单输入触发
      1. input用户输入事件
    5. ready() DOM加载完成
    6. resize() 浏览器窗口的大小发生改变
  • 事件调用的函数:要做的事情

②举个栗子1:点击叉号关闭图片
<div class="imgbox">
    <img src="image/background.jpg">
    <div class="chahao" style="color: black;">xdiv>
div>
<script>
    let imgbox=document.querySelector('.imgbox')
    let chahao=document.querySelector('.chahao')
    chahao.addEventListener('click',function(){
        //隐藏盒子
        imgbox.style.display='none'
    })
script>

JS进阶webAPIs_第1张图片

③举个栗子2:小米输入框
  • 开始下拉菜单隐藏

  • 表单获得焦点就显示下拉菜单并将文本框变色

  • 表单失去焦点,反向操作

<style>
    *{
        margin: 0;
        padding: 0;
        box-sizing: border-box;
    }
    ul{
    	list-style: none;
    }
    .mi{
        position: relative;
        width: 200px;
        margin: 100px auto;
    }
    .mi input{
        width: 200px;
        height: 50px;
        padding: 0 10px;
        font-size: 14px;
        line-height: 50px;
        border: 1px solid #e0e0e0;
        outline: none;
    }
    .mi .search{
    	border: 10px solid #ff6700;
    }
    .resultList{
        display: none;
        position: absolute;
        left: 0;
        top: 50px;
        width: 200px;
        border: 1px solid #ff6700;
        border-top: 0;
        background: #fff;
    }
    .resultList a{
        display: block;
        padding: 6px 15px;
        font-size: 12px;
        color: #424242;
        text-decoration: none;
    }
    .resultList a:hover{
    	background-color: #eee;
    }
style>
<div class="mi">
    <input type="search" placeholder="请输入产品名">
    <ul class="resultList">
        <li><a href="#">全部商品a>li>
        <li><a href="#">小米笔记本a>li>
        <li><a href="#">小米手环a>li>
        <li><a href="#">小米手机a>li>
    ul>
div>
<script>
    //1.获取元素
    //使用属性选择器选择search
    let search=document.querySelector('input[type=search]')
    let resultList=document.querySelector('.resultList')
    //2.事件函数
    search.addEventListener('focus',function(){
        resultList.style.display='block';
    })
    search.addEventListener('blur',function(){
        resultList.style.display='none';
    })
script>

JS进阶webAPIs_第2张图片

JS进阶webAPIs_第3张图片

④举个栗子3:微博输入
  • 不断取得文本框里面的字符长度
  • 把获得的数字给下面文本框,若字数为0或达到最多就将字数设置为红色
<div class="Weibo">
    有什么新鲜事想要告诉大家?<br>
    <textarea placeholder="说点什么吧..." id="area" cols="30" rows="10" maxlength="200">textarea>
    <div class="foot">
        <span>0span>/200
        <button>发布button>
    div>
div>
<script>
    let area=document.querySelector('#area')
    let text=document.querySelector('.foot span')
    let fontNum=0
    area.addEventListener('input',function(){
        fontNum=area.value.length
        text.innerHTML=fontNum
        if(fontNum!=0&&fontNum<200)
            text.style.color='black'
        else
            text.style.color='red'
    })
script>

JS进阶webAPIs_第4张图片

JS进阶webAPIs_第5张图片

⑤举个栗子:全选商品
<style>
    *{
        margin: 0;
        padding: 0;
        box-sizing: border-box;
    }
    .FuXuan{
        width: 500px;
        border: 1px solid skyblue;
        text-align: center;
        border-collapse: collapse;
        margin: 0 auto;
    }
    .FuXuan th{
        background-color: skyblue;
        color: white;
    }
    .FuXuan td{
        border: 1px solid skyblue;
    }
style>
<div>
    <table class="FuXuan">
        <tr>
            <th><input type="checkbox" class="checkAll"><span class="QuanXuan">全选span>th>
            <th>商品th>
            <th>商家th>
            <th>价格th>
        tr>
        <tr>
            <td><input type="checkbox" class="check1">td>
            <td>红米K40td>
            <td>小米td>
            <td>¥1999td>
        tr>
        <tr>
            <td><input type="checkbox" class="check2">td>
            <td>OPPO Findx3td>
            <td>OPPOtd>
            <td>¥3000td>
        tr>
        <tr>
            <td><input type="checkbox" class="check3">td>
            <td>Iphone13td>
            <td>苹果td>
            <td>¥6000td>
        tr>
    table>
div>
<script>
    let QuanXuan=document.querySelector('.QuanXuan')
    let checkAll=document.querySelector('.checkAll')
    let check=document.querySelectorAll('.check')
    checkAll.addEventListener('click',checkAllNum)
    for(let i=0;i<check.length;i++)
        check[i].addEventListener('click',checkNum)
    function checkNum(){
        for(let i=0;i<check.length;i++)
        {
            if(check[i].checked==false)
            {//若有未选的直接退出
                QuanXuan.innerHTML='全选'
                checkAll.checked=false
                return
            }
        }
        QuanXuan.innerHTML='取消'
        checkAll.checked=true
    }
    function checkAllNum(){
        if(checkAll.checked==true)
        {
            QuanXuan.innerHTML='取消'
            for(let i=0;i<check.length;i++)
                check[i].checked=true
        }
        else
        {
            QuanXuan.innerHTML='全选'
            for(let i=0;i<check.length;i++)
                check[i].checked=false
        }
    }
script>

JS进阶webAPIs_第6张图片

JS进阶webAPIs_第7张图片

2.高阶函数

可以理解为函数的高级使用,把函数当作来对待的函数就是高级函数

(1)函数表达式

let 变量名=function(){}

(2)回调函数

如果将一个函数当作一个参数传递给另一个参数,那么当参数的函数称为回调函数。比较常见的是使用匿名函数当作回调函数

比如:checkAll.addEventListener('click',checkAllNum)中的checkAllNum就是回调函数

3.环境对象

环境对象指的是函数内部特殊的变量this,代表当前函数运行时所处的环境。目的是让代码更加简洁

this就是一个对象,普通函数this指向window,因为直接调用函数,相当于是window.函数,所以this指向window

function fn(){console.log(this)} 
//结果:Window
btn.addEventListener('click',function(){console.log(this)})
//结果:

粗略的规则:谁调用,this就指向谁

//原来
btn.addEventListener('click',function(){
    btn.style.color='red'
})
//使用this
btn.addEventListener('click',function(){
    this.style.color='red'
})
4.排他思想

就是比如标签,只有选择的那一项会改变模样,其他不变,实现方法就是先将所有元素的样式关闭,然后只打开自己

for(let i=0;i<btns.length;i++)
	btns[i].addEventListener('chick',function(){
        // //干掉所有人
        // for(let j=0;j
        //     btns[j].classList.remove('pink')
        
        //改进:因为只有一个会是pink样式,找到那唯一的一个pink类,然后删除
        document.querySelector('.pink').classList.remove('pink')
        //只打开自己
        this.classList.add('pink')
        }
    })

三、DOM节点

1.DOM节点

DOM树中的每个内容都称之为节点

(1)节点类型
  • 元素节点:标签
  • 属性节点:标签的属性
  • 文本节点:标签中的文本
(2)节点关系:
  • 父节点
  • 子节点
  • 兄弟节点
2.查找节点
<div class="a">
    <div class="b">
        <img src="" class="image">
        <div class="c">div>
    div>
div>
(1)查找父节点
  • 节点.parentNode:返回最近一级的父结点,找不到则返回null,若想找再上一层可以继续.parentNode
let image=document.querySelector('.image')
//查找父节点,得到
...
console.log(image.parentNode) //查找父节点的父节点,得到
...
console.log(image.parentNode.parentNode)
(2)查找子节点
  • 节点.childNodes:获得所有子节点,包括文本节点(空格、换行)、注释节点等
  • 节点.children(重点)仅获得所有元素节点,返回的还是一个数组
let father=document.querySelector('.b')
//查找孩子节点,结果为:NodeList(5) [text, img.image, text, div.c, text]
console.log(father.childNodes)
//查找孩子节点,结果为:HTMLCollection(2) [img.image, div.c]
console.log(father.children)
(3)查找兄弟节点
  • 节点.nextElementSibling:查找下一个兄弟节点
  • 节点.previousElementSibling:查找上一个兄弟节点
//查找下一个兄弟节点,结果为:
let next=image.nextElementSibling console.log(next) //查找上一个兄弟节点,结果为: console.log(next.previousElementSibling)
3.增加节点

创建新的节点并放到指定位置

(1)创建节点—document.createElement('新的标签')
//创建标签
let d=document.createElement('div')
//添加class
div.className='d'
(2)追加节点
  • 插入到父元素的最后一个子元素后面—元素.appendChild(要插入的元素)
//追加到父元素最后一个子元素后面
let b=document.querySelector('.b')
b.appendChild(d)
//添加内容
d.innerHTML='class=d'
  • 插入到父元素中某个子元素的前面—元素.insertBefore(要插入的元素,在哪个元素前)
//追加到父元素第一个子元素前面
b.insertBefore(d,b.children[0])

在页面排列图片或者其他元素时,之前学的是用document.write(),这个方法并不好,因为需要在script内渲染,学到这里,我们就可以使用节点进行追加

(3)举个栗子:使用增加节点来实现之前的打印学生列表
<div>
    <table>
        <caption>学生列表caption>
        <tr>
            <th>序号th>
            <th>姓名th>
            <th>年龄th>
            <th>性别th>
        tr>
    table>
div>
<script>
    let student=[
        {name:'张三',age:20,gender:'男'},
        {name:'李四',age:21,gender:'女'},
        {name:'王五',age:19,gender:'男'},
        {name:'钱六',age:22,gender:'男'}
    ]
    let table=document.querySelector('table')
    for(let i=0;i<student.length;i++)
    {
        //追加行节点
        let tr=document.createElement('tr')
        table.appendChild(tr)
        //追加序号
        let No=document.createElement('td')
        tr.appendChild(No)
        No.innerHTML=`${i+1}`
        //循环追加学生信息
        for(let k in student[i])
        {
            let st=document.createElement('td')
            tr.appendChild(st)
            st.innerHTML=`${student[i][k]}`
        }
    }
script>  

JS进阶webAPIs_第8张图片

4.克隆节点—元素.cloneNode(布尔值)

无缝滚动使用的就是克隆节点,就是复制一个原有的节点,再将复制的节点放到指定位置。

  • 若为true则克隆会包含后代节点一起克隆

  • 若为false则不克隆后代

<div class="a">
    <div class="b">
        <img src="" class="image">
        <div class="c">div>
    div>
div>
<script>
    let b=document.querySelector('.b')
    //克隆b
    let newb=b.cloneNode(true)
    //放到c的子节点
    let c=document.querySelector('.c')
    c.appendChild(newb)
    //放到最外层body内
    document.body.appendChild(newb)
script>  
5.删除节点—父元素.removeChild(要删除的孩子元素)
//删除刚才克隆到c内的b
c.removeChild(b)

四、时间对象

1.实例化

在代码中如果发现new关键字,一般将这个操作称为实例化

2.时间对象—let date=new Date()
//获得当前时间
let date=new Date()
//获得指定时间,比如做倒计时的时候
let date2=new Date(2022,01,01,01,00,00)
let date2=new Date('2022-01-01 01:00:00')
3.时间对象方法

时间对象返回的数据不能直接使用,需要使用一些方法进行转换格式

方法 作用 范围
getFullYear()
getMonth() 0~11
getDate()
getDay() 星期 0~6
getHours() 0~23
getMinutes() 0~59
getSeconds() 0~59

注:

月份是从0开始,所以需要加1;

星期是数字从0-6,所以需要转换成星期日、星期一、星期二、…、星期六

4.时间戳

时间戳是指从1970年1月1日0时0分0秒到现在的毫秒数,是用来计算时间的,是一种特殊的计量时间的方式。最常见的应用是倒计时,即将结束的时间的时间戳减去开始的时间的时间戳,得出剩余的时间毫秒数。

获得时间戳方式:(三种)

  • 时间.getTime():可以得到当前也可以得到指定时间的时间戳
  • +new Date():可以得到当前也可以得到指定时间的时间戳
  • Date.now():但只能得到当前时间戳
let date=new Date()
let date2=new Date('2022-01-01 01:00:00')
//获得当前时间的时间戳
console.log(date.getTime())
console.log(+new Date())
console.log(Date.now())
//获得指定时间的时间戳
console.log(date2.getTime())
console.log(+new Date('2022-01-01 01:00:00'))

倒计时转换公式:

  • 总秒数=parseInt((future-now)/1000)

  • 天数=parseInt(总秒数/60/60/24)

  • 小时数=parseInt(总秒数/60/60%24)

  • 分钟数=parseInt(总秒数/60%60)

  • 秒数=parseInt(总秒数%60)

倒计时的时间差也可以直接使用时间对象相减

//倒计时:future是未来的时间,now是现在的时间
let now=new Date()
let future=new Date('2022-05-24 09:10:00')
//得出时间差,转换成秒数
let count = parseInt((future-now)/1000);
//得出天数,86400=60*60*24
let day = parseInt(count/60/60/24);
//得出小时
let hour = parseInt(count/60/60%24);
//得出分钟
let min = parseInt(count/60%60);
//得出秒
let sec = parseInt(count%60);
console.log(count,day,hour,min,sec);

五、重绘和回流

1.浏览器是如何进行界面渲染
  1. 解析(Parser)HTML,生成DOM树(DOM tree)
  2. 同时解析CSS,生成样式规则(Style Rules)
  3. 根据DOM树和样式规则,生成渲染树(Render Tree)
  4. 进行布局/Layout(回流/重排):根据生成的渲染树,得到节点的几何信息(位置、大小),即进行盒子布局
  5. 进行绘制/Painting(重绘):根据计算和获取的信息进行整个页面的绘制渲染相应的信息
  6. Display:展示在页面上
2.回流(重排)

当Render Tree中部分或者全部元素的尺寸、结构、布局发生改变时,浏览器就会重新渲染部分或者全部文档的过程称为回流

如:页面首次刷新;浏览器窗口大小发生改变;元素大小或位置发生改变;激活css伪类;DOM操作(如添加、删除DOM元素)

3.重绘

因为节点的样式发生改变,但是并不影响布局时,称为重绘

如:设置背景色、设置字体颜色等等

重绘不一定会引起回流,但是回流一定会引起重绘

四、DOM事件高级

1.事件对象

事件对象也是一个对象,存放事件触发时的相关信息。在事件绑定的回调函数的第一个参数就是事件对象,并且一般命名为event、ev、e,如鼠标点击事件中:元素.addEventListener('click',function(e){})事件对象e就存放了鼠标点击的位置等信息。可以使用console.log(e)查看事件对象详情

(1)事件对象常用属性
  • type:获取当前事件的类型

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

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

  • key:用户按下的键盘键的值

    • 注:现在不提倡使用keyCode

(2)举个栗子1:图片跟着鼠标移动
  1. 鼠标移动使用mousemove事件
  2. 不断将鼠标的坐标给图片的left和top值
<img src="./image/logo.jpg" class="logo" style="left: 0;top:0;position:absolute;width: 60px;height: 50px;">
<script>
    let logo=document.querySelector('.logo')
    let move=addEventListener('mousemove',function(e){
        //因为在图片左上角,所以想要在图片中间可以修改一下,减图片的一半
        logo.style.left=e.clientX-30+'px'
        logo.style.top=e.clientY-25+'px'
    })
    setInterval(move,1000)
script>
(3)举个栗子2:回车发布微博,升级之前的微博发布
DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>微博输入改进title>
    <style>
        *{
            margin: 0;
            padding: 0;
        }
        textarea{
            width: 500px;
            border: 1px solid skyblue;
            font-size: 20px;
            color:black;
        }
        .Weibo{
            width: 500px;
            margin: 0 auto;
            color: skyblue;
        }
        .foot{
            color: black;
            float: right;
        }
        .foot span{
            color: red;
        } 
        .text{
            padding-top: 100px;
            width: 500px;
            margin: 0 auto;
        }
        ul{
            display: block;
            width: 500px;
        }
        li{
            list-style: none;
            display: block;
            word-wrap: break-word;
            width: 480px;
            padding: 10px 10px;
            margin: 10px 0; 
            border: 1px solid skyblue;
            border-radius:10px; 
        }
        .time{
            text-align: right;
            color: skyblue;
        }
    style>
head>
<body>
    <div class="Weibo">
        有什么新鲜事想要告诉大家?<br>
        <textarea placeholder="说点什么吧..." id="area" cols="30" rows="10" maxlength="200">textarea>
        <div class="foot">
            <span>0span>/200
            <button>发布button>
        div>
    div>
    <div class="text">
        <ul>
        ul>
    div>
    <script>
        let area=document.querySelector('#area')
        let text=document.querySelector('.foot span')
        let fontNum=0
        area.addEventListener('input',function(){
            fontNum=area.value.length
            text.innerHTML=fontNum
            if(fontNum!=0&&fontNum<200)
                text.style.color='black'
            else
                text.style.color='red'
        })
        //按下回车生成留言信息
        let btn=document.querySelector('button')
        let ul=document.querySelector('ul')
        function btn_display(){
            if(area.value.trim()==''){
                area.value=''
                text.innerHTML=0
                alert('内容不能为空')
                return
            } 
            else{
                let li=document.createElement('li')
                ul.insertBefore(li,ul.children[0])
                li.innerHTML=area.value
                area.value=null
                let date=new Date()
                let time=document.createElement('div')
                li.appendChild(time)
                time.className='time'
                let year=date.getFullYear()
                let month=date.getMonth()
                let day=date.getDay()
                let hour=date.getHours()
                let min=date.getMinutes()
                time.innerHTML=year+'年'+month+'月'+day+'日'+hour+':'+min
                text.innerHTML=0
                text.style.color='red'
            }
        }
        btn.addEventListener('click',btn_display)
        area.addEventListener('keyup',function(e){
            //按下回车键
            console.log(e.key);
            if(e.key=='Enter'){
                btn_display()
            }
        })
    script>
body>
html>

JS进阶webAPIs_第9张图片

2.事件流

指事件完整执行过程中的流动路径,先捕获,然后冒泡

  1. 捕获阶段:Document->HTML->body->div(即父到子)
  2. 冒泡阶段:div->body->html->Document(即子到父)

JS进阶webAPIs_第10张图片

(1)事件冒泡阶段

当一个元素的事件被触发时,同样的事件将会在该元素的所有祖先元素中依次被触发。这一过程被称之为事件冒泡。

即:当一个元素触发事件后,会依次向上调用所有父级元素的同名事件

<style>
    .father{
        margin: 100px auto;
        width: 500px;
        height: 500px;
        background-color: skyblue;
    }
    .son{
        width: 200px;
        height: 200px;
        background-color: black;
    }
style>
<div class="father">
    <div class="son">div>
div>
<script>
    let f=document.querySelector('.father')
    let s=document.querySelector('.son')
    f.addEventListener('click',function(){
        alert('father')
    })
    s.addEventListener('click',function(){
        alert('son')
    })
script>

此时点击father框会弹出father,但是点击son不仅会弹出son,还会弹出father,即会将其父级元素的相同事件一起触发。若father上级还有相同的事件也会触发,若不同事件则不会被触发。

事件冒泡是默认存在的

JS进阶webAPIs_第11张图片

(2)事件捕获阶段—DOM.addEventlistener(事件类型,事件处理函数,是否使用捕获机制)

从DOM的根元素开始去执行对应的事件(从外到内),并且事件捕获需要编写对应代码才能看到效果

<style>
    .father{
        margin: 100px auto;
        width: 500px;
        height: 500px;
        background-color: skyblue;
    }
    .son{
        width: 200px;
        height: 200px;
        background-color: black;
    }
style>
<div class="father">
    <div class="son">div>
div>
<script>
    let f=document.querySelector('.father')
    let s=document.querySelector('.son')
    f.addEventListener('click',function(){
        alert('father')
    },true)
    s.addEventListener('click',function(){
        alert('son')
    },true)
    document.addEventListener('click',function(){
        alert('body')
    },true)
script>

此时点击son会首先弹出body,然后弹出father,最后弹出son;若点击father则首先弹出body,然后弹出father;若点击body只会弹出body。即若开启捕获,则会从根元素开始去执行对应的事件。和冒泡正好相反。

捕获本身不重要,开发中基本不用,只用理解即可,主要是使用事件冒泡

JS进阶webAPIs_第12张图片

(3)阻止事件流动

因为默认冒泡,那么容易导致事件影响到父级元素,若想让事件不影响父级元素,则需要阻止事件流动。阻止事件流动:在事件中:e.stopPropagation()

let f=document.querySelector('.father')
let s=document.querySelector('.son')
f.addEventListener('click',function(e){
    alert('father')
    //阻止流动 Propagation:传播
    e.stopPropagation()
})
s.addEventListener('click',function(e){
    alert('son')
    //阻止流动
    e.stopPropagation()
})

此方法不仅可以阻断冒泡,还可以阻断捕获

之前学到的事件中

  1. mouseover 鼠标进入(有冒泡)
  2. mouseout 鼠标离开(有冒泡)
  3. mouseenter 鼠标进入(没有冒泡)
  4. mouseleave 鼠标离开(没有冒泡)

所以尽量使用mouseenter 鼠标进入和mouseleave 鼠标离开

(4)阻止默认行为—e.preventDeafult()

比如链接点击不跳转,表单域不提交

<a href="http://www.baidu.com">baidua>
<script>
    let a=document.querySelector('a')
    a.addEventListener('click',function(e){
        //点击链接不跳转,阻止默认行为
        e.preventDefault()
    })
script>
(5)两种注册事件的区别:
  • 传统on注册(L0)—不常用了

    • 同一个对象,后面注册的事件会覆盖前面注册(同一个事件)

      <button>点击button>
      <script>
          let btn=document.querySelector('button')
          btn.onclick=function(){
              alert('onclick1')
          }
          btn.onclick=function(){
              alert('onclick2')
          }
      script>
      执行结果:
      执行的话只会显示onclick2,会覆盖前面的事件
      
    • 直接使用null覆盖偶就可以实现事件的解绑

      btn.onclick=null
      执行结果:
      之前注册的事件将不会执行,也就是解绑
      
    • 都是冒泡阶段执行的

  • 事件监听注册(L2)
    语法: addEventListener(事件类型,事件处理函数,是否使用捕获)

    • 后面注册的事件不会覆盖前面注册的事件(同一个事件)

      <button>点击button>
      <script>
          let btn=document.querySelector('button')
          btn.addEventListener('click',function(){
              alert('click1')
          })
          btn.addEventListener('click',function(){
              alert('click2')
          })
      script>
      执行结果:
      执行的话会依次显示click1、click2
      
    • 解绑

      • 匿名函数无法被解绑
      • 必须使用removeEventListener(事件类型,事件处理函数,获取捕获或者冒泡阶段)
      btn.addEventListener('click',Falert)
      function Falert(){
          alert('click1')
      }
      btn.removeEventListener('click',Falert)
      //但是若是在注册事件参数中写的匿名函数function(){}则不能解绑
      
    • 可以通过第三个参数去确定是在冒泡或者捕获阶段执行

3.事件委托

事件委托利用事件流的特征解决一些开发需求的知识技巧。

事件委托是利用事件冒泡的特点,给父节点添加事件,当点击子节点时会向上冒泡,冒泡到其父节点触发事件。即把子结点的事件委托给父节点,从而简化操作和提高性能

注:

  • 事件对象.target可以获得真正触发事件的元素,即子节点,是整个元素
  • 事件对象.target.tagName找到获得真正触发事件的元素标签名
  • 事件对象.target.id获取数据的索引号
<ul>
    <li>1li>
    <li>2li>
    <li>3li>
    <li>4li>
    <li>5li>
ul>
<script>
    //不要每个li都注册事件,而是把事件委托给其父节点ul
    let ul=document.querySelector('ul')
    ul.addEventListener('click',function(e){
        //即通过冒泡性,点击其子结点时会向上冒泡,发现其父节点有点击事件,则会执行
        // alert('点击li')
        //得到点击的当前元素,即会得到li
        // console.log(e.target)
        //设置点击哪个li哪个li就变红
        e.target.style.color='red'
    })
script>

事件委托.png

4.举个栗子:学生管理案例

点击录入按钮,可以添加学生信息,主要目的是为了后面学习Vue做铺垫(数据驱动视图),即主要是操作数组数据,从而重新渲染页面

需求1:添加数据

  • 点击录入按钮,把表单内的值都放入数组内
  • 学号自动生成,若还未有学生,则从1001开始,若有学生则为数组最后一个学生的学号+1
  • 若学生数据表单未填写则弹框表示需要填写完整

需求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>Documenttitle>
    <style>
        *{
            margin: 0;
            padding: 0;
        }
        input{
            width: 70px;
            border: 1px solid skyblue;
        }
        select{
            border: 1px solid skyblue;
        }
        button{
            width: 40px;
            color: white;
            background-color:teal;
            border-radius: 5px;
        }
        h2{
            margin-top: 20px;
            text-align: center;
        }
        table{
            text-align: center;
            width: 700px;
            border: 1px solid skyblue;
            border-collapse: collapse;
        }
        tr,th,td{
            height: 50px;
            border: 1px solid teal;
        }
        th{
            background-color: skyblue;
        }
        tbody tr:hover{
            background-color: #eee;
        } 
        a {
            text-decoration: none;
            color: teal;
        }
        .add{
            width: 700px;
            margin: 0 auto;
        }
    style>
head>
<body>
    <div class="add">
        <h2>新增学生h2><br>
        姓名:<input type="text" class="name">
        年龄:<input type="text" class="age">
        性别:<select name="gender" class="gender">
            <option value="">option>
            <option value="">option>
        select>
        薪资:<input type="text" class="salary">
        就业城市:<input type="text" class="city">
        <button class="add_btn">录入button>
        <h2>学生信息表h2>
        <table>
            <thead>
                <tr>
                    <th>学号th>
                    <th>姓名th>
                    <th>年龄th>
                    <th>性别th>
                    <th>薪资th>
                    <th>就业城市th>
                    <th>删除th>
                tr>
            thead>
            <tbody>

            tbody>
        table>
    div>
    <ul>
    ul>
    <script>
        let student=[
            {id:1001,name:'张三',age:20,gender:'男',salary:'15',city:'北京'}
        ]
        let tbody=document.querySelector('tbody')
        //根据数组进行渲染
        function showTable(){
            //先删除以前的数据
            tbody.innerHTML=''
            //再渲染新的数据
            for(let i=0;i<student.length;i++)
            {
                //创建tr
                let tr=document.createElement('tr')
                //tr内的内容
                tr.innerHTML=`
                    ${student[i].id}
                    ${student[i].name}
                    ${student[i].age}
                    ${student[i].gender}
                    ${student[i].salary}
                    ${student[i].city}
                    ${i}">删除
                `
                //给删除添加id以方便删除时获取id
                tbody.appendChild(tr)
            }
        }
        showTable()
        
        //添加学生
        //获取提交按钮
        let add_btn=document.querySelector('.add_btn')
        //获取各个表单元素
        let name=document.querySelector('.name')
        let age=document.querySelector('.age')
        let gender=document.querySelector('.gender')
        let salary=document.querySelector('.salary')
        let city=document.querySelector('.city')
        //添加点击提交事件
        add_btn.addEventListener('click',function(){
            //若非空则添加到数组
            if(Empty(name.value)&&Empty(age.value)&&Empty(gender.value)&&Empty(salary.value)&&Empty(city.value)){
                let stuId
                if(student.length!=0)
                    stuId=student[student.length-1].id+1
                else//若数组为空,则学生学号从1001开始
                    stuId=1001
                student.push({
                    id: stuId,//最后一个元素的Id+1
                    name: name.value,
                    age: age.value,
                    gender: gender.value,
                    salary: salary.value,
                    city: city.value
                })
                //重新渲染函数
                showTable()
                //将表单恢复为空
                name.value=age.value=salary.value=city.value=''
                gender.value='男'
            }
        }
        )
        //判断input非空,之后可以使用正则
        function Empty(value){
            if(value.trim()!='') return true
            else{
                alert('添加学员数据不可为空')
                return false
            }    
        }
        
        //事件委托进行删除
        let del=document.querySelector('tbody')
        del.addEventListener('click',function(e){
            // console.log(e.target.tagName)
            // 点击的标签名,当为A时执行
            if(e.target.tagName=='A'){
                //获取id,比如点击第一个,则返回0,即a中id保存的是其在数组中的位置
                //console.log(e.target.id);
                student.splice(e.target.id,1)
                //重新渲染页面
                showTable()
            }   
        })
    script>
body>
html>

JS进阶webAPIs_第13张图片

5.举个栗子:手风琴特效
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>
        *{
            margin: 0;
            padding: 0;
        }
        div{
            width: 1000px;
            margin: 0 auto;
            font-size:0;
            /* 消除img之间的空隙 */
        }
        img{
            width: 200px;
            height:500px
        }
        .show{
            width: 800px;
        }
        .hidden{
            width: 50px;
        }
    style>
head>
<body>
    <div>
        <img src="image/1.jpg">
        <img src="image/2.jpg">
        <img src="image/3.jpg">
        <img src="image/4.jpg">
        <img src="image/5.jpg">
    div>
    <script>
        let imglist=document.querySelectorAll('img')
        // imglist[0].classList.add('show')
        for(let i=0;i<imglist.length;i++)
        {
            //鼠标经过
            imglist[i].addEventListener('mouseenter',function(){
                for(let j=0;j<imglist.length;j++)
                    //目前多个元素一起设置只能一个一个设置,到后期学其他的可以一下子一起设置
                    imglist[j].classList.add('hidden')
                this.classList.remove('hidden')
                this.classList.add('show')
            })
            //鼠标离开
            imglist[i].addEventListener('mouseleave',function(){
                for(let j=0;j<imglist.length;j++){
                    imglist[j].classList.remove('show')
                    imglist[j].classList.remove('hidden')
                } 
            })
        }
    script>
body>
html>

五、DOM网页特效

1.滚动和加载事件
(1)滚动事件—scroll

当页面进行滚动时触发,比如滚动时固定导航栏、或者点击按钮可以直接返回顶部

用到最多的就是监听整个页面滚动—window.addEventListener('scroll',function(){})

(2)加载事件—loadDOMContentLoaded
①load当资源加载完成触发

加载外部资源(如图片、外联CSS和Javascript等)加载完毕时触发事件。

有些时候需要等页面资源全部处理完了做一些事情;

或者老代码喜欢把script写到head中,这时候直接找DOM元素找不到

用到最多的就是监听所有资源加载完毕—window.addEventListener('load',function(){})

这个事件可以放到任何地方,因为是要等所有资源加载完毕才执行,但是还是提倡写在下面

②DOMContentLoaded当初始HTML文档被完全加载和解析完成触发

当初始HTML文档被完全加载和解析完成触,而无需等待样式表、图像等完全加载

2.元素大小和位置

掌握元素大小和位置的获取方式,为后续网页特效打基础

  • scroll家族

    • 获取元素内容的总大小
    • 获取元素向左向上滚出去看不见的距离可读写属性
  • offset家族

    • 获取元素自身大小:包括自身设置的宽高、padding、border
    • 获取元素距离定位父级的左和上距离只读属性
  • client家族

    • 获取元素可见区域的大小
    • 获取元素左、上边框距离只读属性
(1)scroll家族

比如我们想要页面滚动一段距离后就将一些元素显示或隐藏,那么就可以使用scroll来检测滚动距离

①获取宽高:scrollWidthscrollHeight:元素内容的总宽高,不包含滚动条

获取元素的内容总宽高(不包含滚动条)返回值不带单位

<style>
    div{
        width: 100px;
        height: 100px;
        background-color: skyblue;
        /* 滚动条 */
        overflow: auto;
    }
style>
<div>
大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好大家好
div>
<script>
    let div=document.querySelector('div')
    //内容的大小
    console.log(div.scrollWidth)//100不带单位
    console.log(div.scrollHeight)//478不带单位
    //有了滚动条后内容的宽度改变为83,高度为582
script>
②获取位置:scrollLeftscrollTop

获取元素内容向左或者向上滚动出去看不到的距离,这两个属性是可以修改

//页面滚动事件
window.addEventListener('scroll',function(){
    //获取当前页面被卷去的头部
    let num=document.documentElement.scrollTop
    //可以修改,即只要一滚动那么会直接滚动到500
	documentElement.scrollTop=500
    console.log(num)
})

window.addEventListener('scroll',function(){
    //获取当前页面被卷去的左边
    let num=document.documentElement.scrollLeft
    console.log(num) 
})

document.documentElement是整个页面文档即...

③举个栗子:返回页面顶部按钮
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>
        a{
            text-decoration: none;
            color:black;
            font-size: 35px;
        }
        .return{
            background-color: aquamarine;
            border-radius: 50px;
            width: 50px;
            height: 50px;
            position: fixed;
            right:10px;
            bottom: 10px;
            text-align: center;
        }
        .text{
        width: 100px;
        height:2000px;
        background-color:skyblue;
        }
    style>
head>
<body>
    <div class="text">div>
    <div class="return"><a href="javascript:">a>div>
    <script>
        let ret=document.querySelector('.return')
        //页面滚动事件
        window.addEventListener('scroll',function(){
            let num=document.documentElement.scrollTop
            console.log(num)
            //当顶部向上滚动到500时显示返回顶部按钮
            if(num>=500)
                ret.style.display='block'
            else
                ret.style.display='none'
        })
        //点击返回事件
        ret.addEventListener('click',function(){
            document.documentElement.scrollTop=0
        })
    script>
body>
html>

JS进阶webAPIs_第14张图片

JS进阶webAPIs_第15张图片

(2)offset家族

前面案例滚动多少距离,都是我们自己算的(如上面例子中的500),最好是页面滚动到某个元素,就可以做某些事。

简单说,就是通过js的方式,得到元素在页面中的位置这样我们可以做,页面滚动到这个位置,就可以返回顶部的小盒子显示。如当我们滑动到某个元素距离顶部多少像素时,显示返回顶部

①获取宽高:offsetWidthoffsetHeight:元素自身宽高,包含padding和border

获取元素的自身宽高、包含元素自身设置的宽高、padding、border

let div=document.querySelector('div')
//盒子的大小,和内容无关,包含padding、border
console.log(div.offsetWidth)//100不带单位
console.log(div.offsetHeight)//100不带单位
②获取位置:offsetLeftoffsetTop

获取元素距离自己定位父级元素的左、上距离,若父级没有定位则一层一侧向上找,直到body。这两个属性是只读属性,不可以修改

let div=document.querySelector('div')
//页面滚动事件
window.addEventListener('scroll',function(){
    console.log(div.offsetTop)
    console.log(div.offsetLeft)
})
③举个栗子:京东固定导航栏
<style>
    *{
        margin: 0;
        padding: 0;
        box-sizing: border-box;
    }
    header{
        position: fixed;
        top: -80px;
        /* 当滚动到一定位置再改为0 */
        left: 0;
        width: 100%;
        height: 80px;
        background-color: purple;
        text-align: center;
        color: white;
        transition: all .3s;
    }
    .content{
        overflow: hidden;
        width: 1000px;
        height: 3000px;
        background-color: pink;
        margin: 0 auto;
    }
    .sk{
        width: 300px;
        height: 300px;
        background-color: skyblue;
        margin-top: 500px;
    }
style>
<header>导航栏header>
<div class="content">
    <div class="sk">秒杀模块div>
div>
<script>
    let header=document.querySelector('header')
    let sk=document.querySelector('.sk')
    //1.页面滚动事件
    window.addEventListener('scroll',function(){
        //2.检测滚动的距离>=秒杀模块的offsetTop,则滑入
        if(document.documentElement.scrollTop>=sk.offsetTop)
            header.style.top=0
        else
            header.style.top='-80px'
    })
script>
④举个栗子:电梯导航

需求:

①点击当前小导航栏,当前添加active,其余移除active

②得到对应内容的offsetTop值

③让页面的scrollTop走到对应内容的offsetTop

<style>
    *{
        margin: 0;
        padding: 0;
        box-sizing: border-box;
    }
    body{
        height: 3000px;
    }
    .content1{
        width: 600px;
        height: 400px;
        background-color: blueviolet;
        margin: 10px auto;
        color: white;
    }
    .content2{
        width: 600px;
        height: 400px;
        background-color: blue;
        margin: 10px auto;
        color: white;
    }
    .content3{
        width: 600px;
        height: 400px;
        background-color: cadetblue;
        margin: 10px auto;
        color: white;
    }
    .content4{
        width: 600px;
        height: 400px;
        background-color: burlywood;
        margin: 10px auto;
        color: white;
    }
    .item{
        text-decoration: none;
        color: #000;
        display: block;
        width: 60px;
        text-align: center;
    }
    .active{
        color: white;
        background-color: red;
    }
    .aside{
        position: fixed;
        left: 0;
        top: 50%;
    }
style>

<div class="aside">
    <div class="item active">男装div>
    <div class="item">女装div>
    <div class="item">童装div>
    <div class="item">鞋帽div>
div>
<div class="content">
    <div class="neirong content1">男装div>
    <div class="neirong content2">女装div>
    <div class="neirong content3">童装div>
    <div class="neirong content4">鞋帽div>
div>
<script>
    //1.获取元素
    let items=document.querySelectorAll('.item')
    let neirongs=document.querySelectorAll('.neirong')
    //2.aside点击谁谁高亮
    for (let i = 0; i < items.length; i++) {
        items[i].addEventListener('click',function(){
            //找到上一个active类,移除
            document.querySelector('.aside .active').classList.remove('active')
            //点击谁,谁添加类
            this.classList.add('active')
            //3.右侧内容跟随走动
            // //获取盒子的位置
            // console.log(neirongs[i].offsetTop);
            document.documentElement.scrollTop=neirongs[i].offsetTop
        })
    }
script>
(3)client家族
①获取宽高:clientWidthclientHeight:当前可视区域,不包含边框和滚动条

获取元素的可见部分的宽高(不包含边框,滚动条等)

let div=document.querySelector('div')
//不包含边框,滚动条等
console.log(div.clientWidth)//83不带单位
console.log(div.clientHeight)//100不带单位
②resize事件:在窗口尺寸发生改变时触发
//得到窗口宽高,并且当宽度变化时背景颜色变色
window.addEventListener('resize',function(){
    let w=document.documentElement.clientWidth
    if(w<200)   document.body.style.backgroundColor='skyblue'
    else if(w<400)   document.body.style.backgroundColor='pink'
    else if(w<800)   document.body.style.backgroundColor='red'
    else   document.body.style.backgroundColor='green'
    console.log('页面宽度:'+document.documentElement.clientWidth);
    console.log('页面高度:'+document.documentElement.clientHeight);
})
(4)轮播图案例

需求:

①小图标鼠标经过事件

鼠标经过小图片,当前高亮,其余兄弟变淡,添加类

②大图片跟随变化

对应的大图片跟随显示,如果想要过度效果,可以使用opacity效果,可以利用CSS淡入淡出的效果,还是添加类

③左右侧按钮播放效果

点击右侧按钮,可以自动播放下一张图片

需要一个变化量index不断自增,然后播放下一张图片,如果到最后一张图片,必须要还原为第一张图片:索引号=索引号%数组长度(放到播放前面)

因为左右侧按钮有大量相同的操作,可以封装一个函数common

④解决一个BUG

点击右侧按钮可以实现播放下一张,但是鼠标经过前面的,播放就会乱序

解决方案:让变化量(索引号)重新赋值为当前鼠标经过的索引号

⑤开启定时器

定时器自动播放,相当于点击右侧按钮,只需right.click()

⑥鼠标经过停止定时器(清除定时器),鼠标离开开启定时器(开启定时器)


二、window对象学习内容

1.BOM(浏览器对象模型)

JS进阶webAPIs_第16张图片

  • window是浏览器内置中的全局对象,我们所学习的所有Web APls的知识内容都是基于window对象实现的
  • window对象下包含了navigator、 location、document、history、screen 5个属性,即所谓的BOM(浏览器对象模型)
  • document是实现DOM的基础,它其实是依附于window的属性。
  • 注:依附于window对象的所有属性和方法,使用时可以省略window
2.定时器-延迟函数
let timer=setTimeout(回调函数,等待的毫秒数)
clearTimeout(timer)//停止延迟函数

让代码延迟执行的函数,setTimeout仅仅执行一次,平时省略window

function Hello(){
    alert('Hello')
}
//提前结束延迟函数
//clearTimeout(timer)
let timer=setTimeout(Hello,3000)//3秒后执行
延迟函数结合递归函数实现setInterval
let clock=document.querySelector('.clock')
function myInterval(){
    let d=new Date()
    clock.innerText=d.toLocaleString()
    //延迟任务,自动调用,1秒后执行
    setTimeout(myInterval,1000)
}
myInterval()
3.js执行机制:面试常见
(1)JS是单线程

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

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

(2)同步和异步

为了解决这个问题,利用多核CPU的计算能力,HTML5提出 web Worker 标准,允许JavaScript脚本创建多个线程。于是,JS中出现了同步和异步。

同步:即任务之间有顺序,前一个任务结束后再执行后一个顺序。

异步:即在做一个任务的期间可以同时一时间再做其他任务。

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

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

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

1、普通事件,如click、resize等

2、资源加载,如 load、error等

3、定时器,包括setlnterval、setTimeout等

异步任务相关添加到任务队列中(任务队列也称为消息队列

(3)JS执行机制–先同步后异步

1.先执行执行栈中的同步任务

2.异步任务放入任务队列中。

3.一旦执行栈中的所有同步任务执行完毕,系统就会按次序读取任务队列中的异步任务,于是被读取的异步任务结束等待状态,进入执行栈,开始执行。

console.log(111)
setTimeout(function(){
    console.log(222);
},0)
console.log(333)
// 执行结果:
// 111  
// 333 
// 222

JS进阶webAPIs_第17张图片

(4)事件循环

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

4.location对象

location的数据类型是对象,它拆分并保存URL地址的各个组成部分

常用属性和方法:

(1)href 属性获取完整的URL地址,对其赋值时用于地址的跳转
//得到url地址,给的地址是字符串,可以使用js的方式跳转页面
console.log(location.href)
location.href='http://www.baidu.com'//跳转到百度
举个栗子:5秒后自动跳转页面
<a href="http://www.baidu.com">登录成功,<span style="color: red;">5</span>秒之后跳转页面至百度</a>
<script>
    let span=document.querySelector('span')
	let count=5
	let Timer=setInterval(function(){
        count--
        span.innerHTML=`${count}`
        if(count==0){
            clearInterval(Timer)
            location.href='http://www.baidu.com'
		}
	}, 1000)
</script>
(2)search属性获取地址中携带的参数,符号?后面部分

43.form.html

<form action="44.target.html"><!--提交后跳转页面-->
    <input type="text" name="username">
    <button>提交</button>
</form>

输入:123

44.target.html

//获取43文件提交的信息
	console.log(location.search)

输出结果:?username=123
(3)hash 属性获取地址中的啥希值,符号#后面部分
<a href="#one.html">第一个</a>
<a href="#two.html">第二个</a>
<script>
    console.log(location.hash);
//输出结果:点击第一个超链接,输出#one.html;点击第二个超链接,输出#two.html
//并且页面地址最后会改变,
//file:///D:/Javascript/45.location.hash.html#one.html
//file:///D:/Javascript/45.location.hash.html#two.html
</script>

后期学习vue路由的铺垫,经常用于不刷新页面,显示不同页面,比如网易云音乐

(4)reload方法用来刷新当前页面,传入参数true时表示强制刷新
<button>刷新button>
<script>
    let btn=document.querySelector('button')
    btn.addEventListener('click',function(){
        //刷新按钮,有本地缓存
        location.reload()
        //强制刷新,和ctrl+f5一样,直接更新最新内容,从网络获取
        location.reload(true)
    })
script>
5.navigator对象

location的数据类型是对象,该对象下记录了浏览器自身的相关信息

通过userAgent检测浏览器的版本及平台

//检测userAgent(浏览器信息)
!(function (){
    const userAgent = navigator.userAgent
    //验证是否为Android或iPhone
    const android = userAgent.match(/(Android);?[\s\/]+([\d.]+)?/)
    const iphone = userAgent.match(/(iPhone\sos)ls([id_]+)/)

    //如果是Android或iPhone,则跳转至移动站点
    if (android || iphone)
        location.href = 'http://www.baidu.com'
})()
6.history对象(了解)

history 的数据类型是对象,该对象与浏览器地址栏的操作相对应,如前进、后退、历史记录

history对象 作用
back() 可以后退功能
forward() 前进功能
go(参数) 前进后退功能,参数为1是前进一个页面,-1是后退一个页面

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

<button class="forward">前进button>
<button class="back">后退button>
<script>
    let forward=document.querySelector('.forward')
    let back=document.querySelector('.back')
    forward.addEventListener('click',function(){
        // history.forward()
        history.go(1)
    })
    back.addEventListener('click',function(){
        // history.back()
        history.go(-1)
    })
script>
7.swiper插件

swiper是一个开源、免费、强大的触摸滑动插件。这样我们可以不需要自己一步步编写轮播图等一些常用的功能,而可以直接使用swiper插件。学习如何使用插件

插件:就是别人写好的一些代码,我们只需要复制对应的代码,就可以直接实现对应的效果

学习插件的基本过程

熟悉官网,了解这个插件可以完成什么需求:https: //www.swiper.com.cn/

看在线演示,找到符合自己需求的demo https://www.swiper.com.cn/demo/index.html

查看基本使用流程https:// www.swiper.com.cn/usage/index.html

查看APi文档,去配置自己的插件https:// www.swiper.com.cn/api/index.html

下载插件后,解压找到swiper-bundle.js和swiper-bundle.css以及swiper-bundle.min.js、swiper-bundle.min.css。其中前两个是自己使用查询看的,后两个是实际使用时用的,因为压缩过,更小。将这两个文件复制放入代码文件夹中的css文件夹和js文件夹中

若无法上网,也可以直接点击demos文件夹,里面存放了demo的代码

注意:多个swiper同时使用的时候,类名需要注意区分

DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <title>Swiper demotitle>
    <meta name="viewport"content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1"/>
    
    <link rel="stylesheet" href="css/swiper-bundle.min.css"/>
    
    <style>
    .box{
        width: 1000px;
        height: 600px;
        margin: 0 auto;
    }
      html,
      body {
        position: relative;
        height: 100%;
      }

      body {
        background: #eee;
        font-family: Helvetica Neue, Helvetica, Arial, sans-serif;
        font-size: 14px;
        color: #000;
        margin: 0;
        padding: 0;
      }

      .swiper {
        width: 100%;
        padding-top: 50px;
        padding-bottom: 50px;
      }

      .swiper-slide {
        background-position: center;
        background-size: cover;
        width: 600px;
        height: 400px;
      }

      .swiper-slide img {
        display: block;
        width: 100%;
      }
    style>
  head>

  <body>
    <div class="box">
        
        <div class="swiper mySwiper">
            <div class="swiper-wrapper">
            <div class="swiper-slide">
                <img src="./image/1.jpg" />
            div>
            <div class="swiper-slide">
                <img src="./image/2.jpg" />
            div>
            <div class="swiper-slide">
                <img src="./image/3.jpg" />
            div>
            <div class="swiper-slide">
                <img src="./image/4.jpg" />
            div>
            <div class="swiper-slide">
                <img src="./image/5.jpg" />
            div>
            div>
            <div class="swiper-pagination">div>
        div>
    div>
    

    
    <script src="js/swiper-bundle.min.js">script>

    
    <script>
      var swiper = new Swiper(".mySwiper", {
        effect: "coverflow",
        grabCursor: true,
        centeredSlides: true,
        slidesPerView: "auto",
        coverflowEffect: {
          rotate: 50,
          stretch: 0,
          depth: 100,
          modifier: 1,
          slideShadows: true,
        },
        pagination: {
          el: ".swiper-pagination",
        },
      });
    script>
  body>
html>

JS进阶webAPIs_第18张图片

8.本地存储

随着互联网的快速发展,基于网页的应用越来越普遍,同时也变的越来越复杂,为了满足各种各样的需求,会经常性在本地存储大量的数据,HTML5规范提出了相关解决方案。

1、数据存储在用户浏览器中

2、设置、读取方便、甚至页面刷新不丢失数据

3、容量较大,sessionStorage和localStorage约5M左右

(1)localStorage
  • 生命周期永久生效,除非手动删除否则关闭页面也会存在
  • 可以多窗口(页面)共享(同一浏览器可以共享)
  • 键值对的形式存储使用
①存储简单数据
// 存储数据:
// localStorage.setItem(key,value)
localStorage.setItem('uname','张三')

// 获取数据:
// localStorage.getItem(key)
localStorage.getItem('uname')
console.log(localStorage.getItem('uname'))

// 删除数据:
// localStorage.removeItem(key)
localStorage.removeItem('uname')

可以按F12,查看应用->本地存储

JS进阶webAPIs_第19张图片

②存储复杂数据

本地存储只能存储字符串,无法存储复杂数据类型,需要将复杂数据类型转换成JSON字符串,再存储到本地

let obj={
    uname:'张三',
    age:30,
    gender:'男'
}
// 存储数据:
// JSON.stringify(复杂数据类型):将复杂数据类型转换成 JSON字符串存储到本地
// console.log(JSON.stringify(obj))
// 输出结果:{"uname":"张三","age":30,"gender":"男"}
localStorage.setItem('obj',JSON.stringify(obj))

// 取出数据:
// JSON.parse(JSON字符串):将JSON字符串转换成对象,取出时使用
// localStorage.getItem('obj')
console.log(JSON.parse(localStorage.getItem('obj')))

JSON属性和值都是双引号进行包含。

(2)sessionStorage(了解)
  1. 生命周期为关闭浏览器窗口
  2. 在同一个窗口(页面)下数据可以共享
  3. 以键值对的形式存储使用
  4. 用法跟localStorage基本相同
(3)举个栗子:学生管理案例(本地存储版)

需求:改为本次存储版本的学习信息表分析:
①读取本地存储数据(封装函数)
如果本地存储有数据,则返回JSON.parse()之后的对象
如果本地存储没有数据,则默认写入三条数据,注意存储的利用JSON.stringify()存储JSON格式的数据
②渲染模块
先读取本地存储数据,然后渲染
③添加模块
注意,先取的最新的本地存储数据,然后追加。新增了数据,要把新数据存储到本地存储别,忘记转换

④删除模块
先读取本地存储数据,删除数组元素后再更新到本地存储,然后渲染

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>
        *{
            margin: 0;
            padding: 0;
        }
        input{
            width: 70px;
            border: 1px solid skyblue;
        }
        select{
            border: 1px solid skyblue;
        }
        button{
            width: 40px;
            color: white;
            background-color:teal;
            border-radius: 5px;
        }
        h2{
            margin-top: 20px;
            text-align: center;
        }
        table{
            text-align: center;
            width: 700px;
            border: 1px solid skyblue;
            border-collapse: collapse;
        }
        tr,th,td{
            height: 50px;
            border: 1px solid teal;
        }
        th{
            background-color: skyblue;
        }
        tbody tr:hover{
            background-color: #eee;
        } 
        a {
            text-decoration: none;
            color: teal;
        }
        .add{
            width: 700px;
            margin: 0 auto;
        }
    style>
head>
<body>
    <div class="add">
        <h2>新增学生h2><br>
        姓名:<input type="text" class="name">
        年龄:<input type="text" class="age">
        性别:<select name="gender" class="gender">
            <option value="">option>
            <option value="">option>
        select>
        薪资:<input type="text" class="salary">
        就业城市:<input type="text" class="city">
        <button class="add_btn">录入button>
        <h2>学生信息表h2>
        <table>
            <thead>
                <tr>
                    <th>学号th>
                    <th>姓名th>
                    <th>年龄th>
                    <th>性别th>
                    <th>薪资th>
                    <th>就业城市th>
                    <th>删除th>
                tr>
            thead>
            <tbody>

            tbody>
        table>
    div>
    <ul>
    ul>
    <script>
        // 从本地存储中取数据,封装为函数
        function getLocalDate(){
            let data=localStorage.getItem('data')
            //若有数据则转换类型
            if(data&&data!='[]')
                return JSON.parse(data)
            //若没有数据则默认写入一条数据
            else{
                let student=[
                    {id:1001,name:'张三',age:20,gender:'男',salary:'20',city:'北京'},
                    {id:1001,name:'李四',age:20,gender:'女',salary:'25',city:'广州'},
                ]
                localStorage.setItem('data',JSON.stringify(student))
            }
        }
        // getLocalDate()

        let tbody=document.querySelector('tbody')
        //根据数组进行渲染
        function showTable(){
            //获取本地数据
            let student=getLocalDate()
            //先删除以前的数据
            tbody.innerHTML=''
            //再渲染新的数据
            for(let i=0;i<student.length;i++)
            {
                //创建tr
                let tr=document.createElement('tr')
                //tr内的内容
                tr.innerHTML=`
                    ${student[i].id}
                    ${student[i].name}
                    ${student[i].age}
                    ${student[i].gender}
                    ${student[i].salary}
                    ${student[i].city}
                    ${i}">删除
                `
                //给删除添加id以方便删除时获取id
                tbody.appendChild(tr)
            }
        }
        showTable()
        
        //添加学生
        //获取提交按钮
        let add_btn=document.querySelector('.add_btn')
        //获取各个表单元素
        let name=document.querySelector('.name')
        let age=document.querySelector('.age')
        let gender=document.querySelector('.gender')
        let salary=document.querySelector('.salary')
        let city=document.querySelector('.city')
        //添加点击提交事件
        add_btn.addEventListener('click',function(){
            let student=getLocalDate()
            //若非空则添加到数组
            if(Empty(name.value)&&Empty(age.value)&&Empty(gender.value)&&Empty(salary.value)&&Empty(city.value)){
                let stuId
                if(student.length!=0)
                    stuId=student[student.length-1].id+1
                else//若数组为空,则学生学号从1001开始
                    stuId=1001
                student.push({
                    id: stuId,//最后一个元素的Id+1
                    name: name.value,
                    age: age.value,
                    gender: gender.value,
                    salary: salary.value,
                    city: city.value
                })
                //将数组更新到本地
                localStorage.setItem('data',JSON.stringify(student))
                //重新渲染函数
                showTable()
                //将表单恢复为空
                name.value=age.value=salary.value=city.value=''
                gender.value='男'
            }
        }
        )
        //判断input非空,之后可以使用正则
        function Empty(value){
            if(value.trim()!='') return true
            else{
                alert('添加学员数据不可为空')
                return false
            }    
        }
        
        //事件委托进行删除
        let del=document.querySelector('tbody')
        del.addEventListener('click',function(e){
            let student=getLocalDate()
            // console.log(e.target.tagName)
            // 点击的标签名,当为A时执行
            if(e.target.tagName=='A'){
                //获取id,比如点击第一个,则返回0,即a中id保存的是其在数组中的位置
                //console.log(e.target.id);
                student.splice(e.target.id,1)
                localStorage.setItem('data',JSON.stringify(student))
                //重新渲染页面
                showTable()
            }   
        })
    script>
body>
html>
9.正则表达式

用于匹配字符串中字符组合的模式

作用:

  • 表单验证(匹配)
  • 过滤敏感词(替换)

(1)字符表达式语法

let 变量名=/表达式/
//变量名存储的是一个正则表达式的对象
eg:let x=/Hello World/

(2)判断是否符合规则的字符串

//表达式变量.test(要匹配的字符串)
let str='My name is PCGuo,Hello World'
let bl=x.test(str)
//输出:true

正则表达式具体学习看之前笔记

你可能感兴趣的:(前端,javascript,前端,html)