JavaScript自学Day11-一些补充和总结

154 阅读2分钟

1. tab栏切换——排他思想

使用场景: 切换tab栏时,改变选项的选中状态 排他思想:

  1. 移除上一个选中状态的选中类名
  2. 为当前元素添加选中类名
  //1.tab栏切换
    const tabNav = document.querySelector('.tab-nav')
    const tabPane = document.querySelectorAll('.tab-pane')
    console.log(tabPane)
    tabNav.addEventListener('click',function(e){
      if(e.target.tagName === 'A'){
        //排他,取消上一个元素的active,为当前元素添加active
        tabNav.querySelector('.active').classList.remove('active')
        e.target.classList.add('active')
        for(let i = 0;i<tabPane.length;i++){
          tabPane[i].style.display = 'none'
        }
        tabPane[e.target.dataset.id].style.display = 'block'
      }
    })

    //2.提交模块
    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'
    })

2. 表单验证

验证表单内容时,建议使用函数,当失去焦点时触发函数。

  • 如果不符合要求,则出现提示信息,并 return false 中断程序
  • 如果符合要求,则 return true

返回布尔值的原因: 当点击提交时,根据验证函数返回值确定是否阻止提交表单

//1.点击发送验证码
    const code = document.querySelector('.code')
    let flag = true  //通过flag变量来控制是否能够点击  节流阀
    code.addEventListener('click', function () {
      if (flag) {
        //取反,不能马上第二次点击
        flag = false
        let i = 5
        code.innerHTML = '05秒后重新获取'
        const timeId = setInterval(function () {
          i--
          code.innerHTML = `0${i}秒后重新获取`
          if (i === 0) {
            clearInterval(timeId)
            code.innerHTML = `重新获取`
            //倒计时结束,可以再次点击
            flag = true
          }
        }, 1000)
      }
    })

    //2.验证用户名
    const username = document.querySelector('[name=username]')
    username.addEventListener('change', verifyName)
    //封装检验函数
    function verifyName() {
      const msg = username.nextElementSibling
      //定义正则,检验用户输入是否符合
      const regt = /^[a-zA-Z0-9-_]{6,10}$/.test(username.value)
      if (!regt) {
        msg.innerHTML = '格式错误,请输入6~10位'
        return false
      }
      msg.innerHTML = ''
      return true
    }

    //3.验证手机号
    const phone = document.querySelector('[name=phone]')
    phone.addEventListener('change', verifyPhone)
    //封装检验函数
    function verifyPhone() {
      const msg = phone.nextElementSibling
      //定义正则,检验用户输入是否符合要求
      const regt = /^1(3\d|4[5-9]|5[0-35-9]|6[567]|7[0-8]|8\d|9[0-35-9])\d{8}$/.test(phone.value)
      if (!regt) {
        msg.innerHTML = '格式错误,请输入11位手机号'
        return false
      }
      msg.innerHTML = ''
      return true
    }

    //4.验证验证码
    const codeInput = document.querySelector('[name=code]')
    codeInput.addEventListener('change', verifyCode)
    //封装检验函数
    function verifyCode() {
      const msg = codeInput.nextElementSibling
      //定义正则,检验用户输入是否符合要求
      const regt = /^\d{6}$/.test(codeInput.value)
      if (!regt) {
        msg.innerHTML = '格式错误,请输入6位数字'
        return false
      }
      msg.innerHTML = ''
      return true
    }

    //5.验证密码
    const password = document.querySelector('[name=password]')
    password.addEventListener('change', verifyPassword)
    //封装检验函数
    function verifyPassword() {
      const msg = password.nextElementSibling
      //定义正则,检验用户输入是否符合要求
      const regt = /^[a-zA-Z0-9-_]{6,20}$/.test(password.value)
      if (!regt) {
        msg.innerHTML = '格式错误,6-20位数字或字母组成'
        return false
      }
      msg.innerHTML = ''
      return true
    }

    //6.再次验证密码
    const confirm = document.querySelector('[name=confirm]')
    confirm.addEventListener('change', verifyConfirm)
    //封装检验函数
    function verifyConfirm() {
      const msg = confirm.nextElementSibling
      if (confirm.value !== password.value) {
        msg.innerHTML = '密码不一致'
        return false
      }
      msg.innerHTML = ''
      return true
    }

    //7.我同意模块
    const agree = document.querySelector('.icon-queren')
    agree.addEventListener('click',function(){
      //切换类
      this.classList.toggle('icon-queren2')
    })

    //8.表单提交模块
    const form = document.querySelector('form')
    //绑定提交事件
    form.addEventListener('submit',function(e){
      //8.1判断是否勾选 我同意
      //如果没有勾选,弹出提示,阻止表单提交
      if(!agree.classList.contains('icon-queren2')){
        alert('请勾选我同意')
        e.preventDefault()
      }
      //8.2依次判断表单项,只要有一项没通过就阻止表单提交
      if(!verifyName()) e.preventDefault()
      if(!verifyPhone()) e.preventDefault()
      if(!verifyCode()) e.preventDefault()
      if(!verifyPassword()) e.preventDefault()
      if(!verifyConfirm()) e.preventDefault()
    })

3. 就业统计表

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport"
    content="width=device-width, initial-scale=1.0" />
  <meta http-equiv="X-UA-Compatible"
    content="ie=edge" />
  <title>学生就业统计表</title>
  <link rel="stylesheet"
    href="./iconfont/iconfont.css">
  <link rel="stylesheet"
    href="css/index.css" />
</head>

<body>
  <h1>学生就业统计表</h1>
  <form class="info"
    autocomplete="off">
    <input type="text"
      class="uname"
      name="uname"
      placeholder="姓名" />
    <input type="text"
      class="age"
      name="age"
      placeholder="年龄" />
    <input type="text"
      class="salary"
      name="salary"
      placeholder="薪资" />
    <select name="gender"
      class="gender">
      <option value="男"></option>
      <option value="女"></option>
    </select>
    <select name="city"
      class="city">
      <option value="北京">北京</option>
      <option value="上海">上海</option>
      <option value="广州">广州</option>
      <option value="深圳">深圳</option>
      <option value="曹县">曹县</option>
    </select>
    <button class="add">
      <i class="iconfont icon-tianjia"></i>添加
    </button>
  </form>

  <div class="title">共有数据<span>0</span></div>
  <table>
    <thead>
      <tr>
        <th>ID</th>
        <th>姓名</th>
        <th>年龄</th>
        <th>性别</th>
        <th>薪资</th>
        <th>就业城市</th>
        <th>录入时间</th>
        <th>操作</th>
      </tr>
    </thead>
    <tbody>
      <!-- <tr>
        <td>1</td>
        <td>迪丽热巴</td>
        <td>23</td>
        <td>女</td>
        <td>12000</td>
        <td>北京</td>
        <td>2099/9/9 08:08:08</td>
        <td>
          <a href="javascript:">
            <i class="iconfont icon-shanchu"></i>
            删除
          </a>
        </td>
      </tr> -->
    </tbody>
  </table>
  <script>
    // 参考数据
    const initData = [
      {
        stuId: 1,
        uname: '迪丽热巴',
        age: 22,
        salary: '12000',
        gender: '女',
        city: '北京',
        time: '2099/9/9 08:08:08'
      }
    ]
    // localStorage.setItem('initData',JSON.stringify(initData))
    // 1. 渲染业务
    // 1.1 先读取本地存储的数据
    // (1). 本地存储有数据则记得转换为对象然后存储到变量里面,后期用于渲染页面
    // (2). 如果没有数据,则用 空数组来代替
    const arr = JSON.parse(localStorage.getItem('data')) || []
    // console.log(arr)
    // 1.2 利用map和join方法来渲染页面
    const tbody = document.querySelector('tbody')
    const num = document.querySelector('.title span')
    function render() {
      // (1). 利用map遍历数组,返回对应tr的数组
      const trArr = arr.map(function (ele, index) {
        return `
        <tr>
          <td>${ele.stuId}</td>
          <td>${ele.uname}</td>
          <td>${ele.age}</td>
          <td>${ele.gender}</td>
          <td>${ele.salary}</td>
          <td>${ele.city}</td>
          <td>${ele.time}</td>
          <td>
          <a href="javascript:" data-id="${index}">
            <i class="iconfont icon-shanchu"></i>
            删除
          </a>
          </td>
        </tr>
        `
      })
      // (2). 把数组转换为字符串 join
      // (3). 把生成的字符串追加给tbody 
      tbody.innerHTML = trArr.join('')
      // 显示共计有几条数据
      num.innerHTML = arr.length
    }
    render()
    // 2. 新增业务
    const info = document.querySelector('.info')
    const uname = document.querySelector('.uname')
    const age = document.querySelector('.age')
    const salary = document.querySelector('.salary')
    const gender = document.querySelector('.gender')
    const city = document.querySelector('.city')
    // 2.1 form表单注册提交事件,阻止默认行为
    info.addEventListener('submit', function (e) {
      e.preventDefault()
      // 2.2 非空判断
      if (!uname.value || !age.value || !salary.value) {
        alert('请输入内容后提交')
      }
      // 2.3 给 arr 数组追加对象,里面存储 表单获取过来的数据
      arr.push({
        // 处理 stuId:数组最后一条数据的stuId + 1
        // stuId: arr.length + 1,
        stuId: arr.length ? arr[arr.length - 1].stuId + 1 : 1,
        uname: uname.value,
        age: age.value,
        salary: salary.value,
        gender: gender.value,
        city: city.value,
        time: new Date().toLocaleString()
      })
      render()
      // 2.4 渲染页面和重置表单(reset()方法)
      this.reset()
      // 2.5 把数组重新存入本地存储里面,记得转换为JSON字符串存储
      localStorage.setItem('data', JSON.stringify(arr))
    })

    // 3. 删除业务
    // 3.1 采用事件委托形式,给 tbody 注册点击事件
    tbody.addEventListener('click', function (e) {
      // 判断是否点击的是删除按钮  A 链接
      if (e.target.tagName === 'A') {
        // 3.2 得到当前点击链接的索引号。渲染数据的时候,动态给a链接添加自定义属性例如 data-id="0"
        // console.log(e.target.dataset.id)
        // 确认框 确认是否要真的删除
        if (confirm('您确认要删除数据吗?')) {
          // 3.3 根据索引号,利用 splice 删除数组这条数据
          arr.splice(e.target.dataset.id, 1)
          // 3.4 重新渲染页面
          render()
          // 3.5 把最新 arr 数组存入本地存储
          localStorage.setItem('data', JSON.stringify(arr))
        }
      }
    })
  </script>
</body>

</html>

4. 放大镜效果

补充知识pageX pageY 属性可得到鼠标在页面中的横纵坐标 getBoundingClientRect() 方法其提供了元素的大小及其相对于视口的位置。

<!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>
    <link rel="stylesheet"
        href="./index.css">
</head>

<body>
    <div>
        <div class="Lbox">
            <img src="./img/2.jpg"
                alt="">
            <div class="mask-layer"></div>
        </div>
        <div class="Rbox"></div>
    </div>
    <script>
        //1. 获取DOM元素
        const Lbox = document.querySelector('.Lbox')
        const Rbox = document.querySelector('.Rbox')
        const maskLayer = document.querySelector('.mask-layer')
        //定义一个变量,用来接受定时器序号
        let timeId = 0

        //2. 给Lbox绑定鼠标移入移出事件
        Lbox.addEventListener('mouseenter', show)
        Lbox.addEventListener('mouseleave', hide)

        //3. 封装显示、隐藏函数
        function show() {
            //显示前先清除定时器
            clearInterval(timeId)
            Rbox.style.display = 'block'
        }
        function hide() {
            //设置定时器,鼠标离开延时隐藏
            timeId = setInterval(function () {
                Rbox.style.display = 'none'
            }, 200)
        }

        //4. 给Rbox绑定鼠标移入移出事件
        Rbox.addEventListener('mouseenter', show)
        Rbox.addEventListener('mouseleave', hide)

        //5.显示、隐藏遮罩层
        Lbox.addEventListener('mouseenter', function () {
            maskLayer.style.display = 'block'
        })
        Lbox.addEventListener('mouseleave', function () {
            maskLayer.style.display = 'none'
        })

        //6.根据鼠标位置移动遮罩层
        Lbox.addEventListener('mousemove', function (e) {
            //e.pageX获取鼠标在页面中X轴坐标
            //getBoundingClientRect()方法的.left属性,获取Lbox在页面中的坐标
            //获取鼠标在 Lbox 中的坐标值
            let x = e.pageX - Lbox.getBoundingClientRect().left
            //y坐标还要减去滚动条卷去的头部
            let y = e.pageY - Lbox.getBoundingClientRect().top - document.documentElement.scrollTop
            //改变遮罩层的位置
            //限定遮罩层在Lbox中的移动距离
            if (x >= 0 && x <= 500 && y >= 0 && y <= 500) {
                //声明mx和my两个变量,用于限定遮罩层的移动
                let mx = 0, my = 0
                //如果 x∈[0,90) 遮罩层不移动
                if (x < 90) mx = 0
                //如果x∈[90,410] 遮罩层开始移动
                if (x >= 90 && x <= 410) mx = x - 90
                //如果x∈(410,500] 遮罩层不移动
                if (x > 410) mx = 320

                // my同mx
                if (y < 90) my = 0
                if (y >= 90 && y <= 410) my = y - 90
                if (y > 410) my = 320
                //根据计算过的 mx 和 my 改变遮罩层的位置,注意加单位
                maskLayer.style.left = mx + 'px'
                maskLayer.style.top = my + 'px'

                //7. 放大镜效果/鼠标在Lbox中移动,Rbox中的背景图位置移动
                Rbox.style.backgroundPositionX = -0.92 * mx + 'px'
                Rbox.style.backgroundPositionY = -0.92 * my + 'px'
            }
        })
    </script>
</body>

</html>