Web APIs——实战案例

图片切换模块及放大镜效果

分析:

  1. 鼠标经过对应小盒子,左侧中等盒子显示对应中等图片
  2. 鼠标经过中盒子,右侧会显示放大镜效果的大盒子
  3. 黑色遮罩盒子跟着鼠标来移动
  4. 鼠标在中等盒子上移动,大盒子的图片跟着显示对应位置
    思路分析:

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

  1. 获取对应的元素

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

  3. 让鼠标经过小图片的爸爸li盒子,添加类,其余的li移除类(注意先移除,后添加)

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

    • 让中等盒子的图片换成这个 这个小图片的src

    • 让大盒子的背景图片,也换成这个小图片的 src (稍后做)

②: 鼠标经过中等盒子,右侧大盒子显示

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

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

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

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

③: 黑色遮罩盒子跟着鼠标来移动

  1. 先做鼠标经过 中等盒子,显示隐藏 黑色遮罩 的盒子

  2. 让黑色遮罩跟着鼠标来走, 需要用到鼠标移动事件 mousemove

  3. 让黑色盒子的移动的核心思想:不断把鼠标在中等盒子内的坐标给黑色遮罩层 let top 值,这样遮罩层就可以跟着移动了

    • 需求

      • 我们要的是 鼠标在 中等盒子内的坐标, 没有办法直接得到

      • 得到1: 鼠标在页面中的坐标

      • 得到2: 中等盒子在页面中的坐标

    • 算法

      • 得到鼠标在页面中的坐标 利用事件对象的 pageX

      • 得到middle中等盒子在页面中的坐标 middle.getBoundingClientRect()

      • 鼠标在middle 盒子里面的坐标 = 鼠标在页面中的坐标 - middle 中等盒子的坐标

      • 黑色遮罩层不断得到 鼠标在middle 盒子中的坐标 就可以移动起来了

      注意 y坐标特殊,需要减去 页面被卷去的头部

      为什么不用 box.offsetLet 和 box.offsetTop 因为这俩属性跟带有定位的父级有关系,很容被父级影响,而getBoundingClientRect() 不受定位的父元素的影响

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

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

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

    • 遮罩盒子移动的坐标:

      • 声明一个 mx 作为移动的距离

      • 水平坐标 x 如果 小于等于100 ,则移动的距离 mx 就是 0 不应该移动

      • 水平坐标 如果 大于等于100 并且小于300,移动的距离就是 mx - 100 (100是遮罩盒子自身宽度的一半)

      • 水平坐标 如果 大于等于300,移动的距离就是 mx 就是200 不应该在移动了

      • 其实我们发现水平移动, 就在 100 ~ 200 之间移动的

      • 垂直同理

javascript 复制代码
        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

大盒子图片移动的计算方法:

  • 中等盒子是 400px 大盒子 是 800px 的图片

  • 中等盒子移动1px, 大盒子就应该移动2px, 只不过是负值

javascript 复制代码
large.style.backgroundPositionX = - 2 * mx + 'px'
large.style.backgroundPositionY = - 2 * my + 'px'
javascript 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>小兔鲜儿 - 新鲜 惠民 快捷!</title>
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="renderer" content="webkit">
  <!-- <link rel="stylesheet" href="//at.alicdn.com/t/font_1939705_bgtmkonu28.css"> -->
  <link rel="stylesheet" href="./css/common.css">
  <link rel="stylesheet" href="./css/product.css">
</head>

<body>
  <!-- 项部导航 -->
  <div class="xtx_topnav">
    <div class="wrapper">
      <!-- 顶部导航 -->
      <ul class="xtx_navs">
        <li>
          <a href="javascript:;">请先登录</a>
        </li>
        <li>
          <a href="javascript:;">免费注册</a>
        </li>
        <li>
          <a href=".javascript:;">我的订单</a>
        </li>
        <li>
          <a href="javascript:;">会员中心</a>
        </li>
        <li>
          <a href="javascript:;">帮助中心</a>
        </li>
        <li>
          <a href="javascript:;">在线客服</a>
        </li>
        <li>
          <a href="javascript:;">
            <i class="mobile sprites"></i>
            手机版
          </a>
        </li>
      </ul>
    </div>
  </div>
  <!-- 头部 -->
  <div class="xtx_header">
    <div class="wrapper">
      <!-- 网站Logo -->
      <h1 class="xtx_logo"><a href="/">小兔鲜儿</a></h1>
      <!-- 主导航 -->
      <div class="xtx_navs">
        <ul class="clearfix">
          <li>
            <a href="javascript:;">首页</a>
          </li>
          <li>
            <a href="javascript:;">生鲜</a>
          </li>
          <li>
            <a href="javascript:;">美食</a>
          </li>
          <li>
            <a href="javascript:;">餐厨</a>
          </li>
          <li>
            <a href="javascript:;">电器</a>
          </li>
          <li>
            <a href="javascript:;">居家</a>
          </li>
          <li>
            <a href="javascript:;">洗护</a>
          </li>
          <li>
            <a href="javascript:;">孕婴</a>
          </li>
          <li>
            <a href="javascript:;">服装</a>
          </li>
        </ul>
      </div>
      <!-- 站内搜索 -->
      <div class="xtx_search clearfix">
        <!-- 购物车 -->
        <a href="javascript:;" class="xtx_search_cart sprites">
          <i>2</i>
        </a>
        <!-- 搜索框 -->
        <div class="xtx_search_wrapper">
          <input type="text" placeholder="搜一搜" onclick="location.href='./search.html'">
        </div>
      </div>
    </div>
  </div>
  <div class="xtx-wrapper">
    <div class="container">
      <!-- 面包屑 -->
      <div class="xtx-bread">
        <a href="javascript:;"> 首页 > </a>
        <a href="javascript:;"> 电子产品 > </a>
        <a href="javascript:;"> 电视 > </a>
        <span>小米电视4A 32英寸</span>
      </div>
      <!-- 商品信息 -->
      <div class="xtx-product-info">
        <div class="left">
          <div class="pictrue">
            <div class="middle">
              <img src="./images/1.jpg" alt="">
              <div class="layer"></div>
            </div>
            <div class="small">
              <ul>
                <li class="active"><img src="./images/1.jpg" alt=""></li>
                <li><img src="./images/2.jpg" alt=""></li>
                <li><img src="./images/3.jpg" alt=""></li>
                <li><img src="./images/4.jpg" alt=""></li>
                <li><img src="./images/5.jpg" alt=""></li>
              </ul>
            </div>
            <div class="large"></div>
          </div>
          <div class="other">
            <ul>
              <li>
                <p>销量人气</p>
                <p>1999+</p>
                <p>销量人气</p>
              </li>
              <li>
                <p>商品评价</p>
                <p>999+</p>
                <p>查看评价</p>
              </li>
              <li>
                <p>收藏人气</p>
                <p>299+</p>
                <p><a href="javascript:;">收藏商品</a></p>
              </li>
              <li>
                <p>品牌信息</p>
                <p>小米</p>
                <p><a href="javascript:;">品牌主页</a></p>
              </li>
            </ul>
          </div>
        </div>
        <div class="right">
          <h3 class="name">小米电视4A 32英寸</h3>
          <p class="desc">全面屏设计 / 高清分辨率 / 海量内容 / 1G+4G大内存 / 多核处理器</p>
          <p class="price"><span class="now">¥1899</span><span class="old">¥2999</span></p>
          <div class="address">
            <div class="item">
              <div class="dt">促销</div>
              <div class="dd">12月好物放送,App领券购买直降120元</div>
            </div>
            <div class="item">
              <div class="dt">配送</div>
              <div class="dd">至
                <div class="box">
                  <span>陕西 西安 <i></i></span>
                </div>
              </div>
            </div>
            <div class="item">
              <div class="dt">服务</div>
              <div class="dd">
                <span class="fw">无忧退货</span>
                <span class="fw">快速退款</span>
                <span class="fw">免费包邮</span>
                <a href="#" class="lj">了解详情</a>
              </div>
            </div>
          </div>
          <div class="attrs">
            <div class="item">
              <div class="dt">颜色</div>
              <div class="dd">
                <img src="./uploads/img/cate-06.png" alt="">
                <img src="./uploads/img/cate-07.png" alt="">
              </div>
            </div>
            <div class="item">
              <div class="dt">颜色</div>
              <div class="dd">
                <span class="size">22英寸</span>
                <span class="size">42英寸</span>
                <span class="size">52英寸</span>
                <span class="size">62英寸</span>
              </div>
            </div>
            <div class="item">
              <div class="dt">数量</div>
              <div class="dd">
                <div class="num">
                  <a href="javascript:;">-</a>
                  <input type="text" value="1">
                  <a href="javascript:;">+</a>
                </div>
              </div>
            </div>
            <div class="item">
              <a class="buy" href="javascript:;">立即购买</a>
            </div>
          </div>
        </div>
      </div>
      <!-- 同类产品推荐 -->
      <div class="xtx-relevant-product">
        <h3>同类产品推荐</h3>
        <ul>
          <li>
            <a href="#">
              <img src="./uploads/history_goods_1.jpg" alt="">
              <p class="name">USB Type C数据线</p>
              <p class="desc">快速充电,稳定传输</p>
              <p class="price">¥39</p>
            </a>
          </li>
          <li>
            <a href="#">
              <img src="./uploads/history_goods_2.jpg" alt="">
              <p class="name">红米Note 5A 高配版</p>
              <p class="desc">1600万像素柔光自拍</p>
              <p class="price">¥1899</p>
            </a>
          </li>
          <li>
            <a href="#">
              <img src="./uploads/history_goods_3.jpg" alt="">
              <p class="name">VGA网口多功能转接器</p>
              <p class="desc">小巧便携,节省桌面空间</p>
              <p class="price">¥19</p>
            </a>
          </li>
          <li>
            <a href="#">
              <img src="./uploads/history_goods_4.jpg" alt="">
              <p class="name">笔记本Pro 15.6"</p>
              <p class="desc">全金属强化机身搭配独显</p>
              <p class="price">¥4899</p>
            </a>
          </li>
        </ul>
        <a href="javascript:;" class="prev"><span class="iconfont icon-angle-left"></span></a>
        <a href="javascript:;" class="next"><span class="iconfont icon-angle-right"></span></a>
      </div>
      <!-- 商品详情 -->
      <div class="xtx-product-detail">
        <div class="main">
          <div class="cont">
            <div class="tab-head">
              <a href="javascript:;">商品详情</a>
              <a href="javascript:;">商品评价<span>(998+)</span></a>
            </div>
            <div class="tab-pane">
              <!-- 静态属性 -->
              <div class="attrs">
                <div class="item"><span>商品名称:</span><span>小米L32M5-AZ </span></div>
                <div class="item"><span>商品编号:</span><span>4620979 </span></div>
                <div class="item"><span>商品毛重:</span><span>8.0kg </span></div>
                <div class="item"><span>商品产地:</span><span>中国大陆 </span></div>
                <div class="item"><span>屏幕尺寸:</span><span>32英寸及以下 </span></div>
                <div class="item"><span>能效等级:</span><span>三级能效 </span></div>
                <div class="item"><span>电视类型:</span><span>人工智能 </span></div>
                <div class="item"><span>选购指数:</span><span>6.9-6.0 </span></div>
                <div class="item"><span>观看距离:</span><span>2m以下(≤32英寸)</span></div>
              </div>
              <!-- 详情内容 -->
              <div class="detail">
                <img src="https://yanxuan-item.nosdn.127.net/39d7f2407c90d0442566a719146ee9c1.jpg" alt=""
                  data-v-2c43c764=""><img src="https://yanxuan-item.nosdn.127.net/7dfee58e7c6b3996badf368610ed62b1.jpg"
                  alt="" data-v-2c43c764=""><img
                  src="https://yanxuan-item.nosdn.127.net/d1acff1a29bddd21c2ad337d892a9f7c.jpg" alt=""
                  data-v-2c43c764=""><img src="https://yanxuan-item.nosdn.127.net/ac722b04b2014ac337d8db695ee46f0c.jpg"
                  alt="" data-v-2c43c764=""><img
                  src="https://yanxuan-item.nosdn.127.net/c63e36faa0848ee37c825897f5cec179.jpg" alt=""
                  data-v-2c43c764=""><img src="https://yanxuan-item.nosdn.127.net/e0f13dbf14c8a2f07e86bf3df3ca002b.jpg"
                  alt="" data-v-2c43c764="">
              </div>
            </div>
            <div class="tab-pane" style="display: none;">评价</div>
          </div>
          <!-- 注意事项 -->
          <div class="warn">
            <h3>注意事项</h3>
            <p class="tit">• 购买运费如何收取? </p>
            <p>单笔订单金额(不含运费)满88元免邮费;不满88元,每单收取10元运费。(港澳台地区需满500元免邮费;不满500元,每单收取30元运费) </p>
            <br>
            <br>
            <p class="tit">• 使用什么快递发货? </p>
            <p>默认使用顺丰快递发货(个别商品使用其他快递) </p>
            <p>配送范围覆盖全国大部分地区(港澳台地区除外)。 </p>
            <br>
            <br>
            <p class="tit">• 如何申请退货? </p>
            <p>1.自收到商品之日起30日内,顾客可申请无忧退货,退款将原路返还,不同的银行处理时间不同,预计1-5个工作日到账; </p>
            <p>2.内裤和食品等特殊商品无质量问题不支持退货; </p>
            <p>3.退货流程: 确认收货-申请退货-客服审核通过-用户寄回商品-仓库签收验货-退款审核-退款完成; </p>
            <p>4.因小兔鲜儿产生的退货,如质量问题,退货邮费由小兔鲜儿承担,退款完成后会以现金券的形式报销。因客户个人原因产生的退货,购买和寄回运费由客户个人承担。</p>
          </div>
        </div>
        <div class="aside">
          <div class="tit">24小时热销榜</div>
          <div class="product">
            <img src="./uploads/fresh_goods_3.jpg" alt="">
            <p class="name">USB Type C数据线</p>
            <p class="desc">快速充电,稳定传输</p>
            <p class="price">¥29</p>
          </div>
          <div class="product">
            <img src="./uploads/fresh_goods_3.jpg" alt="">
            <p class="name">USB Type C数据线</p>
            <p class="desc">快速充电,稳定传输</p>
            <p class="price">¥29</p>
          </div>
          <div class="product">
            <img src="./uploads/fresh_goods_3.jpg" alt="">
            <p class="name">USB Type C数据线</p>
            <p class="desc">快速充电,稳定传输</p>
            <p class="price">¥29</p>
          </div>
          <div class="tit">专题推荐</div>
          <div class="special">
            <img src="./uploads/discuss_goods_1.jpg" alt="">
            <p class="name">一往无前,诞生于崛起</p>
          </div>
          <div class="special">
            <img src="./uploads/discuss_goods_1.jpg" alt="">
            <p class="name">一往无前,诞生于崛起</p>
          </div>
          <div class="special">
            <img src="./uploads/discuss_goods_1.jpg" alt="">
            <p class="name">一往无前,诞生于崛起</p>
          </div>
        </div>
      </div>
    </div>
  </div>
  <!-- 公共底部 -->
  <div class="xtx_footer clearfix">
    <div class="wrapper">
      <!-- 联系我们 -->
      <div class="contact clearfix">
        <dl>
          <dt>客户服务</dt>
          <dd class="chat">在线客服</dd>
          <dd class="feedback">问题反馈</dd>
        </dl>
        <dl>
          <dt>关注我们</dt>
          <dd class="weixin">公众号</dd>
          <dd class="weibo">微博</dd>
        </dl>
        <dl>
          <dt>下载APP</dt>
          <dd class="qrcode">
            <img src="./uploads/qrcode.jpg">
          </dd>
          <dd class="download">
            <span>扫描二维码</span>
            <span>立马下载APP</span>
            <a href="javascript:;">下载页面</a>
          </dd>
        </dl>
        <dl>
          <dt>服务热线</dt>
          <dd class="hotline">
            400-0000-000
            <small>周一至周日 8:00-18:00</small>
          </dd>
        </dl>
      </div>
    </div>
    <!-- 其它 -->
    <div class="extra">
      <div class="wrapper">
        <!-- 口号 -->
        <div class="slogan">
          <a href="javascript:;" class="price">价格亲民</a>
          <a href="javascript:;" class="express">物流快捷</a>
          <a href="javascript:;" class="quality">品质新鲜</a>
        </div>
        <!-- 版权信息 -->
        <div class="copyright">
          <p>
            <a href="javascript:;">关于我们</a>
            <a href="javascript:;">帮助中心</a>
            <a href="javascript:;">售后服务</a>
            <a href="javascript:;">配送与验收</a>
            <a href="javascript:;">商务合作</a>
            <a href="javascript:;">搜索推荐</a>
            <a href="javascript:;">友情链接</a>
          </p>
          <p>CopyRight &copy; 小兔鲜儿</p>
        </div>
      </div>
    </div>
  </div>
  <script>
    // 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})`
      }
    })


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


    // 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'
      }
    })
  </script>
</body>

</html>
相关推荐
2分钟速写快排16 分钟前
什么是 RAG?如何用 RAG 实现一个用户记忆?
前端·后端·ai编程
passerby60611 小时前
如何自己造一个时间处理库
前端·javascript·github
走到天涯海角2 小时前
react里面的长列表渲染优化
前端·react.js·前端框架
小羊没烦恼!2 小时前
Hello Web API系列教程——Web API与国际化
java·服务器·前端·javascript·php
北岛贰2 小时前
迷茫焦虑期,我做了一个带支付带官网的 AI 聊天虚拟恋人 App
前端·人工智能·后端
mayaairi4 小时前
Vue2 组件通讯(三):全局事件总线、PubSub、插槽与组件实例属性
前端·javascript·vue.js
kyriewen4 小时前
面试官问我:AI 都能写代码了,前端凭什么还值 25K
前端·javascript·人工智能
风骏时光牛马5 小时前
AI源码分析:拆解模型底层实现逻辑
前端
BillKu5 小时前
全局样式变量:CSS 自定义属性(--border-color)和SCSS 变量($border-color)的说明
javascript·css·scss
IT_陈寒5 小时前
React子组件莫名其妙重渲染?你可能漏了这个Hook
前端·人工智能·后端