pink老师前端案例

116 阅读4分钟

tab切换

<!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>tab栏切换</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }

        .tab {
            width: 590px;
            height: 340px;
            margin: 20px;
            border: 1px solid #e4e4e4;
        }

        .tab-nav {
            width: 100%;
            height: 60px;
            line-height: 60px;
            display: flex;
            justify-content: space-between;
        }

        .tab-nav h3 {
            font-size: 24px;
            font-weight: normal;
            margin-left: 20px;
        }

        .tab-nav ul {
            list-style: none;
            display: flex;
            justify-content: flex-end;
        }

        .tab-nav ul li {
            margin: 0 20px;
            font-size: 14px;
        }

        .tab-nav ul li a {
            text-decoration: none;
            border-bottom: 2px solid transparent;
            color: #333;
        }

        .tab-nav ul li a.active {
            border-color: #e1251b;
            color: #e1251b;
        }

        .tab-content {
            padding: 0 16px;
        }

        .tab-content .item {
            display: none;
        }

        .tab-content .item.active {
            display: block;
        }
    </style>
</head>

<body>
    <div class="tab">
        <div class="tab-nav">
            <h3>每日特价</h3>
            <ul>
                <li><a class="active" href="javascript:;" data-id="0">精选</a></li>
                <li><a href="javascript:;" data-id="1">美食</a></li>
                <li><a href="javascript:;" data-id="2">百货</a></li>
                <li><a href="javascript:;" data-id="3">个护</a></li>
                <li><a href="javascript:;" data-id="4">预告</a></li>
            </ul>
        </div>
        <div class="tab-content">
            <div class="item active"><img src="./images/tab00.png" alt="" /></div>
            <div class="item"><img src="./images/tab01.png" alt="" /></div>
            <div class="item"><img src="./images/tab02.png" alt="" /></div>
            <div class="item"><img src="./images/tab03.png" alt="" /></div>
            <div class="item"><img src="./images/tab04.png" alt="" /></div>
        </div>
    </div>

</body>
<script>
    /* const as = document.querySelectorAll('.tab-nav ul li a')
    const items = document.querySelectorAll('.tab-content .item')
    const imgs = document.querySelectorAll('.tab-content .item img')
    // console.log(imgs);
    for (let i = 0; i < as.length; i++) {
        as[i].addEventListener('mouseenter', (e) => {
            // for (let a of as) {
            //     // a.style.display = 'none'
            //     a.classList.remove('active')
            // }
            document.querySelector('.tab-nav .active').classList.remove('active') //每次都删掉上一个active类
            as[i].classList.add('active')


            //原来加上active类就可以了
            document.querySelector('.tab-content .active').classList.remove('active')
            // items[i].classList.add('active')
            document.querySelector(`.tab-content .item:nth-child(${i + 1})`).classList.add('active')

        })


    } */
    /* 事件委托重写 */

    const ul = document.querySelector('.tab-nav ul')

    ul.addEventListener('click', function (e) {
        if (e.target.tagName === 'A') {
            // console.log('A');
            document.querySelector('.tab-nav .active').classList.remove('active')
            e.target.classList.add('active')

            // console.log(e.target.dataset.id);
            const id = +e.target.dataset.id;
            //大盒子 active
            document.querySelector('.tab-content .active').classList.remove('active')

            document.querySelector(`.tab-content .item:nth-child(${id + 1})`).classList.add('active')
        }
    })
    //之前给每个li的a都创建了一个监听器,现在是为父元素ul创建监听器,e.target是当前选中的元素
    //尝试用dataset获取对应的id
</script>

</html>

学生信息表案例

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

<body>
  <h1>新增学员</h1>
  <form class="info" autocomplete="off">
    姓名:<input type="text" class="uname" name="uname" />
    年龄:<input type="text" class="age" name="age" />
    性别:
    <select name="gender" class="gender">
      <option value="男"></option>
      <option value="女"></option>
    </select>
    薪资:<input type="text" class="salary" name="salary" />
    就业城市:<select name="city" class="city">
      <option value="北京">北京</option>
      <option value="上海">上海</option>
      <option value="广州">广州</option>
      <option value="深圳">深圳</option>
      <option value="曹县">曹县</option>
    </select>
    <button class="add">录入</button>
  </form>

  <h1>就业榜</h1>
  <div style="text-align: center;">
    共有数据<span>0</span></div>
  <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>
    //   /* 自己照着写 
    //   减少dom操作 删除不是删除dom而是删除数组的数据
    //   */
    //   const arr = []

    //   const uname = document.querySelector('.uname')
    //   const age = document.querySelector('.age')
    //   const gender = document.querySelector('.gender')
    //   const salary = document.querySelector('.salary')
    //   const city = document.querySelector('.city')
    //   //获取表单
    //   const info = document.querySelector('.info')

    //   const nameItems = document.querySelectorAll('[name]')
    //   info.addEventListener('submit', function (e) {
    //     //提交不要跳到别的页面
    //     e.preventDefault()

    //     //非空判断, 如果为空则跳出函数
    //     for (let i = 0; i < nameItems.length; i++) {
    //       if (nameItems[i].value === '') {
    //         return alert('输入不能为空')
    //       }
    //     }
    //     // console.log(uname.value)
    //     const obj = {
    //       stuId: arr.length + 1,
    //       uname: uname.value,
    //       age: age.value,
    //       gender: gender.value,
    //       salary: salary.value,
    //       city: city.value

    //     }
    //     // obj.uname = uname.value
    //     // obj.age = age.value
    //     // obj.gender = gender.value
    //     // obj.salary = salary.value
    //     // obj.city = city.value
    //     // console.log(obj);
    //     // arr.append(obj)
    //     arr.push(obj)
    //     //提交完后重置表单
    //     this.reset();
    //     render()
    //     // console.log(arr)
    //   })
    //   // 参考数据
    //   // const initData = [
    //   //   {
    //   //     stuId: 1001,
    //   //     uname: '欧阳霸天',
    //   //     age: 19,
    //   //     gender: '男',
    //   //     salary: '20000',
    //   //     city: '上海',
    //   //   }
    //   // ]
    //   const tbody = document.querySelector('tbody')
    //   function render() {
    //     // 清空tbody的内容防止重复,每次添加新对象都重复渲染一次
    //     tbody.innerHTML = ''
    //     for (let i = 0; i < arr.length; i++) {
    //       const tr = document.createElement('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>
    //         `
    //       // console.log(tr)
    //       tbody.append(tr)
    //       // console.log(tbody);
    //     }
    //   }


    //   //删除操作 使用事件委托 删除的是数组元素
    //   tbody.addEventListener('click', function (e) {
    //     if (e.target.tagName === 'A') {
    //       // document.querySelector('tbody td')
    //       arr[e.target.dataset.id]
    //       arr.splice(e.target.dataset.id, 1)
    //       render()
    //     }
    //   }) 

    //存入本地存储
    const initData = [
      {
        stuId: 1001,
        uname: '欧阳霸天',
        age: 19,
        gender: '男',
        salary: '20000',
        city: '上海',
      }
    ]
    // localStorage.setItem('data', JSON.stringify(initData))
    //渲染页面
    arr = JSON.parse(localStorage.getItem('data')) || []
    const tbody = document.querySelector('tbody')

    function render() {
      //通过map创建数组 替代for
      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>
              <a href="javascript: " data-id="${index}">删除</a>
            </td>
          </tr>
            `
      })
      //用join将数组转化为字符串
      tbody.innerHTML = trArr.join('')
      const tiaoshu = document.querySelector('div span')
      tiaoshu.innerHTML = trArr.length
    }



    //提交数据
    const uname = document.querySelector('.uname')
    const age = document.querySelector('.age')
    const gender = document.querySelector('.gender')
    const salary = document.querySelector('.salary')
    const city = document.querySelector('.city')
    //获取表单
    const info = document.querySelector('.info')
    const nameItems = document.querySelectorAll('[name]')
    // const arr = []

    //负责学号的全局变量
    let num = 0
    info.addEventListener('submit', function (e) {
      num++;
      e.preventDefault()
      //输入有一个为空则不提交
      for (let i = 0; i < nameItems.length; i++) {
        if (nameItems[i].value === '') {
          return alert('输入不能为空')
        }
      }
      // console.log(arr[arr.length - 1], arr.length);
      arr.push({
        // stuId: arr.length + 1, 学号为数组长度加一 删除会产生重复学号
        // stuId: arr.length ? arr[arr.length - 1].stuId + 1 : 1,
        // 上面写法 数组最后一个元素的学号加一 , 不符合现实情况
        // 创建一个全局变量 每次创建则加一
        stuId: num,
        uname: uname.value,
        age: age.value,
        gender: gender.value,
        salary: salary.value,
        city: city.value,
      });
      render()
      this.reset()
      //把数据存在本地存储
      localStorage.setItem('data', JSON.stringify(arr))
    })

    //将本地存储的数据删除 再渲染
    tbody.addEventListener('click', function (e) {
      if (e.target.tagName === 'A') {
        // console.log('hello')
        if (confirm('您确定要删除吗')) {
          arr.splice(e.target.dataset.id, 1)
          // console.log(arr)
          // localStorage.removeItem('data')
          localStorage.setItem('data', JSON.stringify(arr))
          render()
        }

      }
    })



  </script>

</body>

</html>

倒计时

function getCountTime() {

      countdown.style.backgroundColor = getRandomColor()

      // 1. 得到当前的时间戳
      const now = +new Date()
      const date = new Date()
      // 2. 得到将来的时间戳
      // console.log(date.toLocaleDateString() + ' 18:30:00')

      const last = +new Date(date.toLocaleDateString() + ' 18:30:00')
      // console.log(now, last)
      // 3. 得到剩余的时间戳 count  记得转换为 秒数
      const count = (last - now) / 1000
      // console.log(count)
      // 4. 转换为时分秒
      // h = parseInt(总秒数 / 60 / 60 % 24)   //   计算小时
      // m = parseInt(总秒数 / 60 % 60);     //   计算分数
      // s = parseInt(总秒数 % 60);   
      // let d = parseInt(count / 60 / 60 / 24)               //   计算当前秒数
      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
      console.log(h, m, s)

      //  5. 把时分秒写到对应的盒子里面
      document.querySelector('#hour').innerHTML = h
      document.querySelector('#minutes').innerHTML = m
      document.querySelector('#scond').innerHTML = s
    }
    // 先调用一次
    getCountTime()

    // 开启定时器
    setInterval(getCountTime, 1000)

电梯导航

  //第一个模块 往下滚动显示侧栏 按键回到顶部
  (function () {
    const xtxElevator = document.querySelector('.xtx-elevator')
    const xtx_entry = document.querySelector('.xtx_entry')
    // const xtx_banner = document.querySelector('.xtx_banner')
    // console.log(xtx_entry.offsetTop);
    // console.log(xtx_banner.offsetTop);
    window.addEventListener('scroll', function () {
      if (document.documentElement.scrollTop >= xtx_entry.offsetTop) {
        xtxElevator.style.opacity = 1
      }
      else {
        xtxElevator.style.opacity = 0
      }
    })
    //按键回到页面顶部
    const backTop = document.querySelector('#backTop');
    backTop.addEventListener('click', () => {
      document.documentElement.scrollTop = 0
      // window.scrollTo(0,0) 另一种方法
    })
  })();
  //第二个模块 点击页面滑动 使用事件委托

  (function () {
    const xtxElevatorList = document.querySelector('.xtx-elevator-list')
    // console.log(xtxElevatorList);
    xtxElevatorList.addEventListener('click', (e) => {
      if (e.target.tagName === 'A' && e.target.dataset.name) {
        // console.log('A');
        /* 点击变绿 添加active类实现 */
        // document.querySelector('.xtx-elevator-list active').classList.remove('active') 找不到会返回null
        //改进写法
        const old = document.querySelector('.xtx-elevator-list .active')
        if (old) {
          old.classList.remove('active')
        }
        e.target.classList.add('active')
        // const box = document.querySelector(`.xtx_goods_${e.target.dataset.name}`) //根据当前的dataset定位位置
        const box = document.querySelector('.xtx_goods_' + e.target.dataset.name)
        // console.log(box);
        document.documentElement.scrollTop = box.offsetTop
      }

    })
  })();
  //第三个模块滑动到大盒子的位置 右边对应高亮
  (function () {
    // console.log(document.querySelector('.xtx_goods_new').offsetTop);
    const xtxNew = document.querySelector('.xtx_goods_new')
    const xtxPopular = document.querySelector('.xtx_goods_popular')
    const xtxBrand = document.querySelector('.xtx_goods_brand')
    const xtxTopic = document.querySelector('.xtx_goods_topic')
    // const as = document.querySelectorAll('.xtx-elevator-list a')
    //滑到对应的offsetTop 为右边添加active


    window.addEventListener('scroll', function () {
      //先移除上一个类
      const old = document.querySelector('.xtx-elevator-list .active')
      const n = document.documentElement.scrollTop
      if (old) {
        old.classList.remove('active')
      }
      if (n >= xtxTopic.offsetTop) {
        // console.log('hello');
        document.querySelector('[data-name="topic"]').classList.add('active')
      }
      else if (n >= xtxBrand.offsetTop) {
        document.querySelector('[data-name="brand"]').classList.add('active')
      }
      else if (n >= xtxPopular.offsetTop) {
        document.querySelector('[data-name="popular"]').classList.add('active')
      }
      else if (n >= xtxNew.offsetTop) {
        document.querySelector('[data-name="new"]').classList.add('active')
      }
    })

  })();

放大镜效果

 //移动黑色遮罩
    const layer = document.querySelector('.layer')
    
      middle.addEventListener('mouseenter', function () {
        layer.style.display = 'block'
      })
      middle.addEventListener('mouseleave', function () {
        layer.style.display = 'none'
      })
    middle.addEventListener('mousemove', function(e){
      //获取箭头的x,y坐标,箭头相对的页面距离减去中盒子相对视口距离
      let x = e.pageX - middle.getBoundingClientRect().left
      let y = e.pageY - middle.getBoundingClientRect().top - document.documentElement.scrollTop
      //2根据箭头坐标,算出盒子左上角应该固定在哪里,注意黑色盒子不要超出中盒子
      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 //鼠标超出位置盒子设置坐标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'
      }
    })

防抖节流

<!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 {
      width: 500px;
      height: 500px;
      background-color: #ccc;
      color: #fff;
      text-align: center;
      font-size: 100px;
    }
  </style>
</head>

<body>
  <div class="box"></div>
  <script>
    const box = document.querySelector('.box')
    let i = 0
    function mouseMove(){
      box.innerHTML = ++i
    }
    function debounce(fn, t){
      let timeId;
      //这样写在500毫秒内 如果鼠标不断移动 则会不断触发监听器
      //然后会不断的清除定时器 直到停止移动
      //利用闭包的写法 timeId写在外层函数,所以每次移动都是调用的匿名函数,timeId只有一个且不会被销毁
      //所以才要判断timeId是否为null
      return function(){
        
        if (timeId) clearTimeout(timeId)
        timeId = setTimeout(() => {
          fn()
        }, t);
        
      }
    }
    // box.addEventListener('mousemove',debounce(mouseMove,500))
        box.addEventListener('mousemove', throttle(mouseMove, 500))

    function throttle(fn, t){
      let timeId = null;
      return function(){
        if(!timeId){
          timeId = setTimeout(function(){
            fn()
            //时间到了才清除定时器
            //在setTimeout里 此时clearTimeout(timeId)没有效果 timeId不为null 这样就防止了重复设置定时器,
            //一旦时间到则timeId为null  就可以再次调用定时器 这样没法清除定时器
            timeId = null
          },t)
        }
      }
    }
  </script>
</body>

</html>

利用api改进案例渲染写法

<!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>
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }

    .list {
      width: 990px;
      margin: 100px auto 0;
    }

    .item {
      padding: 15px;
      transition: all .5s;
      display: flex;
      border-top: 1px solid #e4e4e4;
    }

    .item:nth-child(4n) {
      margin-left: 0;
    }

    .item:hover {
      cursor: pointer;
      background-color: #f5f5f5;
    }

    .item img {
      width: 80px;
      height: 80px;
      margin-right: 10px;
    }

    .item .name {
      font-size: 18px;
      margin-right: 10px;
      color: #333;
      flex: 2;
    }

    .item .name .tag {
      display: block;
      padding: 2px;
      font-size: 12px;
      color: #999;
    }

    .item .price,
    .item .sub-total {
      font-size: 18px;
      color: firebrick;
      flex: 1;
    }

    .item .price::before,
    .item .sub-total::before,
    .amount::before {
      content: "¥";
      font-size: 12px;
    }

    .item .spec {
      flex: 2;
      color: #888;
      font-size: 14px;
    }

    .item .count {
      flex: 1;
      color: #aaa;
    }

    .total {
      width: 990px;
      margin: 0 auto;
      display: flex;
      justify-content: flex-end;
      border-top: 1px solid #e4e4e4;
      padding: 20px;
    }

    .total .amount {
      font-size: 18px;
      color: firebrick;
      font-weight: bold;
      margin-right: 50px;
    }
  </style>
</head>

<body>
  <div class="list">
    <!-- <div class="item">
      <img src="https://yanxuan-item.nosdn.127.net/84a59ff9c58a77032564e61f716846d6.jpg" alt="">
      <p class="name">称心如意手摇咖啡磨豆机咖啡豆研磨机 <span class="tag">【赠品】10优惠券</span></p>
      <p class="spec">白色/10寸</p>
      <p class="price">289.90</p>
      <p class="count">x2</p>
      <p class="sub-total">579.80</p>
    </div> -->
  </div>
  <div class="total">
    <div>合计:<span class="amount">1000.00</span></div>
  </div>
  <script>
    const goodsList = [
      {
        id: '4001172',
        name: '称心如意手摇咖啡磨豆机咖啡豆研磨机',
        price: 289.9,
        picture: 'https://yanxuan-item.nosdn.127.net/84a59ff9c58a77032564e61f716846d6.jpg',
        count: 2,
        spec: { color: '白色' }
      },
      {
        id: '4001009',
        name: '竹制干泡茶盘正方形沥水茶台品茶盘',
        price: 109.8,
        picture: 'https://yanxuan-item.nosdn.127.net/2d942d6bc94f1e230763e1a5a3b379e1.png',
        count: 3,
        spec: { size: '40cm*40cm', color: '黑色' }
      },
      {
        id: '4001874',
        name: '古法温酒汝瓷酒具套装白酒杯莲花温酒器',
        price: 488,
        picture: 'https://yanxuan-item.nosdn.127.net/44e51622800e4fceb6bee8e616da85fd.png',
        count: 1,
        spec: { color: '青色', sum: '一大四小' }
      },
      {
        id: '4001649',
        name: '大师监制龙泉青瓷茶叶罐',
        price: 139,
        picture: 'https://yanxuan-item.nosdn.127.net/4356c9fc150753775fe56b465314f1eb.png',
        count: 1,
        spec: { size: '小号', color: '紫色' },
        gift: '50g茶叶,清洗球'
      }
    ]
      const list = document.querySelector('.list')
      // let sum = 0;
      list.innerHTML = goodsList.map(({id,name,price,picture,count,spec,gift})=>{
        // sum += price * count
        
        let giftStr = ''
        //赠品问题 若为空则不显示赠品
        if(gift !== undefined){
          giftStr = gift.split(',').map(item => {
            return `<span class="tag">【赠品】${item}</span>`
          }).join('')
        }else{
          giftStr = ''
        }
        
        return `
        <div class="item" id="${id}">
          <img src="${picture}" alt="">
          <p class="name">${name} 
            ${giftStr}
          </p>
          <p class="spec">${Object.values(spec).join('/')}</p>
          <p class="price">${price.toFixed(2)}</p>
          <p class="count">x${count}</p>
          <p class="sub-total">${(count * price).toFixed(2)}</p>
        </div>
      `
      }).join('')
      const amount = document.querySelector('.amount')
      // amount.innerHTML = sum.toFixed(2)
      //使用reduce方法求和
      const total = goodsList.reduce((prev,item)=> prev + (item.price * item.count *100)/100,0)
      amount.innerHTML = total.toFixed(2)

//处理小数的一种方法(0.1*10 + 0.2*10)/10
  </script>
</body>

</html>