JavaScriptAPI-BOM

282 阅读8分钟

BOM

BOM:浏览器对象模型

window是浏览器内置中的全局对象,我们学习的所有Web APIs的知识内容,都是基于window对象实现的

window对象下包含了navigator、location、document、history、screen等5个属性,也就是所谓的BOM(浏览器对象模型)

document是实现DOM的基础,他其实是依附于window的属性

图片.png

延迟函数+案例

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

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

他与setInterval()不同的是:setTimeout只会执行一次,可以理解为就是把一段代码、延迟执行,平时省略window

let timer = setTimeour(回调函数,等待的毫秒数)
clearTimeout(timer)

递归函数

递归函数:自己调用自己

let num = 0
function fn(){
    num++
    console.log(111)
    
    if(num>=10){
        return
    }
    
    //在函数里面,调用自己
    fn()
}
fn()

使用递归函数:一定要写退出条件!!!

递归与setTimeou

setTimeout结合递归函数,模拟setInterval重复执行

let div = document.querySelector('div')

function fn(){
    div.innerHTML = new Date().toLocaleString()
    
    setTimeout(fn,1000)
}
fn()

图片.png

JavaScript执行机制(重要)

1.2经典面试题

console.log(1111)
setTimeout(function(){
    console.log(2222)
},1000)
console.log(3333)

输出结果:1111、3333、2222;js不会等定时器结束了才执行下面的代码。

1.3

console.log(1111)
setTimeout(function(){
    console.log(2222)
},0)
console.log(3333)

输出结果:1111、3333、2222

JavaScript是单线程的,同一个时间、只能做一件事

JavaScript是为了处理页面中用户的交互,以及操作DOM的。比如我们对某个DOM进行添加和删除、不能同时进行。应该先添加、后删除!

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

同步和异步

为了解决单线程存在的缺陷、利用多核CPU的计算能力,HTML5提出了一个标准,允许JavaScript创建多个线程、于是JS中出现了同步和异步。

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

异步:在做这件事的同时,还可以去处理其他的事情。

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

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

图片.png

同步和异步被分别放到执行栈(同步)执行队列(异步)

JS执行机制:
先执行执行栈中的同步任务
异步任务放入任务队列中
一旦执行栈中的所有同步任务执行完毕后、系统就会按照次序读取任务队列中的异步任务,于是被读取的异步任务结束等待状态,进入执行栈、开始执行。

图片.png

事件click、setTimeout、load加载、都是异步任务

console.log(1)

document.addEventListener('click',function(){
    console.log(4)
})

console.log(2)

setTimeout(function(){
    console.log(3)
},3000)

输出:1234或1243

图片.png

location对象

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

常用的属性和方法:
href属性:获取完整的URL地址,对其赋值时用于地址的跳转

可以得到当前文件的URL地址
console.log(location.href)

可以通过js方式跳转到目标地址
location.href = 'http://www.baidu.com'
<a href = "http://www.njtech.edu.cn/">支付成功,5秒之后跳转首页</a>

let a = document.querySelector('a')
let num = 5
let timer = setInterval(()=>{
    num--
    a.innerHTML = `支付成功,${num}秒之后跳转首页`
    if(num==0){
        clearInterval(timer)
        location.href = "http://www.njtech.edu.cn"
    }
},1000)

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

点击提交后,将input中的数据传给target.html

<form action = "target.html">
    <input type = "text" name = "username">
    <button>提交</button>
</form>

target.html

可以拿到index.html传来的数据信息
console.log(location.search)//?username = abc

图片.png

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

#号最大的优势就是:页面不刷新、意味着不会重新加载资源

<a href = "#one"></a>
<a href = "#two"></a>

console.log(location.hash)//点击a标签后,返回#one或者#two

reload属性:用来刷新当前页面,传入参数true时、表示强制刷新

let btn = document.querySelector('button')

btn.addEventListener('click',function(){
    location.reload(true)
})

普通刷新的时候,如果我前一次打开过这个网站,浏览器会帮我把网站中的一些图片资源什么的,存储到本地缓存中,再次普通刷新后,能够比第一次打开网页更快

ctrl+f5:强制刷新:不保存到本地存储,页面是最新的

navigator对象

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

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

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

history对象

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

back():后退功能

forward():前进功能

go(参数):前进后退功能,参数如果是1:前进1个页面、如果是-1:后退一个页面

history对象在实际开发中很少使用

swiper插件

swiper.com.cn

图片.png

图片.png

使用步骤:www.swiper.com.cn/usage/index…

本地存储

数据存储在用户浏览器中
设置、读取方便、甚至页面刷新不丢失数据
容量较大,sessionStorage和localStorage约5M

localStorage(重点)

生命周期永久生效,除非手动删除,否则关闭页面也会存在
可以多窗口(页面)共享(同一浏览器可以共享)
以键值对的形式存储使用

存储数据:localStorage.setItem(key,value)

读取数据:localStorage.getItem(key)

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

必须要加引号

//存储数据
localStorage.setItem('uname','pink老师')

//获取数据
console.log(localStorage.getItem('uname'))//pink老师

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

存储引用数据类型:

let obj = {
    uname:'刘德华',
    age:17,
    address:南工大
}

//前面的key必须加引号,是key的名字,后面存的是变量,不需要写引号
localStorage.setItem('obj',obj)

但是上方的存储,会在浏览器中显示的是一个Object,并不能将数据展示出来。我们需要通过数据转换来实现:

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

JSON.stringify(复杂数据类型):将复杂数据类型转换为JSON字符串、存储到本地

JSON.parse(JSON字符串):将JSON字符串转换为对象、取出的时候使用

如果不用parse转换成对象,那么取出来的就是一个字符串,而不是对象!!!

JSON的样子(属性和值都是双引号进行包含):

let obj = {
    "uname":"刘德华",
    "age":17,
    "address":"南工大"
}

最终书写

let obj = {
    uname:'刘德华',
    age:17,
    address:'南工大'
}
//存数据
localStorage.setItem('obj',JSON.stringify(obj))//对象--》JSON

//取数据
JSON.parse(localStorage.getItem('obj'))

图片.png

sessionStorage

生命周期为:关闭浏览器窗口
在同一个窗口下、数据可以共享
以键值对的形式存储使用
用法跟localStorage基本相同

综合案例

里面的数据是缓存

图片.png

图片.png

<body>

  <h1>新增学员</h1>

  <div class="info">

    姓名:<input type="text" class="uname">

    年龄:<input type="text" class="age">

    性别: <select name="gender" id="" class="gender">

      <option value="男"></option>

      <option value="女"></option>

    </select>

    薪资:<input type="text" class="salary">

    就业城市:<select name="city" id="" class="city">

      <option value="北京">北京</option>

      <option value="上海">上海</option>

      <option value="广州">广州</option>

      <option value="深圳">深圳</option>

      <option value="曹县">曹县</option>

\


    </select>

    <button class="add">录入</button>

  </div>

\


  <h1>就业榜</h1>

  <table>

    <thead>

      <tr>

        <th>学号</th>

        <th>姓名</th>

        <th>年龄</th>

        <th>性别</th>

        <th>薪资</th>

        <th>就业城市</th>

        <th>操作</th>

      </tr>

    </thead>

    <tbody>

      <!-- <tr>

        <td>1001</td>

        <td>欧阳霸天</td>

        <td>19</td>

        <td>男</td>

\


        <td>15000</td>

        <td>上海</td>

        <td>

          <a href="javascript:">删除</a>

        </td>

      </tr> -->

    </tbody>

  </table>

  <script>

    // 读取本地存储的数据  封装为函数

    // 需求①:读取本地存储数据(封装函数)

    //   如果本地存储有数据,则返回 JSON.parse() 之后的对象

    //   如果本地存储没有数据,则默认写入三条数据,注意存储的利用JSON.stringify() 存 储JSON 格式的数据

    function getLocalData() {

      let data = localStorage.getItem('data')

      if (data) {

        //   如果本地存储有数据,则返回 JSON.parse() 之后的对象

        return JSON.parse(data)  //   {xxxxx}

      } else {

        // 如果本地存储没有数据,则默认写入三条数据,注意存储的利用JSON.stringify() 存 储JSON 格式的数据

        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: '北京' },

        ]

        // 写入到本地存储里面

        localStorage.setItem('data', JSON.stringify(arr))

      }

    }

    // 先调用一次

    getLocalData()

    // 获取父元素 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 = getLocalData()

\


      // 先干掉以前的数据  让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:"  data-id="${i}">删除</a>

            </td>

            `

        // 3.把tr追加给 tobdy  父元素.appendChild(子元素)

        tbody.appendChild(tr)

\
\


      }

    }

    // 页面加载就调用函数

    render()

\


    add.addEventListener('click', function () {

      // 需求③:添加模块

      // 注意,先取的最新的本地存储数据,然后追加

      let arr = getLocalData()

      // 新增了数据,要把新数据存储到本地存储别,忘记转换

\
\


      // alert(11)

      // 获得表单里面的值   之后追加给 数组 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

      })

      // console.log(arr)

\


      // 存储到仓库里面

      localStorage.setItem('data', JSON.stringify(arr))

\


      // 重新渲染我们的函数

      render()

      // 复原所有的表单数据

      uname.value = age.value = salary.value = ''

      gender.value = '男'

      city.value = '北京'

    })

\
\


    // 删除操作, 删除的也是数组里面的数据 , 但是我们用事件委托

    tbody.addEventListener('click', function (e) {

      // 读取本地存储里面的数据

      let arr = getLocalData()

      // 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)

        // console.log(e.target.dataset.id)
// 第一条数据不允许删除

        if (e.target.dataset.id === '0') {

          alert('当前数据不允许被删除')

          return

        }
        arr.splice(e.target.dataset.id, 1)

\


        // 存到本地里面

        localStorage.setItem('data', JSON.stringify(arr))

\


        // 重新渲染我们的函数

        render()

      }

    })

  </script>

</body>

自定义属性

设置自定义属性:.setAttribute('key','value')

得到自定义属性:.getAttribute('key')

移除自定义属性:.removeAttribute('key')

<div class = "box"></box>

let box = document.querySelector('.box')
box.setAttribute('myid','10')

console.log(box.getAttribute('myid'))

传统的自定义属性,没有专门的定义规则、开发者随意定值,不够规范。

所以在HTML5中推出专门的data-自定义属性,在标签上一律以data-开头

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

<div class = "box" data-id="10"></div>

let box = document.querySeelctor('.box')
console.log(box.dataset.id)//10

dataset对象:存储自定义集合的一个对象

正则表达式

正则表达式:用于匹配字符串中、字符组合的模式。在JavaScript中,正则表达式也是对象。

通常用来查找、替换那些符合正则表达式的文本,许多语言都支持正则表达式。

图片.png

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

语法

步骤分为两步:1.定义规则;2.根据规则去查找

定义语法:

let 变量名 = /表达式/

//:是正则表达式的字面量,正则表达式是一个对象。reg里面存储的是对象

例题:查找下面文本中是否包含字符串'前端'

1.定义规则

let reg = /前端/

2.根据规则去查找

reg是否在后面:reg.test('我们都在学前端')

返回的结果是true

检索

检索(查找)符合规则的字符串:exec()方法:在一个指定字符串中,执行一个搜索匹配。

语法:reg.exec(被检测的字符串)

let str = 'IT培训,前端开发,web前端'
let reg = /前端/

let re = reg.exec(str)
console.log(re)//返回的是一个数组

如果匹配成功,exec()方法返回的是一个数组,否则返回null。能够告诉我们在索引号n处,发现匹配

图片.png

图片.png

元字符

普通字符:大多数的字符只能够描述他们本身,例如所有的字母和数字。也就是说普通字符只能够匹配字符串中与他们相同的字符

元字符:具有特殊含义的字符,比如:规定用于只能输入英文26个英文字母,普通字符:abcdefg...、而元字符:[a-z]

正则测试工具:tool.oschina.net/regex

我们对众多的元字符进行了分类:

1.边界符(表示位置,开头和结尾,必须用什么开头,用什么结尾)

^:表示匹配行首的文本(以谁开始)
$:表示匹配行尾的文本(以谁结束)\

console.log(/^哈/.test('二哈'))//规定了以哈开头,但这里没满足,返回false

console.log(/^哈$/.test('二哈'))//必须同时哈开头,哈结尾、返回false

2.量词(表示重复次数)

*:重复0次或多次 +:重复1次或多次 ?:重复0次或1次 {n}:重复n次 {n}:重复n次或多次 {n,m}:重复n次到m次

console.log(/a*/.test('a'))//a至少出现0次或多次,有一个a返回true

//以a开头,并且a至少出现0-1次,同时以a结尾
console.log(/^a?$/.test(''))//true
//因为只能重复3次
console.log(/^a{3}$/.test('aaaa'))//fasle

//允许出现3到无限次
console.log(/^a{3,}$/.test('aaaa'))//true

3.字符类(比如\d 表示0-9)

图片.png

//这个表示只能出现abc,而不是abc中任意一个字母
console.log(/abc/.test('abc'))

//字符类[]、包含abc中任意一个就行
console.log(/[abc]/.test('abc'))

字符类[-]连字符:表示一个范围:/^[a-z]$/.test('c')//true

比如:只能出现一个
[a-z]:表示a到z的26个英文字母都可以
[a-zA-Z]:表示大小写都可以
[0-9]:表示0-9都可以

/^[a-zA-Z]$/.test('d')    //true
/^[a-zA-Z]$/.test('D')    //true
/^[a-zA-Z]$/.test('DD')   //false只能出现一次D才对
//

腾讯QQ号:^[1-9][0-9]{4,}$:以1-9开头,第二个是0-9的数字,并且([0-9])重复4到无限次,并最终以0-9结尾

补充

[]里面加上^取反符号

[^a-z]:匹配除了小写字母外的所有字符、注意一定要写在中括号的里面!!!

.匹配除换行符之外的任何的单个字符

图片.png

\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}:2021-09-14或者2021-9-8;以4个数字开头,出现1-2次的数字,

用户名-案例

图片.png

let reg = /[a-zA-Z0-9-_]{6,16}/

[\u4e00-\u9fa5]:\u是规定,这种一看就是中文的正则要求

<input type="text">

    <span></span>

    <script>

        let input = document.querySelector('input')

        let span = input.nextElementSibling

        input.addEventListener('blur', function () {

            if (/^[a-zA-Z0-9-_]{6,16}$/.test(input.value)) {

                span.className = 'right'

                span.innerHTML = '要输正确'

            } else {

                span.className = 'error'

                span.innerHTML = '只能要输6~16位字符'

            }

        })

    </script>

过滤敏感词

c.runoob.com/front-end/8…

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

语法:/表达式/修饰符

i:是单词ignore的缩写,正则匹配时、字母不区分大小写。

g:是单词global的缩写,匹配所有满足正则表达式的结果。

/a/i.test('a'):true

替换replace

字符串.replace(/正则表达式/,'替换的文本'):把正则里面的值,替换成后面的值。

图片.png

<textarea name="" id="" cols="30" rows="10"></textarea>

    <button>发布</button>

    <div></div>

    <script>

        let btn = document.querySelector('button')

        let textarea = document.querySelector('textarea')

        let div = document.querySelector('div')

        btn.addEventListener('click', function () {

            // 过滤用户输入的内容

            div.innerHTML = textarea.value.replace(/激情|基情/g, '**')

        })

replace只能匹配一个激情,但是通过后面的g来实现全局匹配。

小兔鲜综合案例

立即执行函数:(function(){}())

图片.png

1.发送验证码,用户点击后,显示05秒后重新获取,时间到了,自动改为重新获取

let code = document.querySelector('.code')

code.addEventListener('click',function(){
    //倒计时操作
    let num = 5
    let timer = setInterval(function(){
        num--;
        //这里的this指向的是window,是定时器的调用者
        code.innerHTML = `0${num}秒后重新获取`
        if(num === 0){
            code.innerHTML = `重新获取`
            //清除定时器
            clearInterval(timer)
        }
    },1000)
})

2.用户名验证(注意封装函数)

change事件,我的表单里面的值发生变化的时候就触发

他和input事件不同的是:input事件只要输入就会触发,而change事件:离开表单、并且值发生变化才触发

input.addEventListener('change',function(){
    console.log('change事件,我的表单里面的值发生变化的时候就触发。')
})

操作:

input[属性type=text]{background-color:red}:属性选择器、input标签中,只要有type属性的,全部变成红色

图片.png

因为每个input没有设置类,只写了name值,所以只能通过这种方式去获取。

//属性和值是否相等,是CSS的属性选择器
let username = document.querySelector('[name=username]')

username.addEventListener('change',verify)

//封装verify函数、鼠标离开和点击下一步都需要验证,封装一个函数专门做验证工作
let span = username.nextElementSibling
let reg = '/^[a-zA-Z0-9-_]{6,10}$/'
if(!reg.test(username.value)){
    //这个表示不合格
    span.innerHTML = '请输入6-10个字符'
    return false
}else{
    //这里说明正确,把span里面的值清空
    span.innerHTML = ''
    return true
}

这里需要返回true、false,为了我们后期进行点击下一步的时候,方便操作。

3.手机号验证

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}$/'

let phone = document.querySelector('[name=phone]')

phone.addEventListener('change',verifyPhone)
function verifyPhone(){
    let span = phone.nextElementSibling
    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
    }else{
        span.innerHTML = ''
        return true
    }
    
}

4.验证码验证

let codeInput = document.querySelector('input[name=code]')

let reg = '/^\d{6}$/'

...相同的逻辑

5.密码验证

let reg = '/^[a-zA-Z0-9-_]{6,20}$/'

// 密码模块

    let pass = document.querySelector('[name=password]')

    pass.addEventListener('change', verifyPass)

    function verifyPass() {

      // 正则表达式

      let reg = /^[a-zA-Z0-9-_]{6,20}$/

      let msg = pass.nextElementSibling

      if (!reg.test(pass.value)) {

        msg.innerText = '设置6至20位字母、数字和符号组合';

        return false;

      }

      msg.innerText = '';

      return true;

    }

    // 再次密码模块

    let confirm = document.querySelector('[name=confirm]')

    confirm.addEventListener('change', verifyconfirm)

    function verifyconfirm() {

      // 正则表达式

      let msg = confirm.nextElementSibling

      if (confirm.value !== pass.value) {

        msg.innerText = '两次密码不一致';

        return false;

      }

      msg.innerText = ''

      return true

    }

6.我同意模块

let icon = document.querySelector('.icon-queren')

icon.addEventListener('click',function(){
//toggle:如果有,就删除;如果没有,就添加
    this.classList.toggle('icon-queren2')
})

7.提交按钮模块

如果上面的每个模块,有一个返回的是false,则阻止提交,如果没有勾选同意协议,则提示:需要勾选

let submit = document.querySelector('.submit')

submit.addEventListener('submit',function(e){
    //怎么阻止提交(阻止默认行为)
    //如果返回的是false,我们取反后进行不通过的操作
    if(!verifyUsername()){
        //不通过,阻止submit按钮的提交
        e.preventDefault()
    }
    然后将其他的模块进行复制粘贴
    ....
    //是否包含某个类
    if(icon.classList.contains('icon-queren2')){
        alert('请勾选同意协议')
    }
})

登录页面

image.png

登录按钮点击的时候,需要先判断:
如果没有勾选同意,则提示要勾选
如果勾选协议,则记住用户名和密码
登录成功则跳转到首页
注意:登录按钮需要先阻止默认行为

let dl = document.querySelector('.dl')

//复选框
let remember = document.querySelector('.remember')

let username = document.querySelector('[name=username]')
document.querySelector('[name=password]')

dl.addEventListener('click',function(){
//如果没点,取反、返回true,执行该语句
    if(!remember.checked){
        alert('请勾选该协议')
        return
    }else{
        //勾选了,就记住用户名(写到本地存储)
        let obj = {
            uname:username.value
            password:password.value
        }
        localStorage.setItem('data',JSON.stringify(obj))
        //跳转到新的页面
        lcoation.href = './index.html'
    }
})
    let obj = JSON.parse(localStorage.getItem('data'))
    if(obj){
        username.value = obj.uname
        password.value = obj.password
        
        //如果有数据,则默认勾选
        remember.checked = true
    }


打开页面时候,如果本地存储有数据
则自动记录显示用户名和密码,并勾选复选框
   

首页显示

如果有本地存储,则显示:你好 xxx,否则显示请跳转到注册页面

let li = document.querySelector('xtx_navs li:first-child')

let obj = localStorage.getItem('pink')

if(obj){
    li.innerHTML = `你好,${obj.uname}`
}
所有代码

注册

(function () {
      // 需求①: 发送验证码
      // 用户点击之后,显示  05秒后重新获取
      // 时间到了,自动改为 重新获取
      let code = document.querySelector('.code')
      code.addEventListener('click', function () {
        // 倒计时读秒操作
        this.innerHTML = '05秒后重新获取'
        let num = 5
        let timer = setInterval(function () {
          num--
          code.innerHTML = `0${num}秒后重新获取`
          if (num === 0) {
            code.innerHTML = `重新获取`
            // 清除定时器
            clearInterval(timer)
          }
        }, 1000)
      })

      // 需求②: 用户名验证(注意封装函数  verifyxxx)
      // 正则 /^ [a - zA - Z0 - 9 - _]{ 6, 10 } $ /
      // 如果不符合要求,则出现提示信息  并 return false 
      // 否则 则返回return true  
      // 之所以返回 布尔值,是为了 最后的提交按钮做准备
      // [name=username]  css 属性选择器
      let username = document.querySelector('[name=username]')
      // console.log(username)
      // 鼠标离开需要验证, 点击下一步也需要验证,那我们为何不封装一个函数呢? 
      username.addEventListener('change', verifyUsername)
      // 验证用户名的函数
      function verifyUsername() {
        // console.log(11)
        let span = username.nextElementSibling
        // 开始验证  正则  1. 定义规则  2. 检测  
        let reg = /^[a-zA-Z0-9-_]{6,10}$/
        if (!reg.test(username.value)) {
          // console.log('wrong')
          span.innerHTML = '请输入6~10的字符'
          return false
        }
        // console.log('right')
        span.innerHTML = ''
        return true
      }


      // 需求③: 手机号验证
      // 正则: /^1(3\d|4[5-9]|5[0-35-9]|6[567]|7[0-8]|8\d|9[0-35-9])\d{8}$/
      // 其余同上
      let phone = document.querySelector('[name=phone]')
      phone.addEventListener('change', verifyPhone)
      // 验证手机号的函数
      function verifyPhone() {
        // console.log(11)
        let span = phone.nextElementSibling
        // 开始验证  正则  1. 定义规则  2. 检测  
        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)) {
          // console.log('wrong')
          span.innerHTML = '请输入11位的手机号码'
          return false
        }
        // console.log('right')
        span.innerHTML = ''
        return true
      }

      // 需求④: 验证码验证
      // 正则 /^\d{6}$/
      //   其余同上
      let codeInput = document.querySelector('input[name=code]')
      codeInput.addEventListener('change', verifyCode)
      // 验证手机号的函数
      function verifyCode() {
        // console.log(11)
        let span = codeInput.nextElementSibling
        // 开始验证  正则  1. 定义规则  2. 检测  
        let reg = /^\d{6}$/
        if (!reg.test(codeInput.value)) {
          // console.log('wrong')
          span.innerHTML = '请输入6位数字'
          return false
        }
        // console.log('right')
        span.innerHTML = ''
        return true
      }


      // 需求⑤: 密码验证
      // 正则 /^[a-zA-Z0-9-_]{6,20}$/
      //   其余同上
      let pass = document.querySelector('input[name=password]')
      pass.addEventListener('change', verifyPass)
      // 验证手机号的函数
      function verifyPass() {
        // console.log(11)
        let span = pass.nextElementSibling
        // 开始验证  正则  1. 定义规则  2. 检测  
        let reg = /^[a-zA-Z0-9-_]{6,20}$/
        if (!reg.test(pass.value)) {
          // console.log('wrong')
          span.innerHTML = '请输入6~20位密码'
          return false
        }
        // console.log('right')
        span.innerHTML = ''
        return true
      }

      // 需求⑥: 再次密码验证
      // 如果本次密码不等于上面输入的密码则返回错误信息
      // 其余同上
      let confirm = document.querySelector('[name=confirm]')
      confirm.addEventListener('change', verifyConfirm)
      function verifyConfirm() {
        let span = confirm.nextElementSibling
        if (confirm.value !== pass.value) {
          span.innerHTML = '两次密码不一致'
          return false
        }
        // console.log('right')
        span.innerHTML = ''
        return true
      }


      // 需求⑦: 我同意模块
      // 切换类   .icon-queren2  则是默认选中样式
      let icon = document.querySelector('.icon-queren')
      icon.addEventListener('click', function () {
        this.classList.toggle('icon-queren2')
      })

      // 需求⑧: 提交按钮模块
      // 使用 submit 提交事件
      // 如果上面的每个模块,返回的是 false 则 阻止提交
      // 如果没有勾选同意协议,则提示  需要勾选
      // 在提交之前先验证
      let form = document.querySelector('form')
      form.addEventListener('submit', function (e) {
        // alert(11)
        // e.preventDefault()
        // e.preventDefault()
        //  怎么阻止提交  (怎么阻止默认行为   )
        // 我们如果没有验证成功,不允许提交 阻止提交的行为
        // 这样说明验证不通过
        // verifyUsername() === false
        if (!verifyUsername()) {
          // 阻止提交
          // console.log(111);
          e.preventDefault()
        }
        if (!verifyPhone()) {
          // 阻止提交
          e.preventDefault()
        }
        if (!verifyCode()) {
          // 阻止提交
          e.preventDefault()
        }
        if (!verifyPass()) {
          // 阻止提交
          e.preventDefault()
        }
        if (!verifyConfirm()) {
          // 阻止提交
          e.preventDefault()
        }
        // 勾选模块 必须勾选才能通过
        // classList.add() 添加
        // classList.remove() 移除
        // classList.toggle() 切换
        // classList.contains() 看看有没有包含某个类,如果有则返回true,么有则返回false

        if (!icon.classList.contains('icon-queren2')) {
          alert('请勾选同意协议')
          e.preventDefault()
        }
      })
    }());

登录

    // 需求:
    // 1. 登录按钮点击的时候,需要先判断
    // 如果没有勾选同意,则提示要勾选
    // 如果勾选协议,则记住用户名和密码
    // 登录成功则跳转到首页
    // 注意,登录按钮需要先阻止默认行为

    let dl = document.querySelector('.dl')
    // 复选框
    let remember = document.querySelector('.remember')
    let username = document.querySelector('[name=username]')
    let password = document.querySelector('[name=password]')
    dl.addEventListener('click', function (e) {
      e.preventDefault()
      if (!remember.checked) {
        alert('请勾选协议')
        return
      }

      let obj = {
        username: username.value,
        password: password.value,
      }
      // console.log(obj)
      localStorage.setItem('pink', JSON.stringify(obj))
      // 跳转到新的页面
      location.href = './index.html'
    })


    // 2. 打开页面时候,如果本地存储有数据, 则自动记录显示用户名和密码,并勾选复选框
    let obj = JSON.parse(localStorage.getItem('pink'))
    if (obj) {
      username.value = obj.username
      password.value = obj.password
      // 如果有数据则默认勾选
      remember.checked = true
    }

首页

  <script>
    // 如果本地存储有数据,则 显示 你好 xxxx
    // 否则 显示 请跳转到注册页面

    let li = document.querySelector('.xtx_navs li:first-child')
    let obj = JSON.parse(localStorage.getItem('pink'))
    if (obj) {
      li.innerHTML = ` <a href="#">你好,${obj.username} 欢迎来到小兔鲜世界</a>`
    }
  </script>