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>
相关推荐
Myli_ing9 分钟前
考研倒计时-配色+1
前端·javascript·考研
余道各努力,千里自同风12 分钟前
前端 vue 如何区分开发环境
前端·javascript·vue.js
PandaCave19 分钟前
vue工程运行、构建、引用环境参数学习记录
javascript·vue.js·学习
软件小伟21 分钟前
Vue3+element-plus 实现中英文切换(Vue-i18n组件的使用)
前端·javascript·vue.js
醉の虾42 分钟前
Vue3 使用v-for 渲染列表数据后更新
前端·javascript·vue.js
张小小大智慧1 小时前
TypeScript 的发展与基本语法
前端·javascript·typescript
hummhumm1 小时前
第 22 章 - Go语言 测试与基准测试
java·大数据·开发语言·前端·python·golang·log4j
asleep7011 小时前
第8章利用CSS制作导航菜单
前端·css
hummhumm1 小时前
第 28 章 - Go语言 Web 开发入门
java·开发语言·前端·python·sql·golang·前端框架
幼儿园的小霸王2 小时前
通过socket设置版本更新提示
前端·vue.js·webpack·typescript·前端框架·anti-design-vue