WebApis知识总结以及案例(续3)

综合案例

小兔鲜页面注册

分析业务模块

发送验证码模块

用户点击之后,显示05 秒后重新获取

时间到了,自动改为重新获取

javascript 复制代码
    //1.发送短信验证码模块
    const code=document.querySelector('.code')
    let flag=true//通过一个变量来控制 节流阀 
    // 1.1 点击事件
    code.addEventListener('click',function(){
      if(flag){
        flag=false//时间未到点击之后不可触发事件
        let i=5
      // 点击完毕之后立马触发
      code.innerHTML=`0${i}秒后重新获取`

      let timerID=setInterval(function(){
        i--
        code.innerHTML=`0${i}秒后重新获取`
        if(i===0){
          clearInterval(timerID)
          flag=true//时间结束 点击之后可以触发事件
          // 重新获取
          code.innerHTML=`重新获取`
        }
      },1000)
      }
      
    })

各个表单验证模块

用户名验证(注意封装函数 verifyxxx),失去焦点触发这个函数

  • 正则/^[a-zA-Z0-9-_]$/{6,16}
  • 如果不符合要求,则出现提示信息 并return false中断程序
  • 否则 则返回return true
  • 之所以返回布尔值 是为了最后的提交按钮做准备
  • 侦听使用change事件,当鼠标离开了表单,并且表单值发生了变化时触发(类似京东效果)
javascript 复制代码
    const input =document.querySelector('input')
    input.addEventListener('change',function(){
      console.log(11);
    })
javascript 复制代码
    // 2.验证用户名
    // 2.1获取用户名表单
    const username=document.querySelector('[name=username]')
    username.addEventListener('change',verfiyName)//函数名不加括号
    // 2.3封装vertifyName函数
    function verfiyName(){
      const span=username.nextElementSibling
      // console.log(11)
      // 2.4 定规则
      const reg=/^[a-zA-Z0-9-_]{6,16}$/
      if(!reg.test(username.value)){
        // console.log(11)
        span.innerText='输入不合法,请输入6~16位'
        return false
      }
      // 合法的 就清空span
      span.innerText=''
      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}$/

其余同上
验证码验证

正则:/^\d{6}$/

其余同上
密码验证

正则:/^[a-zA-Z0-9-_]{6,20}$/

其余同上
再次密码验证

如果本次密码不等于上面输入的密码则返回错误信息

其余同上
我同意模块

添加类 .icon-queren2 则是默认选中样式,可以使用toggle切换类
表单提交模块

使用submit提交事件

勾选已经阅读统一模块

如果没有勾选同意协议,则提示需要勾选

classList.contains()看看有没有包含某个类,如果有则返回true,没有则返回false

下一步验证全部模块

只要上面有一个input验证不通过就不同意提交

如果上面input表单 只要有模块返回的是false 则阻止提交

javascript 复制代码
    (function(){
      //1.发送短信验证码模块
    const code=document.querySelector('.code')
    let flag=true//通过一个变量来控制 节流阀 
    // 1.1 点击事件
    code.addEventListener('click',function(){
      if(flag){
        flag=false//时间未到点击之后不可触发事件
        let i=5
      // 点击完毕之后立马触发
      code.innerHTML=`0${i}秒后重新获取`

      let timerID=setInterval(function(){
        i--
        code.innerHTML=`0${i}秒后重新获取`
        if(i===0){
          clearInterval(timerID)
          flag=true//时间结束 点击之后可以触发事件
          // 重新获取
          code.innerHTML=`重新获取`
        }
      },1000)
      }
    })
    });
    
    // 2.验证用户名
    // 2.1获取用户名表单
    const username=document.querySelector('[name=username]')
    username.addEventListener('change',verfiyName)//函数名不加括号
    // 2.3封装vertifyName函数
    function verfiyName(){
      const span=username.nextElementSibling
      // console.log(11)
      // 2.4 定规则
      const reg=/^[a-zA-Z0-9-_]{6,16}$/
      if(!reg.test(username.value)){
        // console.log(11)
        span.innerText='输入不合法,请输入6~16位'
        return false
      }
      // 合法的 就清空span
      span.innerText=''
      return true
    }



    // 3.验证手机号
    // 2.1获取手机表单
    const phone=document.querySelector('[name=phone]')
    phone.addEventListener('change',verfiyPhone)//函数名不加括号
    // 2.3封装verfiyPhone函数
    function verfiyPhone(){
      const span=phone.nextElementSibling
      // console.log(11)
      // 2.4 定规则
      const 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(11)
        span.innerText='输入不合法,请输入正确的手机号码'
        return false
      }
      // 合法的 就清空span
      span.innerText=''
      return true
    }



    // 4.验证验证码
    // 2.1获取验证码表单
    const code=document.querySelector('[name=code]')
    code.addEventListener('change',verfiyCode)//函数名不加括号
    // 2.3封装verfiycode函数
    function verfiyCode(){
      const span=code.nextElementSibling
      // console.log(11)
      // 2.4 定规则
      const reg=/^\d{6}$/
      if(!reg.test(code.value)){
        // console.log(11)
        span.innerText='输入不合法,请输入6位数字'
        return false
      }
      // 合法的 就清空span
      span.innerText=''
      return true
    }



    // 5.验证密码框
    // 2.1获取密码表单
    const password=document.querySelector('[name=password]')
    password.addEventListener('change',verfiypassword)//函数名不加括号
    // 2.3封装verfiypassword函数
    function verfiypassword(){
      const span=password.nextElementSibling
      // console.log(11)
      // 2.4 定规则
      const reg=/^[a-zA-Z0-9-_]{6,20}$/
      if(!reg.test(password.value)){
        // console.log(11)
        span.innerText='输入不合法,6~20位数字字母符号组成'
        return false
      }
      // 合法的 就清空span
      span.innerText=''
      return true
    }



    // 6.密码的再次验证
    // 2.1获取再次验证表单
    const confirm=document.querySelector('[name=confirm]')
    confirm.addEventListener('change',verfiyconfirm)//函数名不加括号
    // 2.3封装verfiyconfirm函数
    function verfiyconfirm(){
      const span=confirm.nextElementSibling
      // console.log(11)
      // 当前表单的值不等于密码框的值就是错误的
      if(confirm.value!==password.value){
        // console.log(11)
        span.innerText='两次密码输入不一致'
        return false
      }
      // 合法的 就清空span
      span.innerText=''
      return true
    }


    // 7.我同意
    const queren=document.querySelector('.icon-queren')
    queren.addEventListener('click',function(){
      // 原来有的就删掉 原来没有的就添加
      this.classList.toggle('icon-queren2')
    })



    // 8.提交模块
    const form=document.querySelector('form')
    form.addEventListener('submit',function(e){
      // 判断是否勾选我同意模块 如果有icon-queren2说明就勾选了 否则没勾选\
      if(!queren.classList.contains('icon-queren2')){
        e.preventDefault()
        return alert('请勾选同意协议')
      }
      //依次判断上面的每个input是否通过,只要有一个没通过就阻止
      if(!(verfiyName()&verfiyCode()&verfiyPhone()&verfiyconfirm()&verfiypassword())){
        e.preventDefault()
      }
    })

登录页

点击切换盒子

使用事件委托时,尽量不要在盒子套的很复杂的时候用,如果li标签里包了一个a元素,a元素里又包了个img元素,此时若给a标签设置事件委托,就不容易实现,因为点击的时候点击的是img元素。

javascript 复制代码
    // tab栏切换
    const tab_nav=document.querySelector('.tab-nav')
    const pane=document.querySelectorAll('.tab-pane')
    // 1.1事件监听
    tab_nav.addEventListener('click',function(e){
      if(e.target.tagName==='A'){
        //取消上一active
        //当前元素添加active
        tab_nav.querySelector('.active').classList.remove('active')
        e.target.classList.add('active')
        for(let i=0;i<pane.length;i++){
          // 先干掉所有人 for循环
          pane[i].style.display='none'
        }
        // 让对应序号的大pane 显示
        pane[e.target.dataset.id].style.display='block'
      }
    })

点击登陆可以跳转页面

  • 先阻止默认行为
  • 如果没有勾选同意,则提示要勾选
  • required属性不能为空
  • 假设登陆成功
  • 把用户名记录到本地存储当中
  • 同时跳转首页 location.href
javascript 复制代码
    // 点击提交模块
    const form=document.querySelector('form')
    const agree=document.querySelector('[name=agree]')
    const username=document.querySelector('[name=username]')
    form.addEventListener('submit',function(e){
      e.preventDefault()
      // 判断是否勾选同意协议
      if(!agree.checked){
        return alert('请勾选同意协议')
      }
      //记录用户名到本地存储
      localStorage.setItem('xtx-uname',username.value)
      // 跳转到首页
      location.href='./index.html'
    })

小兔鲜首页页面

步骤:

最好写个渲染函数,因为一会退出还要用到

1.如果本地存储有记录的用户名,读取本地存储数据

需要把用户名写到第一个li里面

格式:<a href="javascript:;"><i class="iconfont icon-user">用户名</i></a>
因为登陆了,所以第二个里面的文字变为:退出登录

格式:<a href="javascript:;">退出登录</a>

2.如果本地没有数据,则复原为默认的结构

3,点击退出登录,删除本地数据,并重新渲染函数

javascript 复制代码
    // 1.获取第一个小li
    const li1=document.querySelector('.xtx_navs li:first-child')
    const li2=li1.nextElementSibling
    // 2.最好做个渲染函数 因为退出登录需要重新渲染
    function render(){
    // 2.1读取本地存储的用户名
    const uname=localStorage.getItem('xtx-uname')
    // console.log(uname)
    if(uname){
      li1.innerHTML=`<a href="javascript:;"><i class="iconfont icon-user">${uname}</i></a>`
      li2.innerHTML=`<a href="javascript:;">退出登录</a>`
    }else{
      li1.innerHTML='<a href="./login.html">请先登录</a>'
      li2.innerHTML='<a href="./register.html">免费注册</a>'
    }
}
render()
// 2.点击退出登录模块
li2.addEventListener('click',function(){
  //删除本地存储的数据
  localStorage.removeItem('xtx-uname')
  render()
})

放大镜效果

业务分析:

  • 鼠标经过对应小盒子,左侧中等盒子显示对应中等图片

1.获取对应的元素

2.采取事件委托的形式,监听鼠标经过小盒子里面扽图片,注意此时需要使用mouseover事件,因为需要事件冒泡触发small

3.让鼠标经过小图片,可以拿到小图片的src,可以做两件事

  • 让中等盒子的图片换成这个小图片的src
  • 让大盒子的背景图片,也换成这个小图片的src
javascript 复制代码
    // 1. 获取三个盒子
    // 2. 小盒子 图片切换效果
    const small = document.querySelector('.small')
    //  中盒子
    const middle = document.querySelector('.middle')
    //  大盒子
    const large = document.querySelector('.large')
    // 2. 事件委托
    small.addEventListener('mouseover', function (e) {//事件冒泡
      if (e.target.tagName === 'IMG') {
        // console.log(111)
        // 排他 干掉以前的 active  li 上面
        this.querySelector('.active').classList.remove('active')
        // 当前元素的爸爸添加 active
        e.target.parentNode.classList.add('active')
        // 拿到当前小图片的 src
        // console.log(e.target.src)
        // 让中等盒子里面的图片,src 更换为   小图片src
        middle.querySelector('img').src = e.target.src
        // 大盒子更换背景图片
        large.style.backgroundImage = `url(${e.target.src})`
      }
    })
  • 鼠标经过中盒子,右侧会显示放大镜效果的大盒子

1.用到鼠标经过和i离开,鼠标经过中盒子,大盒子利用dislay来显示和隐藏

2,鼠标离开不会立马消失,而是有200ms的延迟,用户体验更好,所以尽量使用定时器做个延迟 settimeout

3.显示和隐藏也尽量定义一个函数,因为鼠标经过离开中等盒子,会显示隐藏,同时,鼠标经过大盒子,也会显示和隐藏

4,给大盒子里面的背景图片一个默认的第一张图片

javascript 复制代码
    // 3. 鼠标经过中等盒子, 显示隐藏 大盒子
    middle.addEventListener('mouseenter', show)
    middle.addEventListener('mouseleave', hide)
    let timeId = null
    // 显示函数 显示大盒子
    function show() {
      // 先清除定时器
      clearTimeout(timeId)
      large.style.display = 'block'
    }
    // 隐藏函数 隐藏大盒子
    function hide() {
      timeId = setTimeout(function () {
        large.style.display = 'none'
      }, 200)
    }


    // 4. 鼠标经过大盒子, 显示隐藏 大盒子
    large.addEventListener('mouseenter', show)
    large.addEventListener('mouseleave', hide)
  • 黑色遮罩盒子跟着鼠标来移动
  1. 先做鼠标经过小盒子small盒子,显示隐藏黑色遮罩的盒子
  2. 让黑色遮罩跟着鼠标来走,需要用到鼠标移动事件 mousermove
  3. 让黑色盒子移动的核心思想:不断把鼠标在中等盒子内的坐标给遮罩层left top,这样遮罩层就可以跟着移动了

算法

  • 得到鼠标在页面中的坐标,利用事件对象的pageX
  • 得到中等盒子在页面中的坐标 middle.getBoundingClientRect()
  • 鼠标在中等盒子中的坐标=鼠标在页面中的坐标-middle中等盒子的坐标
  • 黑色遮罩层不断得到 鼠标在中等盒子中的坐标 就可以移动起来了
  • 注意y坐标特殊,需要减去页面被卷去的头部
  • 不用offsetLeft和offsetTop的原因:因为这两个属性跟带有定位的父级有关系,很容易被父级影响,而getBoundingClientRect()不受定位父元素的影响

限定遮罩的盒子只能在middle内部移动,需要添加判断

  • 限定水平方向 大于等于0并且小于等于400
  • 限定垂直方向大于等于0并且小于等于400

遮罩盒子移动的坐标:

  • 声明一个mx作为移动的距离
  • 水平坐标x如果小于等于100,则移动的距离mx就是0,不应该移动
  • 水平坐标如果大于等于100并且小于300,移动的距离就是mx-100(100)是遮罩层盒子自身宽度的一半
  • 水平坐标如果大于等于300,移动的距离就是mx=200不用再移动了
  • 其实水平移动就是在100~200之间移动的
  • 鼠标在中等盒子上移动,大盒子的图片跟着显示对应位置
javascript 复制代码
    // 5. 鼠标经过中等盒子,显示隐藏 黑色遮罩层
    const layer = document.querySelector('.layer')
    middle.addEventListener('mouseenter', function () {
      layer.style.display = 'block'
    })
    middle.addEventListener('mouseleave', function () {
      layer.style.display = 'none'
    })
    // 6.移动黑色遮罩盒子
    middle.addEventListener('mousemove', function (e) {
      // let x = 10, y = 20
      // console.log(11)
      // 鼠标在middle 盒子里面的坐标 = 鼠标在页面中的坐标 - middle 中等盒子的坐标
      // console.log(e.pageX)鼠标在页面中的坐标
      // middle 中等盒子的坐标
      // console.log(middle.getBoundingClientRect().left)
      let x = e.pageX - middle.getBoundingClientRect().left
      let y = e.pageY - middle.getBoundingClientRect().top - document.documentElement.scrollTop//解决页面滚动时框下移的问题,减去被卷去的头部
      // console.log(x, y)
      // 黑色遮罩移动 在 middle 盒子内 限定移动的距离
      if (x >= 0 && x <= 400 && y >= 0 && y <= 400) {
        // 黑色盒子不是一直移动的
        // 声明2个变量 黑色盒子移动的 mx my变量 
        let mx = 0, my = 0
        if (x < 100) mx = 0
        if (x >= 100 && x <= 300) mx = x - 100
        if (x > 300) mx = 200

        if (y < 100) my = 0
        if (y >= 100 && y <= 300) my = y - 100
        if (y > 300) my = 200

        layer.style.left = mx + 'px'
        layer.style.top = my + 'px'
        // 大盒子的背景图片要跟随 中等盒子移动  存在的关系是 2倍   
        large.style.backgroundPositionX = -2 * mx + 'px'
        large.style.backgroundPositionY = -2 * my + 'px'
      }
    })
相关推荐
hong_zc4 分钟前
初始 html
前端·html
小小吱9 分钟前
HTML动画
前端·html
Xiao Fei Xiangζั͡ޓއއ14 分钟前
一觉睡醒,全世界计算机水平下降100倍,而我却精通C语言——scanf函数
c语言·开发语言·笔记·程序人生·面试·蓝桥杯·学习方法
记录无知岁月17 分钟前
【MATLAB】目标检测初探
开发语言·yolo·目标检测·matlab·yolov3·yolov2
Bio Coder26 分钟前
学习用 Javascript、HTML、CSS 以及 Node.js 开发一个 uTools 插件,学习计划及其周期
javascript·学习·html·开发·utools
糊涂涂是个小盆友31 分钟前
前端 - 使用uniapp+vue搭建前端项目(app端)
前端·vue.js·uni-app
远望清一色31 分钟前
基于MATLAB身份证号码识别
开发语言·图像处理·算法·matlab
NMBG2239 分钟前
[JAVAEE] 面试题(四) - 多线程下使用ArrayList涉及到的线程安全问题及解决
java·开发语言·面试·java-ee·intellij-idea
Py小趴44 分钟前
Python自学之Colormaps指南
开发语言·python·数据可视化
晒足以百八十1 小时前
基于Python 和 pyecharts 制作招聘数据可视化分析大屏
开发语言·python·信息可视化