微科技 2017-01-15 15:07

在京东和淘宝等购买东西的时候,我们会经常预览左侧商品展示图片,把鼠标放到原图,右侧就会有个大图显示出细节。本文将带领大家写一个这样简单的功能!

一、实现原理

当鼠标移入某一图片内部时,图片上部会出现一个类似于扫描的框,这个框内的图片部分,会以方大形式展示在右边,如下图:

从图中可以推测出一下几点:

图片img上层会有一个父元素(如‘div’),在鼠标移入时,父元素内部添加一个子元素代表扫描框,并且整个body会出现一个固定定位的图片预览盒子定位在右侧(这个图片是另外一张准备好的大图),展示着扫描框中扫描到的图片位置,这个扫描框不能在div内部移动,当鼠标移出图片,扫描框和展示台都消失。

因此我们得到以下布局

<!--整个盒子-->
<div><!--图片--><img src="..."><!--扫描框--><div class="sweep"></div>
</div><!--扫描展示区域-->
<div class="show">
</div>    

实际情况下,我们不会手动写上 .sweep 和 .show这两个空div,他是由js来实现的。因此,今天我们练习的布局代码如下

<div><img src="..." />
</div>

二、准备工作

今天,博主准备了两个练习图片,一个 200*200用作原图, 一个400*400用作大图展示。

html:

<div id="box" data-big-img="goods-big.gif"><img src="goods.gif" alt="咖啡" />
</div>
#box {border: 2px solid #000;width: 200px;height: 200px;margin: 0 auto;
}

我们紧紧需要设置图片盒子的样式就可以了,注意: 图片盒子需要把宽高设定为图片大小200*200。

js函数参数选定:

// 将函数命名为zoom,接收两个参数,
// 第一个参数是原图的盒子#box, 第二个是对大图展示台的设定function zoom (elem, options) {...}//  记住,一切与图片打交道的,都放在window.onload内
window.onload = function  {var box = document.querySelector('#box')// 这里我们把展示台设置为图片大小zoom(box, {offsetWidth: 200,  // 展示台宽度offsetHeight: 200,  // 展示台高度offsetX: 10, // 展示台相对图片盒子的横向偏移offsetY: 0 // 展示台相对图片盒子的纵向偏移})
}

对各个元素尺寸的解释:

原图200* 200, 大图预览是原图的2倍。

扫描框100*100, 是原图的1/2

展示台与原图大小相同,展示台中显示图片为400*400的大图做背景图,控制其背景图的位置来改变展示图的图样。

三、逻辑分析

1. 执行zoom函数,我们需要获取到扫描框和展示台,如果没有,就创建。

2. 给图片添加一个onmouseenter事件,在鼠标移入图片,触发函数,显示展示台和扫描框,并且展示台的图片内容就是扫描框扫描到的图片区域的放大部分。

3. 鼠标移出,展示台和扫描框消失。

4. 鼠标在图片上移动,我们在这里给扫描框添加onmousemove事件,鼠标位置始终在扫描框的中心位置(扫描框紧贴图片一侧除外),只有在鼠标移出了图片区域,鼠标才会离开扫描框。

5. 展示台的图片随着扫描框的移动而变化到相应的部分。

四、编写代码

开始代码如下:

window.onload = function  {var box = document.getElementById('box')zoom(box, {offsetWidth: 300,offsetHeight: 300,offsetX: 10,offsetY: 0})}function zoom (elem, options) {// ..
}

之后的代码都会在zoom函数内部。

首先,我们想一下,扫描框.sweep应该在#box内部,其移动是如何实现的,答案是定位,因此#box需要设定为相对定位给.sweep提供环境

// 将盒子设定为相对定位,供之后内部的扫描框用
elem.style.position = 'relative'

由于扫描框的宽高依据图片所定,所以我们先拿到图片的宽高

var innerImg = elem.querySelector('img'),
width = innerImg.offsetWidth,
height = innerImg.offsetHeight

我们需要获取.sweep (扫描框)和 .show(展示台) 两个dom元素

var showBox  = getShowBox  // 获取展示台盒子
var sweepBox = getSweepBox  // 获取扫描框盒子

由于我们在html没有手动添加两个元素,我们需要先创建他,getShowBox如下:

function getShowBox  {var showBox = document.querySelector('.xu-show-box')if (!showBox) {showBox = document.createElement('div')showBox.className = 'xu-show-box'// 糟糕的样式添加操作showBox.style.width = (options.offsetWidth || 400) + 'px'showBox.style.height = (options.offsetHeight || 400) + 'px'showBox.style.position = 'fixed'showBox.style.left = elem.offsetLeft + elem.offsetWidth + (options.offsetX || 10) + 'px'showBox.style.top = elem.offsetTop + (options.offsetY || 0) + 'px'showBox.style.background = 'url(' + elem.getAttribute('data-big-img') + ')'showBox.style.display = 'none'document.body.appendChild(showBox)}return showBox
}

我们先获取到展示台元素,如果没有创建,然后定义了一大串css,然后将它加入到body中,我们可以看到一大串的showBox.style很糟糕,我们需要一个css样式修改函数。

function setStyle(elem, props, value) {if (typeof props === 'object') {//  传入的对象for (var key in props) {elem.style[key] = props[key]}} else {elem.style[props] = value}
}

我们接下来用setStyle来设定样式,代码变成了如下:

function getShowBox  {var showBox = document.querySelector('.xu-show-box')if (!showBox) {showBox = document.createElement('div')showBox.className = 'xu-show-box'setStyle(showBox, {width: (options.offsetWidth || 400) + 'px',height: (options.offsetHeight || 400) + 'px',position: 'fixed',left: elem.offsetLeft + elem.offsetWidth + (options.offsetX || 10) + 'px',top: elem.offsetTop + (options.offsetY || 0) + 'px',background: 'url(' + elem.getAttribute('data-big-img') + ')',display: 'none'})document.body.appendChild(showBox)}return showBox
}

看起来好多了,我们再获取sweep

function getSweepBox  {var sweepBox = elem.querySelector('.xu-sweep-box')if (!sweepBox) {showBox = document.createElement('div')showBox.className = 'xu-sweep-box'setStyle(sweepBox, {border: '1px solid #44f',width: width / 2 - 2+ 'px',height: height / 2 - 2 + 'px',background: '#ff0',opacity: '.4',position: 'absolute',display: 'none',cursor: 'move'})elem.appendChild(sweepBox)}return sweepBox}

目前我们的已经获取到了展示台和扫描框,目前的代码如下:

window.onload = function  {var box = document.getElementById('box')zoom(box, {offsetWidth: 300,offsetHeight: 300,offsetX: 10,offsetY: 0})}function zoom (elem, options) {elem.style.position = 'relative'

var innerImg = elem.querySelector('img'),

width = innerImg.offsetWidth,

height = innerImg.offsetHeight

var showBox = getShowBox var sweepBox = getSweepBox getShowBox{...} getSweepBox {...} setStyle{...} }

接下来,我们开始书写鼠标事件的逻辑,在这之前,我们想一下我们的需求,以及元素尺寸的概念:

因为扫描框大小是图片大小的一半,因此扫描框定位取值:

left: 0 到 图片宽度的一半(也就是扫描框的宽度)

top: 0 到 图片高度的一半(也就是扫描框的高度)

鼠标移入图片的位置不同,决定扫描框的出现位置:

从左上角移入:左上角

从左下角移入: 左下角

从右上角移入: 右上角

从右下角移入: 右下角

移入的样子如下:

扫描框的运动是否允许,需要对鼠标位置的判断,拿左上角移入举例:如果鼠标移动到扫描框的中心位置并继续向右移动,此时扫描框才会移动,如果鼠一直在扫描框的左上部分移动,扫描框是不会移动的。

接下来我们需要获取如下数据:

扫描框宽高度,扫描框移动的度量宽高度

//  扫描框宽高
var sweepW = width / 2,
sweepH = height / 2,
//  扫描框移动的度量宽高
stepW = sweepW / 2,
stepH = sweepH / 2

此时,我们做好了鼠标移入的准备工作,我们可以开始编写移入事件函数了

elem.onmouseenter = function (ev) {//  根据鼠标的位置,加载扫描框和展示台load(ev.offsetX, ev.offsetY)
}

load函数如下:

function load (x, y) {// 扫描框的横纵坐标偏移量var offsetX = offsetY = 0// 不知用什么switch表达式好,所以用了如下方法来判断位置,你有没有好方法? switch ([(x-sweepW) > 0, (y-sweepH) > 0].join(',')) {case 'false,true'://  左下offsetY = sweepHbreak;case 'false,false':// 左上break;case 'true,false'://  右上offsetX = sweepWbreak;case 'true,true'://  右下offsetX = sweepWoffsetY = sweepHbreak;}setStyle(sweepBox, {left: offsetX + 'px',top: offsetY + 'px',display: 'block'})
//  由于我们起初设定的展示图是原图的2倍,所以偏移都*2setStyle(showBox, {backgroundPositionX: offsetX * 2 + 'px',backgroundPositionY: offsetY * 2 + 'px',display: 'block'})}

加载完毕后,再写鼠标移动事件,根据我们的需求,我们需要根据不同方位,不同鼠标坐标,来判断扫描框是否可运动,我们通过需求分析,我们选择的给扫描框加的鼠标移动事件,如下

sweepBox.onmousemove = function (e) {if (!isMove(e)) {return}// 鼠标移动的距离var moveX = e.offsetX - stepWvar moveY = e.offsetY - stepH// 扫描框的偏移量var offsetL = this.offsetLeftvar offsetT = this.offsetTop// 计算出移动的最终坐标var toX, toY// 沿x轴往右移动,并且扫描框右边界还没有碰到图片右边缘,那么可以移动,并且移动的距离最远到图片右边缘if (moveX > 0 && offsetL < sweepW) {toX = Math.min(offsetL + moveX, sweepW) }// 与之相反,沿x轴往左移动,那么判断左边界未碰到图片左边缘,移动并且移动最左只能到0if (moveX < 0 && offsetL > 0) {toX = Math.max(offsetL + moveX , 0)}// y轴雷同if(moveY > 0 && offsetT < sweepH) {toY = Math.min(offsetT + moveY, sweepH) }if (moveY < 0 && offsetT > 0) {toY = Math.max(offsetT + moveY, 0)}// 每次移动,分别设置扫描框和展示台的相应数据setStyle(this, {left: toX + 'px',top: toY + 'px'})setStyle(showBox, {backgroundPositionX: -toX * 2 + 'px',backgroundPositionY: -toY * 2 + 'px'})}

我们用了isMove函数来判断扫描框是否有权移动,函数如下:

function isMove (e) {var offsetX = e.offsetX,offsetY = e.offsetY,offsetLeft = sweepBox.offsetLeft,offsetTop = sweepBox.offsetTop//左上角时,并且鼠标移动的位置小于度量值时,不能移动if (!offsetLeft && !offsetTop) {//  左上if (offsetX < stepW  && offsetY < stepH ) {return false}}// 右上角时,鼠标移动位置x轴方向大于度量值,y轴方向小于度量值,也就是偏右上角,不能移动if (offsetLeft === sweepW && !offsetTop) {//  右上if (offsetY < stepH && offsetX > stepW) {return false}}// 雷同,鼠标移动偏右下角,不能移动if (offsetLeft === sweepW && offsetTop === sweepH) {//  右下if (offsetX > stepW && offsetY > stepH) {return false}}// 雷同,鼠标移动偏左下角,不能移动if(!offsetLeft && offsetTop === sweepH) {//  左下if (offsetX < stepW && offsetY > stepH) {return false}}// 以上条件都不符合,可以移动  return true;}

鼠标移出时,我们需要注销掉这两个事件监听

elem.onmouseleave = function  {sweepBox.onmousemove = nullelem.onmouseleave = nullunload   // 隐藏展示台和扫描框
}

unload很简单,如下

function unload  {showBox.style.display = sweepBox.style.display = 'none'
}

到此整个代码完成,实现了2倍关系的图像方大查看函数,并没有提供多的自定义设置,你可以自己修改一下,提供更多的自定义数据来提供更强大的功能。

结尾

本菜只能写到这样了,语言组织能力差,所以你可能没看懂,不过没关系,静下心来默默的想一下,你可能就会写这个功能了,而且一定比博主写的好~~~。

javascript实现 京东淘宝等商城的商品图片大图预览功能相关推荐

  1. javascript显示本地服务器图片,JavaScript图片本地预览功能的实现方法

    这篇文章主要介绍了JavaScript实现图片本地预览功能,针对非IE浏览器的HTML5滤镜功能及IE浏览器的相关组件功能实现不上传至服务器预览本地图片的效果,需要的朋友可以参考下 本文实例讲述了Ja ...

  2. Java毕设 仿京东淘宝 多用户商城平台 毕业设计源码 使用教程(2)店铺功能

  3. 一键自动完成 2021 京东/淘宝双 11 活动

    苏生不惑第295篇原创文章,将本公众号设为星标,第一时间看最新文章. 之前分享过免费使用腾讯云每天定时签到京东领取京豆网易云音乐等级快速升级:每天自动打卡听歌300首签到 获取脚本,再安装nodejs ...

  4. 安卓APP源码和设计报告——仿淘宝水果商城

    项目名称 仿淘宝水果商城 项目概述 随着互联网技术地高速发展,计算机进入到每一个人的生活里,从人们的生活方式到整个社会的运转都产生了巨大的变革,而在信息技术发达的今天,互联网的各种娱乐方式都在渗透到人 ...

  5. java B2B2C 仿淘宝电子商城系统-Spring Cloud Feign的文件上传实现

    在Spring Cloud封装的Feign中并不直接支持传文件,但可以通过引入Feign的扩展包来实现,本文就来具体说说如何实现.需要JAVA Spring Cloud大型企业分布式微服务云构建的B2 ...

  6. java B2B2C Springboot仿淘宝电子商城系统-负载均衡之ribbon+feign

    一. feign简介 Feign是一个声明式的伪Http客户端,它使得写Http客户端变得更简单.使用Feign,只需要创建一个接口并注解.它具有可插拔的注解特性,可使用Feign注解和JAX-RS注 ...

  7. 【任务脚本】1104更新双十一京东淘宝任务脚本,全自动程序,淘宝京东自动做任务...

       公众号关注 "DLGG创客DIY" 设为"星标",重磅干货,第一时间送达.     今天试了一下大神的脚本,将相关的注意事项发一下.     删掉了之前的 ...

  8. java B2B2C 仿淘宝电子商城系统-Spring Cloud Eureka参数配置项详解

    Eureka涉及到的参数配置项数量众多,它的很多功能都是通过参数配置来实现的,了解这些参数的含义有助于我们更好的应用Eureka的各种功能,下面对Eureka的配置项做具体介绍,供大家参考. 需要JA ...

  9. java B2B2C Springcloud仿淘宝电子商城系统-spring cloud 框架原理

    我们从整体来看一下Spring Cloud主要的组件,以及它的访问流程 需要JAVA Spring Cloud大型企业分布式微服务云构建的B2B2C电子商务平台源码 一零三八七七四六二六 1.外部或者 ...

最新文章

  1. KMP算法求回溯数组的步骤
  2. 计算机书籍-大型网站性能优化实战
  3. jupyter 安装目录Table of Contents
  4. Python编程基础:第三十七节 石头剪刀布游戏Rock, Paper, Scissors Game
  5. php钩子是啥意思,php中的钩子理解及应用实例分析
  6. Linux网络协议栈(四)——链路层(2)
  7. JavaScript中关键字和保留字有哪些
  8. pcie总线连接两台电脑_PCIe总线学习笔记(一、PCI基础知识简介)(转载)
  9. 小白 Linux 云计算怎么学,都要学什么?---超详细---
  10. 添加打印机计算机无法访问,Win7系统添加打印机提示Windows无法打开“添加打印机”的解决方法...
  11. SQL数据库-第一次试验-表与视图的基本操作
  12. 华三防火墙配置端口地址转换_华三防火墙双向nat配置 防火墙端口映射
  13. latex参考文献居中_latex参考文献常见问题
  14. FuntouchOS跟鸿蒙系统,FuntouchOS10.5安装包
  15. Chrome浏览器的自带翻译用途
  16. 情人节翻译软件测试,TechPowerUp
  17. 使用 Clipper 库的一些问题记录
  18. vc实现魔兽3改键程序
  19. ionic3开发系列——实现对手机软件键盘按键的监听
  20. 如何在Edit中切换为默认输入法

热门文章

  1. MacBook Air M1 macOS配置快捷键入门指南
  2. python中实例和对象的区别,python类对象和实例对象有什么区别吗
  3. LeetCode 热题 HOT 100【题型归类汇总,助力刷题】
  4. jboss as 6 pojo cache配置使用
  5. α版本升升备忘录下载链接
  6. python elasticsearch.exceptions.ConnectionError: ConnectionError(check_hostname requires server_host
  7. TSN -促进IT/OT 融合的网络技术
  8. vue-cli网页聊天室:当聊天室有新消息时,控制滚动条滚动到底部
  9. python搜索算法_搜索算法(Python)
  10. 直流有刷电机开环调速基于STM32F302R8+X-NUCLEO-IHM07M1(一)