WebAPI

WebAPI

文章目录

一、DOM

1. 作用和分类

作用:就是使用JS去操作html和浏览器

分类:DOM(文档对象模型)、BOM(浏览器对象模型)

2. 什么是DOM

DOM (Document Object Model —— 文档对象模型)是用来呈现以及与任意HTML 或XML文档交互的API

DOM作用:

开发网页内容特效实现用户交互

3. DOM树

DOM树是什么?

将HTML文档以树状结构直观的表现出来,我们称之为文档树或DOM树

描述网页内容关系的名词

作用:文档树直观的体现了标签与标签之间的关系

4. DOM 对象

DOM对象:浏览器根据html标签生成的js对象

​ 所有的标签属性都可以在这个对象上面找到

​ 修改这个对象的属性会自动隐射到标签身上

DOM的核心思想

​ 把网页内容当做对象来处理

document对象

​ 是DOM里提供的一个对象

​ 所有他提供的属性和方法都是用来访问和操作网页内容的

​ 例如:(document.write())

​ 网页作用的内容都在document里面

5. 获取元素

5.1 选择匹配元素
    // 语法:
    document.querySelector('css选择器')

参数:

包含一个或多个有效的CSS选择器字符串

返回值:

CSS选择器匹配的第一个元素,一个HTMLElement对象。如果没有匹配到,则返回null

5.2 选择匹配多个元素
// 语法:
document.querySelectorAll('css选择器')
  1. 参数:

包含一个或多个有效的css选择器字符串

  1. 返回值:

css选择器匹配的NodeList对象集合

通过querySelectorAll获取过来的是一个伪数组:

有长度有索引号的数组

但是没有pop() push()等数组方法

5.3 获取元素方式
// 根据id获取一个元素
document.getElementById('nav')
// 根据 标签获取一类元素 获取页面所有div
document.getElementsByTagName('div')
// 根据 类名获取元素 获取页面所有类名为w的
document.getElementsByClassName('w')

二、样式操作案例

1.修改元素内容

1.1 元素.innerText属性
  1. 将文本内容添加 /更新到任意标签位置

  2. 文本中包含的标签不会被解析

// 1. 获取标签(元素)
let box = document.querySelector('div')
// 2. 修改标签(元素)内容 box是对象 innerText 属性
//  对象.属性 = 值
box.innerText = '有点意思~'
1.2 元素.innerHTML 属性
  1. 将文本内容添加 / 更新到任意标签位置

  2. 文本中的标签会被解析

// 1. 获取元素
let box = document.querySelector('div')
// 2. 修改标签
box.innerHTML = '<strong>美和易思</strong>'
1.3 三者区别
  1. document.write() 方法 只能追加到body中

  2. 元素.innerText属性 只识别内容,不能解析标签

  3. 元素.innerHTML 属性 能够解析标签

  4. 推荐用(innerHTML)

// 随机点名
 // 1. 获取元素
      let box = document.querySelector('div')
      // 2. 得到随机名字
      // 随机函数
      function getRandom (min,max) {
        return Math.floor(Math.random() * max - min + 1) + min
      }
      let arr = ['关羽','张飞','刘备','马超','黄忠','曹操','赵云','貂蝉']
      let random = getRandom(0,arr.length - 1)
      // 3. 写入标签内部
      box.innerHTML = arr[random]
      arr.splice(arr[random],1)

2. 修改元素常用属性

还可以通过js设置 / 修改标签元素属性,比如通过src更换图片

最常见的属性比如:href、title、src

语法:

对象.属性 = 值

// 1. 获取元素
let pic = document.querySelector('img')
// 2. 修改元素属性 src
pic.src = './images/3.jpg'
pic.title = '这是一张图片'
// 随机图片
<img src="./images/course01.png" alt="">   
   <script>
    // 1.获取图片元素
    let pic = document.querySelector('img')
    // 2. 随机图片
    // 随机函数
    function getRandom (min,max) {
        return Math.floor(Math.random() * (max - min + 1)) + min
    }
    let num = getRandom(1,6)
    // 3. 完成src属性赋值
    pic.src = `./images/course0${num}.png`
   </script>

3. 设置 / 修改元素样式属性

还可以通过js设置 / 修改标签元素的样式属性

比如通过轮播图小圆点自动更换样式颜色

点击按钮可以滚动图片,这是移动的图片的位置left等等

3.1 通过style属性操作css

语法;

对象.style.样式属性 = 值

<div> </div>
   <script>
    // 1. 获取元素
    let box = document.querySelector('div')
    // 2. 修改元素属性
    box.style.backgroundColor = '#333'
    box.style.width = '800px'
    box.style.height = '500px'
    box.innerHTML = '疾风亦有归途'
    box.style.color = 'pink'
    box.style.marginRight = '100px'
   </script>

注意:

  1. 修改样式通过style属性引出
  2. 如果属性有-连接符,需要转换为小驼峰命名法
  3. 赋值的时候,需要的时候不要忘记加css单位
3.2 通过类名(className) 操作CSS

如果修改样式比较多,直接通过style属性修改比较繁琐,我们可以借助与css类名的形式

// 语法:
 元素.className = 'active'

注意:

  1. 由于class是关键字,所以使用className去代替
  2. 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>
         .box {
            margin: 0 auto;
            width: 300px;
            height: 300px;
            background-color: pink;
            text-align: center;
            line-height: 500px;
        }
    </style>
</head>
<body>
   <div class="box"></div>
   <script>
    // 1. 获取元素
    let box = document.querySelector('div')
    // 2. 修改元素属性
    box.className = 'box'
   </script>
</body>
</html>
3.3 通过classlist 操作类控制CSS

为了解决className容易覆盖以前的类名,我们可以通过classList方式追加和删除类名

// 追加一个类
元素.classList.add('类名')
// 删除一个类
元素.classList.remove('类名')
// 切换一个类
元素.classList.toggle('类名')
// 1. 获取元素
let box = document.querySelector('div')
// 添加
box.classList.add('active') 
// 删除
box.classList.remove('one')
// 切换
box.classList.toggle('one')

4. 修改表单

表单很多情况,也需要修改属性,比如点击眼睛,可以看到密码,本质是把表单类型转换为文本框

 <input type="text" value="请输入">
   <button disabled>点击</button>
   <input type="checkbox" name="" id="" class="check">
   <script>
    // 1. 获取元素
   let input = document.querySelector('input')
   let btn = document.querySelector('button')
   let checkbox = document.querySelector('.check')
    // 2. 修改元素属性
    input.value = '账号'
    input.type = 'password'
    // 3. 按钮是否禁用
    btn.disabled = true
    btn.disabled = false
    // 4. 复选框默认勾选
    checkbox.checked = true
   </script>

5. 定时器间歇函数

定时器函数可以开启和关闭定时器

1.开启定时器

setInterval(函数,间隔时间)

作用:每隔一段时间调用这个函数

间隔时间单位是毫秒

2.关闭定时器

let 变量名 = setInterval(函数,间隔时间)

clearInterval(变量名)

// 用户注册倒计时
<button class="btn" disabled>我已经阅读用户协议(6)</button>
    <script>
        // 1. 获取元素
        let btn = document.querySelector('.btn')
        // 2. 用一个变量计数
        let i = 5
        // 开启定时器
        let timer = setInterval(function () {
            i--
            btn.innerHTML = `我已经阅读用户协议(${i})`
            if (i === 0) {
                clearInterval(timer)
                // 开启按钮
                btn.disabled = false
                btn.innerHTML = `我同意该协议`
            }
        },1000)
    </script>
// 焦点图案
<script>
          let data = [
            {
                imgSrc: 'images/b01.jpg',
                title: '挑战云歌单,欢迎你来'
            },
            {
                imgSrc: 'images/b02.jpg',
                title: '田园日记,上演上京记'
            },
            {
                imgSrc: 'images/b03.jpg',
                title: '甜蜜攻势再次回归'
            },
            {
                imgSrc: 'images/b04.jpg',
                title: '我为歌狂,生为歌王'
            },
            {
                imgSrc: 'images/b05.jpg',
                title: '年度校园主题活动'
            },
            {
                imgSrc: 'images/b06.jpg',
                title: 'pink老师新歌发布,5月10号正式推出'
            },
            {
                imgSrc: 'images/b07.jpg',
                title: '动力火车来到西安'
            },
            {
                imgSrc: 'images/b08.jpg',
                title: '钢铁侠3,英雄镇东风'
            },
            {
                imgSrc: 'images/b09.jpg',
                title: '我用整颗心来等你'
            },
        ]
        // 1. 获取元素
        let pic = document.querySelector('.pic')
        let text = document.querySelector('.text')
        // 2. 设置初始变量
        let i = 0
        // 3. 开启定时器
        setInterval(function() {
            i++
            pic.src = data[i].imgSrc
            text.innerHTML = data[i].title
            // 判断边界
            if(i === data.length - 1) {
                i = -1
            }
        },1000)
    </script>

三、事件

1. 事件

1.1 什么是事件?

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

比如用户在网页上点击一个按钮

1.2 什么是事件监听

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

1.3 语法:
元素.addEventListener('事件',要执行的函数)
1.4 事件监听三要素:
  1. 事件源:那个dom元素被事件触发了,要获取dom元素
  2. 事件:用什么方式触发,比如鼠标单击click、鼠标经过mouseover等
  3. 事件调用的函数:要做什么事
<button>点击</button>
    <script>
        // 1.获取元素
        let btn = document.querySelector('button')
        // 2. 注册事件
        btn.addEventListener('click' , function(){
            alert('被点击了')
        })
    </script>
1.5 注意:
  1. 事件类型要加引号
  2. 函数是点击之后再去执行,每次点击都会执行一次
// 点名按钮
 // 数据数组
        let arr = ['马超', '黄忠', '赵云', '关羽', '张飞']
        function getRandom(min, max) {
            return Math.floor(Math.random() * (max - min + 1)) + min
        }
        // 1. 获取元素
        let qs = document.querySelector('.qs')
        let start = document.querySelector('.start')
        let end = document.querySelector('.end')
        let random = 0
        let timer = 0
        // 2. 绑定开始事件
        start.addEventListener('click',function(){
            // 开启定时器随机抽取数据
          timer = setInterval(function(){
                random = getRandom(0,arr.length - 1)
                qs.innerHTML = arr[random]
            },25)
           // 如果抽完了就禁用按钮
            if(arr.length === 1){
                start.disabled = end.disabled = true
            }
        })
        // 3. 绑定关闭事件
        end.addEventListener('click',function(){
            // 关闭定时器
            clearInterval(timer)
            // 删除元素
            arr.splice(random,1)
        })

四、事件类型

1. 事件类型

1.1 鼠标触发事件
  1. click 鼠标点击
  2. mouseenter 鼠标经过
  3. mouseleave 鼠标离开
1.2 表单获得光标
  1. focus 获得焦点
  2. blur 失去焦点
        let search = document.querySelector('input')
        let list = document.querySelector('.result-list')
        // 2. 绑定获取焦点事件
        search.addEventListener('focus',function (){
            // 显示下拉菜单
            list.style.display = 'block'
            // 文本框变色
            search.className = 'search'
        })
        // 3. 绑定失去
        search.addEventListener('blur',function(){
            // 隐藏下拉菜单
            list.style.display = 'none'
            // 取消文本框颜色
            search.classList.remove('search')
        })
1.3 键盘触发
  1. keydown 键盘按下触发
  2. keyup 键盘抬起触发
1.4 表单输入触发
  1. input 用户输入事件
 // 1. 获取元素
    let area = document.querySelector('#area')
    let useCount = document.querySelector('.useCount')
    // 2. 绑定键盘输入事件
    area.addEventListener('input',function(){
      useCount.innerHTML = area.value.length
    })

2. 多个元素绑定事件

 // 1. 获取元素
    let all = document.querySelector('#checkAll')
    let cks = document.querySelectorAll('.ck')
    let span = document.querySelector('span')
    // 2. 绑定点击事件
    all.addEventListener('click',function(){
      // 遍历伪数组依次赋值
      for(let i = 0; i < cks.length; i++) {
        cks[i].checked = all.checked
      }
      if(all.checked === true) {
        span.innerHTML = '取消'
      } else {
        span.innerHTML = '全选'
      }
    })
    // 3.给多个元素绑定事件
    for(let i = 0; i < cks.length; i++){
      cks[i].addEventListener('click',function(){
        for(let j = 0; j < cks.length; j++){
          if(cks[j].checked === false){
            all.checked = false
            return
          }
        }
        all.checked = true
      })
    }
// 购物车案例
<div>
    <input type="text" id="total" value="1" readonly>
    <input type="button" value="+" id="add">
    <input type="button" value="-" id="reduce" >
    <script>
      // 1. 获取元素
      let total = document.querySelector('#total')
      let add = document.querySelector('#add')
      let reduce = document.querySelector('#reduce')
      // 2. 点检加号事件监听
      add.addEventListener('click',function(){
        total.value++
        if(total.value > 1){
          reduce.disabled = false
        }
      })
      // 3. 点击减号事件监听
      reduce.addEventListener('click',function(){
        total.value--
        if(total.value <= 1){
          reduce.disabled = true
        }
      })
    </script>
  </div>

3. 高阶函数

  1. 高阶函数可以别简单理解为函数的高级应用,JavaScript中函数可以被当成[值] 来对待,基于这个特性实现函数的高级应用
  2. [值] 就是JavaScript中的数据,如数值、字符串、布尔、对象
1. 回调函数

如果将函数A做为参数传递给函数B时,我们称函数A为回调函数

简单理解:当一个函数当做参数来传递给另一个函数的时候,这个函数就是回调函数

// 回调函数
function fn() {
    
}
setInterval(fn,1000)
2. 环境对象

环境对象指的是函数内部特殊的变量this,它代表着当前函数运行时所处的环境

作用:弄清楚this的指向,可以让我们代码更简洁

​ 函数的调用方式不同,this指代的对象也不同

[谁调用,this就是谁] 是判断this指向的粗略规则

3. 排他思想

当前元素为A状态,其他元素为B状态

使用:

  1. 干掉所有人 :使用for循环
  2. 复活他自己:通过this或者下标找到自己或者对应的元素
// 排他思想
 // 1. 获取元素
        let btn = document.querySelectorAll('button')
        // 2. 监听事件
        for(let i = 0; i < btn.length; i++){
            btn[i].addEventListener('click',function(){
                this.style.backgroundColor = 'pink'
                for(let j = 0; j < btn.length; j++){
                    btn[j].style.backgroundColor = ""
                }
                this.style.backgroundColor = 'pink'
            })
        }
 // 1.获取元素
    let lis = document.querySelectorAll('.tab .tab-item')
    let divs = document.querySelectorAll('.products .main')
    // 2. 事件监听
    for(let i = 0; i < lis.length; i++) {
      lis[i].setAttribute('index',i)
      lis[i].addEventListener('click',function(){
        // 拿到当前active类移除掉
        document.querySelector('.tab .active').classList.remove('active')
        this.classList.add('active')
        // 底部模块隐藏
        let index = this.getAttribute('index') 
        for (let j = 0; j < divs.length; j++){
          divs[j].style.display = 'none'
        }
        divs[index].style.display = 'block'
      })
    }

4. 优化

// 1.获取元素
    let lis = document.querySelectorAll('.tab .tab-item')
    let divs = document.querySelectorAll('.products .main')
    // 2. 事件监听
    for(let i = 0; i < lis.length; i++) {
      lis[i].addEventListener('click',function(){
        // 拿到当前active类移除掉
        document.querySelector('.tab .active').classList.remove('active')
        this.classList.add('active')
        // 底部模块隐藏
        document.querySelector('.products .active').classList.remove('active')
        // 对应事件加上active
        divs[i].classList.add('active')       
      })
    }

五、节点操作

1. DOM节点

DOM树里每一个内容都称之为节点
1.1 节点类型

元素节点

  所有的标签比如body、div

​ html是根节点

属性节点

​ 所有的属性比如 href

文本节点

​ 所有的文本

其他

2. 查找父节点

let son = document.querySelector('.son')
son.addEventListener('click',function(){
    this.parentNode.style.display = 'none'
})

3. 查找子节点

3.1子节点查找:

childNodes

​ 获得所有子节点、包括文本特点(空格、换行)、注释节点等

children(重点)

​ 仅获得所有元素节点

​ 返回的还是一个伪数组

父元素.children
  // 1. 获取元素
        let btn = document.querySelector('button')
        let ul = document.querySelector('ul')
        // 2. 事件监听
        btn.addEventListener('click',function(){
            for(let i = 0; i < ul.children.length; i++){
                ul.children[i].style.color = 'pink'
            }
            ul.children[0].style.color = 'red'
        })

4. 兄弟关系查找

4.1 下一个兄弟节点

nextElementSibling属性

4.2 上一个兄弟节点

previousElementSibling属性

 // 1.获取元素
        let btn = document.querySelector('button')
        let tow = document.querySelector('.two')
        // 2. 给按钮绑定点击事件
        btn.addEventListener('click',function(){
            tow.nextElementSibling.style.color = 'red'
            tow.previousElementSibling.style.color = 'pink'
        })

5. 增加节点

5.1 创建节点

即创造出一个新的网页元素,再添加到网页内,一般先创建节点,然后插入节点

创建元素节点的方法:

document.createElement(‘标签名’)

// 1. 创建信的标签节点
let li = document.createElement('li')
5.2 追加节点
  1. 想要在界面看到,还得插入到某个父元素中

插入到父元素的最后一个子元素:

父元素.appendChild(要插入的元素)

 let ul = document.querySelector('ul')
        let lis = document.querySelector('li:first-child')
        // 1. 创建节点
        let li = document.createElement('li')
        li.innerHTML = '我是一个小li'
        // 2.追加节点
        ul.appendChild(li)
        li.style.color = 'pink'
        lis.style.color = 'red'
// 插入到父元素中某个子元素的前面
父元素.insertBefore(要插入的元素,在那个元素前面)
// 追加节点案例
 // 1. 获取元素
        let ul = document.querySelector('ul')
        // 2. 循环添加li
        for(let i = 0; i < data.length; i++){
            // 3. 创建节点
            let li = document.createElement('li')
            // 5. 追加内容
            li.innerHTML = `
            <img src="${data[i].src}" alt="">
                    <h4>
                        ${data[i].title}
                    </h4>
                    <div class="info">
                        <span>高级</span> • <span> ${data[i].num}</span>人在学习
                    </div>
            `
            // 4. 给父元素追加节点
            ul.appendChild(li)

6. 克隆节点

// 克隆一个已有的元素节点
元素.cloneNode(布尔值)

cloneNode会克隆出一个跟原标签一样的元素,括号内传入布尔值

若为true,则代表克隆时会包含后代节点一起克隆

若为false,则代表克隆时不包含后代节点

默认为false

 // 1. 获取元素
        let ul = document.querySelector('ul')
        let li = document.querySelector('li')
        let newLi = li.cloneNode()
        let newUl = ul.cloneNode(true)
        // 2. 追加到ul里面
        ul.appendChild(newUl)

7.删除节点

  1. 若一个节点在页面中已经不需要时,可以删除他
  2. 在JavaScript原生DOM操作中,要删除元素必须通过父元素删除
// 语法:
父元素.removeChild(要删除的元素)

注意:

  1. 如不存在父子关系则删除不成功
  2. 删除节点和隐藏节点(display:none)有区别的:隐藏节点还是存在的,但是删除,则从html中删除节点
 // 1.获取元素
        let btn = document.querySelector('button')
        let ul = document.querySelector('ul')
        // 2.注册点击事件删除节点
        btn.addEventListener('click',function(){
            ul.removeChild(ul.children[0])
        })

六、事件对象

1. 实例化

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

// 获得当前时间
let date = new Date()
// 获得指定时间
let date = new Date('2022-7-1 18:30:00')

2. 时间对象方法

方法作用
getFullYear()获得年份获取四位年份
getMonth()获得月份取值为0 ~ 11
getDate()获取月份中的每一天不同月份取值也不相同
getDay()获取星期取值为0 ~ 6
getHours()获取小时取值为0 ~ 23
getMinutes()获取分钟取值为0 ~ 59
getSeconds()获取秒取值为0 ~ 59
 let arr = ['星期一','星期二','星期三','星期四','星期五','星期六','星期天']
        let box = document.querySelector('div')
        getTimer() // 先调用一次解决1秒空白
        setInterval(getTimer,1000)
        function getTimer (){
            // 实例化时间对象
        let date = new Date()
        // 获取当前时间
       let year = date.getFullYear()
       let month = date.getMonth() + 1
       let day = date.getDate()
        // 获取时分秒
       let hour = date.getHours()
       let min = date.getMinutes()
       let sec = date.getSeconds()
       let day1 = date.getDay()       
        box.innerHTML = `今天是:${year}${month}${day}${hour}:${min}:${sec} ${arr[day1]}`
        }

3. 时间戳

3.1 什么是时间戳

是指2018年01月01日00时00分00秒起至现在的秒数,他是一个特殊的计量时间的方式

3.2 获取时间戳
// 1.使用getTime()方法
let date = new Date()
console.log(date.getTimer())
// 2. 简写+new Date()
console.log(+new Date())
// 3. 使用Date().now()
console.log(Date.now())
// 无需实例化
// 但是只能得到当前的时间戳,而前面两种可以返回指定时间的时间戳
3.3 倒计时
// 5. 获取元素
    let hour = document.querySelector('#hour')
    let minutes = document.querySelector('#minutes')
    let scond = document.querySelector('#scond')
    let tips = document.querySelector('.tips')
    let next = document.querySelector('.next')
    getTimer()
    setInterval(getTimer,1000)
    function getTimer(){
    // 1.获取现在的时间戳
    let now = +new Date()
    // 2. 获取指定时间的时间戳
    let last = +new Date('2022-7-1 21:00:00')
    // 3. 计算剩余时间
    let count = (last - now) / 1000
    // 4. 转换为时分秒
    let h = parseInt(count / 60 / 60 % 24)
    h = h < 10 ? '0' + h : h
    let m = parseInt(count / 60 % 60)
    m = m < 10 ? '0' + m : m
    let s = parseInt(count % 60)
    s = s < 10 ? '0' + s : s
    hour.innerHTML = h
    minutes.innerHTML = m
    scond.innerHTML = s
    }
    Time()
    setInterval(Time,1000)
    function  Time (){
      // 6 获取当前时间
    let date = new Date()
    let hour = date.getHours()
    let min = date.getMinutes()
    min = min < 10 ?  '0' + min : min
    let sec = date.getSeconds()
    sec = sec < 10 ? '0' + sec : sec
    tips.innerHTML = `现在是${hour}:${min}:${sec}`
    }
    Dya()
    function Dya(){
      let date = new Date()
      let yaer = date.getFullYear()
      let month = date.getMonth() + 1
      let day = date.getDate()
      next.innerHTML = `今天是${yaer}${month}${day}`
    }
3.4 总和案例–微博发布信息
 // maxlength 是一个表单属性, 作用是给表单设置一个最大长度

    // 模拟数据
    let dataArr = [
      { uname: '司马懿', imgSrc: './images/9.5/01.jpg' },
      { uname: '女娲', imgSrc: './images/9.5/02.jpg' },
      { uname: '百里守约', imgSrc: './images/9.5/03.jpg' },
      { uname: '亚瑟', imgSrc: './images/9.5/04.jpg' },
      { uname: '虞姬', imgSrc: './images/9.5/05.jpg' },
      { uname: '张良', imgSrc: './images/9.5/06.jpg' },
      { uname: '安其拉', imgSrc: './images/9.5/07.jpg' },
      { uname: '李白', imgSrc: './images/9.5/08.jpg' },
      { uname: '阿珂', imgSrc: './images/9.5/09.jpg' },
      { uname: '墨子', imgSrc: './images/9.5/10.jpg' },
      { uname: '鲁班', imgSrc: './images/9.5/11.jpg' },
      { uname: '嬴政', imgSrc: './images/9.5/12.jpg' },
      { uname: '孙膑', imgSrc: './images/9.5/13.jpg' },
      { uname: '周瑜', imgSrc: './images/9.5/14.jpg' },
      { uname: '老夫子', imgSrc: './images/9.5/15.jpg' },
      { uname: '狄仁杰', imgSrc: './images/9.5/16.jpg' },
      { uname: '扁鹊', imgSrc: './images/9.5/17.jpg' },
      { uname: '马可波罗', imgSrc: './images/9.5/18.jpg' },
      { uname: '露娜', imgSrc: './images/9.5/19.jpg' },
      { uname: '孙悟空', imgSrc: './images/9.5/20.jpg' },
      { uname: '黄忠', imgSrc: './images/9.5/21.jpg' },
      { uname: '百里玄策', imgSrc: './images/9.5/22.jpg' },
    ]
    // 1. 获取元素
    let textarea = document.querySelector('textarea')
    let useCount = document.querySelector('.useCount')
    let btn = document.querySelector('#send')
    let list = document.querySelector('#list')
    // 2. 给文本框绑定键盘输入事件
    textarea.addEventListener('input',function(){
      useCount.innerHTML = this.value.length
    })
    // 3. 给发布按钮绑定点击事件
    btn.addEventListener('click',function(){
      if(textarea.value.trim() === ''){
        textarea.value = ''
        useCount.innerHTML = 0
        return alert('内容不能为空!')       
      }
      // 随机换头像图片
    function getRandom (min,max){
      return Math.floor(Math.random() * (min,max + 1)) + min
    }
      let random = getRandom(0,dataArr.length - 1)
      // 创建一个li追加到ul后面
      let li = document.createElement('li')
      // 随机获取数组里面的内容
      li.innerHTML = `
      <div class="info">
      <img class="userpic" src= ${dataArr[random].imgSrc}>
      <span class="username">${dataArr[random].uname}</span>
      <p class="send-time">${new Date().toLocaleDateString()}</p>
    </div>
    <div class="content">${textarea.value}</div>
    <span class="the_del">X</span>
      `
      let del = li.querySelector('.the_del')
      del.addEventListener('click',function(){
        list.removeChild(li)
      })
       // 追加li
      list.insertBefore(li,list.children[0])
      // 发布完清空文本框
      textarea.value = ''
      useCount.innerHTML = 0
    }) 
    // 4. 绑定回车事件
    textarea.addEventListener('keyup',function(e){
      if(e.key === 'Enter'){
        btn.click()
      }
    })

综合案例

  // 1.获取元素
    let adds = document.querySelectorAll(".add")
    let reduces = document.querySelectorAll('.reduce')
    let dels = document.querySelectorAll('.del')
    let inputs = document.querySelectorAll('.count-c input')
    // 获取单价
    let prices = document.querySelectorAll('.price')
    // 小计 = 单价 * 数量
    let totals = document.querySelectorAll('.total')
    // 获取总价的元素
    let totalPrice = document.querySelector('.total-price')
    // 获取商品件数
    let totalCount = document.querySelector('#totalCount')
    // tbody 获取过里
    let carBody = document.querySelector('#carBody')
    // 2.给加号绑定点击事件添加操作
    for(let i = 0; i < adds.length; i++){
      totals[i].innerText = prices[i].innerText
      adds[i].addEventListener('click',function(){
        // 点击后对应输入框里的值自增
        inputs[i].value++
        // 减号启用
        reduces[i].disabled = false
        // 计算总价 = 单价 * 数量
        totals[i].innerHTML = parseInt(prices[i].innerHTML) * inputs[i].value + '¥'
        // 计算现在的总额 调用
        result()
      }) 
       // 3.给减号绑定点击事件
       reduces[i].addEventListener('click',function(){
        // 点击后对应输入框里的值自减
        inputs[i].value--
        // 计算总价 = 单价 * 数量
        totals[i].innerHTML = parseInt(prices[i].innerHTML) * inputs[i].value + '¥'
        // 判断数值是否小于0
        if(inputs[i].value <= 0){
        reduces[i].disabled = true
       }
       // 计算现在的总额 调用
       result()
       })
       // 4.删除模块
      dels[i].addEventListener('click',function(){
        // 要删除的是当前元素爸爸的爸爸
        carBody.removeChild(this.parentNode.parentNode)
        result()
      })   
    }
      // 计算总价
      function result(){
        // 获取商品件数
        let totalCount = document.querySelector('#totalCount')
        // 小计 = 单价 * 数量
        let totals = document.querySelectorAll('.total')
        let sum = 0
        let num = 0
        for(let i = 0; i < totals.length; i++){
          sum += parseInt(totals[i].innerText)
          num += parseInt(inputs[i].value)
        }
        totalPrice.innerText = sum + '¥'
        totalCount.innerText = num
      }
      result()

4. 重绘和回流(面试点)

4.1 浏览器是如何进行页面渲染的?

在这里插入图片描述

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

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

4.3 重绘

由于节点(元素)的样式的改变并不影响他在文档流中的位置和文档布局时(比如:color、background-color、outline等)称为重绘

重绘不一定引起回流,而回流一定会引起重绘

七、事件高级

1. 事件对象

1.1事件对象是什么?
  1. 也是个对象,这个对象里有事件触发时的相关信息
  2. 例如:鼠标点击事件中,事件对象就存了鼠标点在那个位置等信息
1.2 如何获取
  1. 在事件绑定的回调函数的第一个参数就是事件对象
  2. 一般命名为event、ev、e
// 事件对象
元素.addEventListener('click',function(e){
    
})
1.3 部分常有属性:

type:获取当前的事件类型

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

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

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

现在不提倡使用keyCode

// 图片跟随鼠标移动
  // 1. 获取元素
        let pic = document.querySelector('img')
        document.addEventListener('mousemove',function(e){
            pic.style.left = e.pageX + 'px'
            pic.style.top = e.pageY + 'px'
        })

2. 事件流

事件流指的是事件完整执行过程中的流动路径

在这里插入图片描述

说明:假设页面里有个div,当触发事件时,会经历连个阶段,分别是捕获阶段、冒泡阶段

简单来说:捕获阶段是从父到子 冒泡阶段是从子到父

2.1 冒泡事件概念:

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

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

冒泡事件是默认存在的

        let father = document.querySelector('.father')
        let son = document.querySelector('.son')
        father.addEventListener('click',function(){
            alert('我是爸爸')
        })
        son.addEventListener('click',function(){
            alert('我是儿子')
        })
        document.addEventListener('click',function(){
            alert('我是爷爷')
        })
2.2 事件捕获概念

从DOM的根元素开始去执行对应的事件(从外到里)

事件捕获需要写对应代码才能看到效果

DOM.addEventListener(事件类型,事件处理函数,是否使用事件捕获机制)

说明:

  1. addEventListener第三个参数传入true代表是捕获阶段触发(很少使用)
  2. 若传入false代表冒泡阶段触发,默认就是false
  3. 若是用LO事件监听,则只有冒泡阶段,没有捕获
 let father = document.querySelector('.father')
        let son = document.querySelector('.son')
        father.addEventListener('click',function(),true{
            alert('我是爸爸')
        })
        son.addEventListener('click',function(),true{
            alert('我是儿子')
        })
        document.addEventListener('click',function(),true{
            alert('我是爷爷')
        })

3. 阻止事件流动

  1. 因为默认就有冒泡模式的存在,所以容易导致事件影响到父级元素
  2. 若想把事件就限制在当前元素内,就需要阻止事件流动
  3. 阻止事件流动需要拿到事件对象
事件对象.stopPropagation()
 let father = document.querySelector('.father')
        let son = document.querySelector('.son')
        father.addEventListener('click',function(e){
            alert('我是爸爸')
            e.stopPropagation()
        })
        son.addEventListener('click',function(e){
            alert('我是儿子')
            e.stopPropagation()
        })
        document.addEventListener('dblclick',function(){
            alert('我是爷爷')
        })
3.1 鼠标经过事件

mouseenter和mouseleave 没有冒泡效果(推荐)

4. 阻止默认行为,比如链接点击不跳转,表单域的跳转

// 语法:
e.preventDefault()

5. 两种注册事件的区别:

5.1 传统on注册(L0)
  1. 同一个对象,后面注册的事件会覆盖前面注册(同一个事件)
  2. 直接使用null覆盖偶就可以实现事件的解绑
  3. 都是冒泡阶段执行的
5.2 事件监听注册(L2)
  1. 语法:addEventListener(事件类型,事件处理函数,是否使用捕获)
  2. 后面注册的事件不会覆盖前面注册的事件(同一个事件)
  3. 可以通过第三个参数去确定是在冒泡或者捕获阶段执行
  4. 必须使用removeEventListener(事件类型 ,事件处理函数,获取捕获或者冒泡阶段)
  5. 匿名函数无法被解绑
<button>点击</button>
    <button class="btn">点我</button>
    <script>
        let btn = document.querySelector('button')
        let btn2 = document.querySelector('.btn')
        // 1. 绑定事件
        btn.onclick = function(){
            alert('第一次')
        }
        btn.onclick = function(){
            alert('第二次')
        }
        // 解绑事件
        btn.onclick = null
        // 2. 绑定事件
        btn2.addEventListener('click',fun)
            function fun(){
            alert(11)
        }
        // 解绑事件
        btn2.removeEventListener('click',fun)       

6. 事件委托

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

优点:给父级元素加事件(可以提高性能)

原理:事件委托其实是利用事件冒泡的特点,给父元添加事件,子元素可以触发

实现:事件对象.target可以获得真正触发事件的元素

   let ul = document.querySelector('ul')
        ul.addEventListener('click',function(e){
            e.target.style.color = 'pink'
        })
6.1动态创建表格
 //  1. 准备好数据后端的数据
    let arr = [
      { stuId: 1001, uname: '欧阳霸天', age: 19, gender: '男', salary: '20000', city: '上海' },
      { stuId: 1002, uname: '令狐霸天', age: 29, gender: '男', salary: '30000', city: '北京' },
      { stuId: 1003, uname: '诸葛霸天', age: 39, gender: '男', salary: '2000', city: '北京' },
    ]
    let tbody = document.querySelector('tbody')
    // 1. 获取录入按钮
    let add = document.querySelector('.add')
      // 2. 获取表单元素
      let uname = document.querySelector('.uname')
      let age = document.querySelector('.age')
      let gender = document.querySelector('.gender')
      let salary = document.querySelector('.salary')
      let city = document.querySelector('.city')
    // 渲染函数
    function render (){  
      tbody.innerHTML = ''  
      for(let i = 0; i < arr.length; i++){
       // 1. 创建tr
      let tr = document.createElement('tr')
      // 2. tr里面放内容
      tr.innerHTML = `
      <td>${arr[i].stuId}</td>
        <td>${arr[i].uname}</td>
        <td>${arr[i].age}</td>
        <td>${arr[i].gender}</td>
        <td>${arr[i].salary}</td>
        <td>${arr[i].city}</td>
        <td>
          <a href="javascript:" id = "${i}">删除</a>
        </td>
      `
      // 3. 把tr追加给today 父元素.appendChild(子元素)
      tbody.appendChild(tr)
      // 复原表单所有数据
      uname.value = age.value = salary.value = ''
      gender.value = '男'
      city.value = '北京'
      }
    } 
      render()
      
      add.addEventListener('click',function(){
        // 获取表单里面的值然后追加给数组
        arr.push({
          // 得到数组最后一条数据加一
        stuId: arr[arr.length - 1].stuId + 1,
        uname: uname.value,
        age: age.value,
        gender: gender.value,
        salary: salary.value,
        city: city.value
        })
        // 重新渲染
        render()
      })  
      // 删除操作 使用事件委托
      tbody.addEventListener('click',function(e){
        if(e.target.tagName === 'A'){
          arr.splice(e.target.id,1)
          // 删除完之后重新渲染
          render()
        }
      })   

八、网页特效

1. 手风琴效果

// 1. 获取元素
let lis = document.querySelectorAll('li')
for(let i = 0; i < lis.length; i++){
// 2. 绑定鼠标经过事件
lis[i].addEventListener('mouseenter',function(){
  // 排他思想,先让所有的都变成100最后给自己加800
  for(let j = 0; j < lis.length; j++){
      lis[j].style.width = '100px'
  }
  this.style.width = '800px'
})
// 3. 绑定鼠标离开事件
lis[i].addEventListener('mouseleave',function(){
  for(let i = 0; i < lis.length; i++){
    lis[i].style.width = '240px'
  }
})
}

2. 滚动事件和加载事件

2.1 滚动事件

当页面进行滚动时触发的事件

为什么要学?

很多网页需要检测用户把页面滚动到某个区域后做一些处理,比如固定导航栏,比如返回发哦顶部

事件名:scroll

监听整个页面的滚动

// 页面滚动事件
window.addEventListener('scroll',function(){
    // 执行的操作
})

给window或document添加scroll事件

2.2 加载事件

加载外部资源(如图片,外联CSS和JavaScript等)加载完毕时触发的事件

为什么要学?

  1. 有些时候需要等页面资源全部处理完了做一些事情
  2. 老代码喜欢把script写在head中,这时候直接找dom元素找不到

事件名:load

window.addEventListener('load',function(){
    // 执行的操作
})

注意:

不光可以监听整个页面资源加载完毕,也可以针对某个资源绑定load事件

2.3 DOMContentLoaded
  1. 当初始的HTML文档被完全加载的和解析完成后,DOMContentLoaded事件被触发,而无需等待样式表、图像等完全加载
  2. 事件名:DOMContentLoaded
  3. 监听页面DOM加载完毕:给document添加DOMContentLoaded事件
document.addEventListener('DOMContentLoaded',function(){
    // 执行的操作  
})

3 元素大小和位置

3.1 scroll家族

使用场景:

我们想要页面滚动一段距离,比如100px,就让某些元素显示隐藏,那我们怎么知道,页面滚动了100像素呢?

就可以使用scroll来检查页面滚动距离

获取宽高:

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

获取位置:

  1. 获取元素内容往左、往上滚出去看不到的距离
  2. scrollLeft和scrollTop
  3. 这两个属性是可以修改的
3.2 检测页面滚动的距离

语法:

document.documentElement.scrollTop
3.2.1 彷新浪案例
// 1. 获取元素
        let backtop = document.querySelector('.backtop')
        // 2. 绑定页面滚动事件
        window.addEventListener('scroll',function(){
            let num = document.documentElement.scrollTop
            if(num >= 500) {
                backtop.style.display = 'block'
            } else {
                backtop.style.display = 'none'
            }
        })
        // 2.点击链接返回顶部
        backtop.children[1].addEventListener('click',function(){
            document.documentElement.scrollTop = 0
        })
3.2.2 彷京东固定头部
let sk = document.querySelector('.sk')
        let header = document.querySelector('.header')
        window.addEventListener('scroll',function(){
            if(document.documentElement.scrollTop >= sk.offsetTop) {
                header.style.top = 0
            } else {
                header.style.top = '-80px'
            }
        })
3.3 offset家族

使用场景

通过js的方式,得到元素在页面中的的位置

获取宽高:

  1. 获取元素的自身宽高、包含元素自身设置的宽高、padding、border
  2. offsetWidth和offsetHeight

获取位置:

  1. 获取元素距离自己定位父级元素的左、上距离
  2. offsetLeft和offsetTop 注意是只读属性
3.3.1 电梯导航案例
 // 1. 获取元素
        let items = document.querySelectorAll('.item')
        let neirong = 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')
            document.documentElement.scrollTop = neirong[i].offsetTop
           })
        }
3.4 client家族

获取宽高

  1. 获取元素的可见部分宽高(不包含边框,滚动条)
  2. clientWidth和clientHeight

会在窗口尺寸改变的时候触发事件:

window.addEventListener('resize',function(){
    // 执行的代码
})

检测屏幕宽度:

window.addEventListener('resize',function(){
    lew w = document.documentElement.clientWidth
    console.log(w)
})
4. 综合案例(轮播图)
  // 轮播图开始
    // 1.需求鼠标经过小图标 当前图标高亮 添加类
    // 获取元素
    let lis = document.querySelectorAll('.indicator li')
    // 获取图片元素
    let piclis = document.querySelectorAll('.slides ul li')
    // 获取图片文字元素
    let text = document.querySelector('.extra h3')
    // 获取右侧点击按钮
    let next = document.querySelector('.next')
    // 获取左侧点击按钮
    let prev = document.querySelector('.prev')
    // 获取大盒子元素
    let main = document.querySelector('.main')
    for (let i = 0; i < lis.length; i++){
      // 给小图标绑定鼠标经过事件
      lis[i].addEventListener('mouseenter',function(){
        // 选出唯一的那个类删除他
        document.querySelector('.indicator .active').classList.remove('active')
        // 给当先鼠标经过加上类
        this.classList.add('active')
        // 2. 需求大图跟随小图标变化
        document.querySelector('.slides ul .active').classList.remove('active')
        piclis[i].classList.add('active')
        text.innerHTML = `${i + 1}张图的描述信息`
        // 4. 解决一个bug,点击右侧按钮可以实现播放下一张,但鼠标经过前面的会乱序
        index = i
      })
    }
    // 3. 右侧按钮播放效果
    let index = 0
    // 给右侧按钮绑定点击事件
    next.addEventListener('click',function(){
      index++
      // if (index === lis.length){
      //   index = 0
      // }
      index = index % lis.length
       common()
    })
    // 5. 左侧按钮播放效果
    prev.addEventListener('click',function(){
      index--
      if(index < 0){
        index = lis.length - 1
      }
      common()
    })
    // 6. 应为左右侧按钮有大量相同的操作可以封装一个函数 common
      function common (){
        // 选出小图标
      document.querySelector('.indicator .active').classList.remove('active')
        // 给当先鼠标经过加上类
       lis[index].classList.add('active')
       // 选出大图片
       document.querySelector('.slides ul .active').classList.remove('active')
      piclis[index].classList.add('active')
      text.innerHTML = `${index + 1}张图的描述信息`
      }
      // 7. 开启定时器实现自动播放
      let timer = setInterval(function(){
        // 自动调用右侧点击事件
        next.click()
      },2000)
      // 8. 关闭定时器
        main.addEventListener('mouseenter',function(){
          clearInterval(timer)
      })
      main.addEventListener('mouseleave',function(){
         timer = setInterval(function(){
        // 自动调用右侧点击事件
        next.click()
      },2000)
      })

九、Window对象

1. BOM(浏览器模型)

1.1 BOM(Browser Object Model)是浏览器对象模型

在这里插入图片描述

  1. window是浏览器内置中的全局对象,我们所学习的所有Web APIs 的知识内容都是 基于window对象实现的
  2. window对象不包含了navigator、location、document、history、screen 5个属性,即所谓的BOM(浏览器对象模型)
  3. document是实现DOM的基础,他其实是依附于window的属性
  4. 依附于window对象的所有属性和方法,使用时可以省略window

2. 定时器-延迟函数

JavaScript内置的一个用来让代码延迟执行的函数,叫setTimeout

语法:

setTimeout(回调函数,等待的毫秒数)

setTimeout仅仅只执行一次,所有可以理解为就是一段代码延迟执行,平时忽略Windows

// 图片2秒自动关闭
<img src="./images/ad.png" alt="">
    <script>
     let img = document.querySelector('img')
     setTimeout(function(){
        img.style.display = 'none'
     },2000)
    </script>
// 利用递归模仿setinterval
let div = document.querySelector('div')
        function fn (){
            div.innerHTML = new Date().toLocaleString()
            setTimeout(fn,1000)
        }
        fn()

3 . js执行机制

3.1 Js是单线程

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

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

3.2 同步和异步

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

同步

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

异步

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

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

在这里插入图片描述

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

4. location对象

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

4.1 常用方法和属性:
  1. href属性获取完整的URL地址,对其赋值时用于地址的跳转
  2. search属性获取地址携带的参数,符号?后面部分
  3. hash属性获取地址中的哈希值,符号#后面部分
  4. reload方法用来刷新当前页面,传入参数true时表示强制刷新
4.2 location.href的使用
 <a href="https://www.itcast.cn/">支付成功<span>5</span>秒钟后跳转首页</a>
    <script>
        let a = document.querySelector('a')
        let num = 5

        let timer = setInterval(function(){
            num--
            a.innerHTML = `支付成功<span>${num}</span>秒钟后跳转首页`
            if(num === 0){
                clearInterval(timer)
                location.href = 'https://www.itcast.cn/'
            }
        },1000)
4.2.1 location.search

属性当用和方法:

search属性获取地址中携带的参数,符号?后面部分

console.log(location.search)
4.2.2 location.hash

常用属性和方法:

hash属性获取地址中的哈希值,符号#后部分

console.log(location.hash)

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

4.2.3 location.reload

常用属性和方法:

reload方法用来刷新当前页面,传入参数true时表示强制刷新

let btn = document.querySelector('button')
        btn.addEventListener('click',function(){
            // reload() 刷新方法 有本地缓存    强制刷新 ctrl + f5  
            location.reload(true)
        })

5. navigator对象

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

 // 检测 userAgent(浏览器信息)
        !(function () {
            const userAgent = navigator.userAgent
            // 验证是否为Android或iPhone
            const android = userAgent.match(/(Android);?[\s\/]+([\d.]+)?/)
            const iphone = userAgent.match(/(iPhone\sOS)\s([\d_]+)/)
            // 如果是Android或iPhone,则跳转至移动站点
            if (android || iphone) {
                location.href = 'http://m.itcast.cn'
            }
        })()

6. histroy对象

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

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

十、swiper插件

1. swiper插件的基本使用

1.1 插件

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

学习插件的基本过程:

  1. 熟悉官网,了解这个插件可以完成什么需求 https://www.swiper.com.cn/
  2. 看在线演示,知道找到符合自己需求的demo https://www.swiper.com.cn/demo/index.html
  3. 查看基本使用流程 https://www.swiper.com.cn/usage/index.html
  4. 查看API文档,去配置自己的插件 https://www.swiper.com.con/api/index.html
  5. 注意:多个swiper同时使用的时候,类名需要区分

2. 本地存储

2.1 本地存储特性

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

  1. 数据存储在用户浏览器中
  2. 设置、读取方便、甚至页面刷新不丢失数据
  3. 容量较大,sessionStorage和localStorage约5M左右
2.2 localStorage
  1. 声明周期永久生效,除非手动删除,否者关闭页面也会存在
  2. 可以多窗口(页面)共享(同一浏览器可以共享)
  3. 以键值对的形式存储使用

存储数据:

localStorage.setItem(key,value)

获取数据:

localStorage.getItem(key)

删除数据

localStorage.removeItem(‘uname’)

2.3 存储复杂数据类型

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

JSON.stringify(复杂数据类型)

将复杂数据类型转换成JSON字符串 (存储本地存储中)

JSON.parse(JSON字符串)

将JSON字符串转换成对象 (取出时候使用)

 let obj = {
            uname: '刘德华',
            age: 20,
            sex: '男',
            addrsss: '香港'
        }
        //(1)复杂数据类型一定要转换为JSON  JSON.stringify()
        localStorage.setItem('obj',JSON.stringify(obj))
        // (2) 取数据用JSON.parse() 将字符串转换为对象
        console.log(JSON.parse(localStorage.getItem('obj')));

3. 本地存储综合案例

 // 封装一个读取数据的函数
    function getLocalDate() {
      let date = localStorage.getItem('date')
      if(date) {
        return JSON.parse(date)
      } else {
        let arr = [
          //  1. 准备好数据后端的数据
      { stuId: 1001, uname: '欧阳霸天', age: 19, gender: '男', salary: '20000', city: '上海' },
      { stuId: 1002, uname: '令狐霸天', age: 29, gender: '男', salary: '30000', city: '北京' },
      { stuId: 1003, uname: '诸葛霸天', age: 39, gender: '男', salary: '2000', city: '北京' },
    ]
    // 写到本地存储里
    localStorage.setItem('date',JSON.stringify(arr))
      }
    }
     // 获取父元素 tbody
     let tbody = document.querySelector('tbody')
    // 添加数据按钮 
    // 获取录入按钮
    let add = document.querySelector('.add')
    // 获取各个表单的元素
    let uname = document.querySelector('.uname')
    let age = document.querySelector('.age')
    let gender = document.querySelector('.gender')
    let salary = document.querySelector('.salary')
    let city = document.querySelector('.city')
    // 渲染函数  把数组里面的数据渲染到页面中
    function render() {
      // 读取本地存储数据然后渲染
      let arr = getLocalDate()
      // 先干掉以前的数据  让tbody 里面原来的tr 都没有
      tbody.innerHTML = ''
      // 在渲染新的数据
      // 根据数据的条数来渲染增加 tr  
      for (let i = 0; i < arr.length; i++) {
        // 1.创建tr  
        let tr = document.createElement('tr')
        // 2.tr 里面放内容
        tr.innerHTML = `
        <td>${arr[i].stuId}</td>
        <td>${arr[i].uname}</td>
        <td>${arr[i].age}</td>
        <td>${arr[i].gender}</td>
        <td>${arr[i].salary}</td>
        <td>${arr[i].city}</td>
        <td>
          <a href="javascript:" id="${i}">删除</a>
        </td>
        `
        // 3.把tr追加给 tobdy  父元素.appendChild(子元素)
        tbody.appendChild(tr)
      }
    }
    // 页面加载就调用函数
    render()

    add.addEventListener('click', function () {
      // 先读取最新存储数据
      let arr = getLocalDate()
      // 获得表单里面的值   之后追加给 数组 arr  用 push方法
      arr.push({
        // 得到数组最后一条数据的学号 1003    + 1
        stuId: arr[arr.length - 1].stuId + 1,
        uname: uname.value,
        age: age.value,
        gender: gender.value,
        salary: salary.value,
        city: city.value
      })
        //  存储到本地
        localStorage.setItem('date',JSON.stringify(arr))
      // 重新渲染我们的函数
      render()
      // 复原所有的表单数据
      uname.value = age.value = salary.value = ''
      gender.value = '男'
      city.value = '北京'
    })
    // 删除操作, 删除的也是数组里面的数据 , 但是我们用事件委托
    tbody.addEventListener('click', function (e) {
      // 读取本都的数据
      let arr = getLocalDate()
      // alert(11)
      // 我们只能点击了链接 a ,才会执行删除操作
      // 那我们怎么知道你点击了a呢?
      // 俺们只能点击了链接才能做删除操作
      // console.dir(e.target.tagName)
      if (e.target.tagName === 'A') {
        // alert('你点击了链接')
        // 删除操作  删除 数组里面的数据  arr.splice(从哪里开始删,1)
        // 我要得到a的id 需要
        // console.log(e.target.id)
        arr.splice(e.target.id, 1)
        // 保存到本地
        localStorage.setItem('date',JSON.stringify(arr))
        // 重新渲染我们的函数
        render()
      }
    })   

4. 自定义属性

由程序员自带的属性 比如class id title等,可以直接使用点语法操作

  1. getAttribute(‘属性名’) // 获取自定义属性
  2. setAttribute(‘属性名’,‘属性值’) // 设置自定义属性
  3. removeAttribute(‘属性名’) // 删除自定属性
1. data-自定义属性:

传统的自定义属性没有专门的定义规则,开发者随意定值,不够规范,所有在html5中突出来了专门的date-自定义属性在标签上一律以data-开头

在DOM对象上一律以dataset对象方式获取

十一、正则表达式

1. 正则表达式的作用

1.1 什么是正则表达式
  1. 正则表达式(Regular Expression)是用于匹配字符串中字符组合的模式。在 JavaScript中,正则表达式也是对象
  2. 通常用来查找、替换那些符合正则表达式的文本,许多语言都支持正则表达式。
1.2正则表达式的使用场景:
  1. 例如验证表单:用户名表单只能输入英文字母、数字或者下划线, 昵称输入框中可以输入中文(匹配)
  2. 比如用户名: /1{3,16}$/
  3. 过滤掉页面内容中的一些敏感词(替换),或从字符串中获取我们想要的特定部分(提取)等
1.3 小节

正则表达式是什么?

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

正则表达式有什么作用?

  1. 表单验证(匹配)
  2. 过滤敏感词(替换)
  3. 字符串提取我们想要的部分(提取)

2. 语法

2.1 定义正则表达式语法
let 变量名 = /表达式/
  • 其中 / / 是正则表达式的字面量

  • 比如:

let reg = /前端/
2.2 判断是否有符合规则的字符串:

test() 方法 用来查看正则表达式与指定的字符串是否匹配

  • 比如:
// 要检测的字符串
        let str = '学好前端,成就高薪就业'
        // 1. 定义规则
        let reg = /前端/
        // 2. 检测方法
       let s = reg.test(str)
        console.log(s);
  • 如果正则表达式与指定的字符串匹配,返回true,否者false
2.3 检索(查找)符合规则的字符串:

exec() 方法 在一个指定字符串中执行一个搜索匹配

  • 比如:
// 要检测的字符串
        let str = '学好前端,成就高薪就业'
        // 1. 定义规则
        let reg = /前端/
        // 2. 检测方法
        let st = reg.exec(str)
        console.log(st);
  • 如果匹配成功,exec()方法返回一个数组,否者返回null

3. 元字符

  • 普通字符:

大多数的字符仅能够描述他们本身,这些字符称作为普通字符,例如所有的字母和数字。

也就是说普通字符只能匹配字符串中与他们相同的字符

  • 元字符(特殊字符)

是一些具有特殊含义的字符,可以极大提高了灵活性和强大的匹配功能

  1. 比如,规定用户只能输入英文26个英文字母,普通字符的话abcdefghij
  2. 但是换成元字符写法:[a-z]
  • 参考文档:
  1. MDN:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Regular_Expressions
  2. 正则测试工具: http://tool.oschina.net/regex
3.1 元字符分类:
  1. 边界符(表示位置,开头和结尾,必须用什么开头,用什么结尾)
  2. 量词(表示重复次)
  3. 字符类(比如\d 表示0~9)
  • 边界符

正则表达式中的边界符(位置符)用来提示字符所处的位置,主要有两个字符

边界符说明
^表示匹配行首的文本(以谁开始)
$表示匹配行尾的文本(以谁结束)

如果^和$在一起,表示必须是精确匹配

 console.log(//.test('哈')); //trur
        console.log(/二哈/.test('二哈')); // true
        console.log(/二哈/.test('很二哈哈')); // true
        console.log('-----------------------------------');
        // ^ 开头
        console.log(/^二哈/.test('很二哈哈')); // false
        console.log(/^二哈/.test('二哈哈哈')); // true
        console.log('-----------------------------------');
        // $结尾
        console.log(/^二哈$/.test('二哈很傻')); // false
        console.log(/^二哈$/.test('二哈二哈')); // false
        console.log(/^二哈$/.test('二哈')); // true
  • 量词

量词用来设定某个模式出现的次数

量词说明
*重复零次或更多次
+重复一次或更多次
?重复零次或一次
{n}重复n次
{n,}重复n次或更多次
{n,m}重复n到m次

注意: 逗号左右两侧千万不要出现空格

// 量词 * 类似 >= 0次
        console.log(/^哈$/.test('哈')); // true
        console.log(/^哈*$/.test('')); // true
        console.log(/^哈*$/.test('哈哈')); // true
        console.log(/^哈*$/.test('二哈很傻')); // false
        console.log(/^哈*$/.test('哈很傻')); // false
        console.log(/^哈*$/.test('哈很哈')); // false
        console.log('-----------------------------------');
         // 量词 + 类似 >= 1次
         console.log(/^哈$/.test('哈')); // true
        console.log(/^哈+$/.test('')); // false
        console.log(/^哈+$/.test('哈哈')); // true
        console.log(/^哈+$/.test('二哈很傻')); // false
        console.log(/^哈+$/.test('哈很傻')); // false
        console.log(/^哈+$/.test('哈很哈')); // false
        console.log('-----------------------------------');
        // 量词 ? 类似 0 || 1
        console.log(/^哈?$/.test('')); // true
        console.log(/^哈?$/.test('哈')); // true
        console.log(/^哈?$/.test('哈哈')); // false
        console.log(/^哈?$/.test('二哈很傻')); // false
        console.log(/^哈?$/.test('哈很傻')); // false
        console.log(/^哈?$/.test('哈很哈')); // false
 // 量词{n} 写几, 就必须出现几次
        console.log(/^哈{4}$/.test('哈')); // false
        console.log(/^哈{4}$/.test('哈哈')); // false
        console.log(/^哈{4}$/.test('哈哈哈')); // false
        console.log(/^哈{4}$/.test('哈哈哈哈')); // true
        console.log(/^哈{4}$/.test('哈哈哈哈哈')); // false
        console.log('-----------------------------------');
        // 量词{n,} >= n
        console.log(/^哈{4,}$/.test('哈')); // false
        console.log(/^哈{4,}$/.test('哈哈')); // false
        console.log(/^哈{4,}$/.test('哈哈哈')); // false
        console.log(/^哈{4,}$/.test('哈哈哈哈')); // true
        console.log(/^哈{4,}$/.test('哈哈哈哈哈')); // true
        console.log('-----------------------------------');
        // 量词{n,m} 逗号左右两侧千万不能有空格 >=n && <= margin
        console.log(/^哈{4,6}$/.test('哈')); // false
        console.log(/^哈{4,6}$/.test('哈哈')); // false
        console.log(/^哈{4,6}$/.test('哈哈哈')); // false
        console.log(/^哈{4,6}$/.test('哈哈哈哈')); // true
        console.log(/^哈{4,6}$/.test('哈哈哈哈哈')); // true
        console.log(/^哈{4,6}$/.test('哈哈哈哈哈哈')); // true
        console.log(/^哈{4,6}$/.test('哈哈哈哈哈哈哈')); // false
  • 字符类

(1)[ ]里面加上 - 连字符

  • 使用连字符 - 表示一个范围
console.log(/^[a-z]$/.test('c')) // true
  • 比如
  1. [a-z] 表示a到z 26个英文字母都可以
  2. [a-zA-Z] 表示大小写都可以
  3. [0-9] 表示0~9的数字都可以
  • 案例
腾讯QQ号:^[1-9][0-9]{4,}$(腾讯QQ号从10000开始)

(2)[ ]里面加上^取反符号

  • 比如
  1. [^a-z] 匹配除了小写字母以外的字符
  2. 注意要写到中括号里面

(3). 匹配除了换行符之外的任意单个字符

  • 预定义:指的是某些常见模式的简写方式
预定义类说明
\d匹配0~9之间的任一数字,相当于[0-9]
\D匹配所有0-9以外的字符,相当于[^0-9]
\w匹配任意的字母、数字和下划线,相当于[A-Za-z0-9]
\w除所有字母、数字和下划线以外的字符,相当于[^A-Za-z0-9]
\s匹配空格(包括换行符、制表符、空格符等),相等于[\t\r\n\v\f]
\S匹配非空格的字符,相当于[^\t\r\n\v\f]
日期格式:^\d{4}-\d{1,2}-\d{1,2}

4. 修饰符

修饰符约束正则执行的某些细节行为,如是否区分大小写、是否支持多行匹配等

  • 语法:
/表达式/修饰符
  1. i是单词ignore的缩写,正则匹配时字母不区分大小写
  2. g是单词global的缩写,匹配所有满足真正表达式的结果
  • 替换 replace替换
字符串.replace(/正则表达式/,'替换的文本')
 console.log(/^java$/.test('java')); // true
        console.log(/^java$/i.test('JAVA')); // true
        console.log(/^java$/i.test('java')); // true
        let str = 'java是一门编程语言,学完JAVA工资很高'
        let re = str.replace(/java/ig,'前端')
        console.log(re);

5. change事件

内容发生了变化

<input type="text">
    <script>
        let input = document.querySelector('input')
        input.addEventListener('change',function(){
            alert('111')
        })
    </script>

6. 综合案例

<script>
    // 1.发送短息验证
    let code = document.querySelector('.code')
    let falg = true // 节流阀
    // 1.1 绑定点击事件
    code.addEventListener('click',function(){
      if (falg) {
      let i = 5
      falg = false
      // 点击完毕后立即触发
      code.innerHTML = `0${i}之后重新获取`
     let timer = setInterval(function(){
        i--
        code.innerHTML = `0${i}之后重新获取`
        if(i === 0){
          clearInterval(timer)
          code.innerHTML = `重新获取`
          falg = true
        }
      },1000)
      }
    })
     // 2.验证用户名
     // 2.1 获取用户名表单
     let username = document.querySelector('[name=username]')
     // 2.2 绑定change事件
     username.addEventListener('change',verifyName)
     // 2.3 封装verifyName函数
     function verifyName (){
      let span = username.nextElementSibling
        // 2.4 定义规则
        let reg = /^[a-zA-Z0-9-_]{6,10}$/
        if(!reg.test(username.value)) {
          span.innerHTML = '输入不合法,请输入6~10位'
          return false
        }
        // 2.5 合法的
        span.innerHTML = ''
        return true
     }
     // 3. 验证手机号
     // 3.1 获取手机号表单
     let phone = document.querySelector('[name=phone]')
     // 3.2 绑定change事件
     phone.addEventListener('change',verifyPhone)
     // 3.3 封装verifyPhone函数
     function verifyPhone () {
      let span = phone.nextElementSibling
      // 3.4 定义规则
      let reg = /^1(3\d|4[5-9]|5[0-35-9]|6[567]|7[0-8]|8\d|9[0-35-9])\d{8}$/
      if(!reg.test(phone.value)) {
        span.innerHTML = '请输入11位电话号码'
        return false
      }
      // 合法的电话号码
      span.innerHTML = ''
      return true
     }
     // 4. 验证码表单
     // 4.1 获取验证码表单
     let codeInput = document.querySelector('[name=code]')
     // 4.2 绑定change事件
     codeInput.addEventListener('change',verifyCode)
     // 4.3 封装verifyCode函数
     function verifyCode () {
      let span = codeInput.nextElementSibling
      // 4.4 定义规则
      let reg = /^\d{6}$/
      if(!reg.test(codeInput.value)) {
        span.innerHTML = '请输入6位数字'
        return false
      }
      // 4.5合法的验证码
      span.innerHTML = ''
      return true
     }
     // 5.密码表单
     // 5.1 获取密码表单
     let password = document.querySelector('[name=password]')
     // 5.2 绑定change事件
     password.addEventListener('change',verifyPassword)
     // 5.3 封装verifyPassword函数
     function verifyPassword () {
      let span = password.nextElementSibling
      // 5.4 定义规则
      let reg = /^[a-zA-Z0-9-_]{6,20}$/
      if(!reg.test(password.value)) {
        span.innerHTML = '请输入6~20位由字母数字下划线的密码'
        return false
      }
      // 5.5 合法的密码
      span.innerHTML = ''
      return true
     }
     // 6. 密码再次验证
     // 6.1 获取确认密码表单
     let confirm = document.querySelector('[name=confirm]')
     // 6.2 绑定change事件
     confirm.addEventListener('change',verifyPwd)
     // 6.3 封装verifyPwd函数
     function verifyPwd () {
      let span = confirm.nextElementSibling
      // 判断和密码框的值是否相等
      if(password.value !== confirm.value) {
        span.innerHTML = '您两次输入的密码不正确'
        return false
      }
      // 6.4 合法的
        span.innerHTML = ''
        return true
     }
     // 7. 我同意
      let queren = document.querySelector('.icon-queren')
      // 绑定点击事件
      queren.addEventListener('click',function(){
        queren.classList.toggle('icon-queren2')
      })
      // 8. 提交模块
      let form = document.querySelector('form')
      // 8.1 绑定提交事件
      form.addEventListener('submit',function(e) {
        // 8.2 判断是否勾选我同意模块
        if(!queren.classList.contains('icon-queren2')) {
          alert('请勾选同意协议')
          // 阻止提交
          e.preventDefault()
        }
        // 8.3 依次判断上方的表单是否通过,如果有一个没有通过就阻止
        if(!verifyName()) e.preventDefault()
        if(!verifyPhone()) e.preventDefault()
        if(!verifyCode()) e.preventDefault()
        if(!verifyPassword()) e.preventDefault()
        if(!verifyPwd()) e.preventDefault()
      })
  </script>
~~~js

!reg.test(phone.value)) {
        span.innerHTML = '请输入11位电话号码'
        return false
      }
      // 合法的电话号码
      span.innerHTML = ''
      return true
     }
     // 4. 验证码表单
     // 4.1 获取验证码表单
     let codeInput = document.querySelector('[name=code]')
     // 4.2 绑定change事件
     codeInput.addEventListener('change',verifyCode)
     // 4.3 封装verifyCode函数
     function verifyCode () {
      let span = codeInput.nextElementSibling
      // 4.4 定义规则
      let reg = /^\d{6}$/
      if(!reg.test(codeInput.value)) {
        span.innerHTML = '请输入6位数字'
        return false
      }
      // 4.5合法的验证码
      span.innerHTML = ''
      return true
     }
     // 5.密码表单
     // 5.1 获取密码表单
     let password = document.querySelector('[name=password]')
     // 5.2 绑定change事件
     password.addEventListener('change',verifyPassword)
     // 5.3 封装verifyPassword函数
     function verifyPassword () {
      let span = password.nextElementSibling
      // 5.4 定义规则
      let reg = /^[a-zA-Z0-9-_]{6,20}$/
      if(!reg.test(password.value)) {
        span.innerHTML = '请输入6~20位由字母数字下划线的密码'
        return false
      }
      // 5.5 合法的密码
      span.innerHTML = ''
      return true
     }
     // 6. 密码再次验证
     // 6.1 获取确认密码表单
     let confirm = document.querySelector('[name=confirm]')
     // 6.2 绑定change事件
     confirm.addEventListener('change',verifyPwd)
     // 6.3 封装verifyPwd函数
     function verifyPwd () {
      let span = confirm.nextElementSibling
      // 判断和密码框的值是否相等
      if(password.value !== confirm.value) {
        span.innerHTML = '您两次输入的密码不正确'
        return false
      }
      // 6.4 合法的
        span.innerHTML = ''
        return true
     }
     // 7. 我同意
      let queren = document.querySelector('.icon-queren')
      // 绑定点击事件
      queren.addEventListener('click',function(){
        queren.classList.toggle('icon-queren2')
      })
      // 8. 提交模块
      let form = document.querySelector('form')
      // 8.1 绑定提交事件
      form.addEventListener('submit',function(e) {
        // 8.2 判断是否勾选我同意模块
        if(!queren.classList.contains('icon-queren2')) {
          alert('请勾选同意协议')
          // 阻止提交
          e.preventDefault()
        }
        // 8.3 依次判断上方的表单是否通过,如果有一个没有通过就阻止
        if(!verifyName()) e.preventDefault()
        if(!verifyPhone()) e.preventDefault()
        if(!verifyCode()) e.preventDefault()
        if(!verifyPassword()) e.preventDefault()
        if(!verifyPwd()) e.preventDefault()
      })
  </script>



  1. a-z0-9_- ↩︎

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值