js 实现淘宝放大镜功能,可更改配置参数 带完整版解析代码[magnifier.js]
前言:
本人纯小白一个,有很多地方理解的没有各位大牛那么透彻,如有错误,请各位大牛指出斧正!小弟感激不尽。
本篇文章为您分析一下原生JS写淘宝放大镜效果
基本功能:
运用比例来控制移动放大镜从而选择需要放大的区域。
可以根据用户配置来调整放大镜尺寸。
需求分析:
准备两张图片一张小图,一张大图(比例请参考京东或者淘宝页面上的放大镜;本文采用的是350px和800px的)
HTML结构:
<div class="small"> <!--小图-->
<div class="move" style="height: 150px; width:150px"></div><!--可以移动的区域-->
</div>
<div class="big"></div><!--要显示的大图-->
<div class="move" style="height: 150px; width:150px"></div>
<div class="move" style="height: 150px; width:150px"></div>
此处的内联样式在后面是需要用js生成,暂时为了看到效果写在这儿了
CSS样式:
<div class="small">
<div class="move"></div>
</div>
<div class="big"></div>
效果如下:

至此,页面基本结构已经完成,下面开始写JS
JS行为:
由于此处的JS变量不需要供外部使用所以我们直接用一个立即执行函数来完成。
首先要想到的,放大镜需要用到什么配置(即用户需要更改那些参数才能使用)
- 小图的url,大图的url
- 小图和大图要渲染到哪个元素上?
- 配置小图的宽高
- 配置大的div宽高
- 配置大图的宽高
/**
* 第一步: 配置(此处配置均可更改)
*/
var config = {
smallBg: "images/mouse.jpg", // 小图背景路径
bigBg: "images/mouseBigSize.jpg", // 大图背景路径
divBig: document.querySelector(".big"), // 大图div dom元素
divSmall: document.querySelector(".small"), // 小图div dom元素
divMove: document.querySelector(".small .move"), // 可移动的div元素
smallImgSize: { // 小图尺寸
width: 400,
height: 400
},
divBigSize: { // 大的div尺寸
width: 400,
height: 400
},
bigImgSize: { // 大图尺寸
width: 800,
height: 800
}
};

initDivBg(); // 调用函数
/**
* 第二步: 初始化div背景
*/
function initDivBg() {
// 设置小div的背景 使用es6的模板字符串拼接
config.divSmall.style.background = `url("${config.smallBg}") no-repeat left top/100% 100%`;
// 设置大div的初始背景 使用es6的模板字符串拼接
config.divBig.style.background = `url("${config.bigBg}") no-repeat`;
}


因为他的尺寸是可以根据用户更改参数而动态改变的,那他的div宽高要怎么算呢?懵逼了。。。下面来看张分析图

// 第三步: 计算可移动的div的宽高
config.moveSize = {
width: config.divBigSize.width / config.bigImgSize.width * config.smallImgSize.width,
height: config.divBigSize.height / config.bigImgSize.height * config.smallImgSize.height
}
有了宽高,还等啥呢?直接设置就完儿了。
function initMoveDiv() {
config.divMove.style.width = config.moveSize.width + "px";
config.divMove.style.height = config.moveSize.height + "px";
}

一开始大图div是看不见的,display为none,可移动div也是看不见的,display也为none自行设置吧。

那么为谁注册事件呢?(假装看不见-----------小的div)如下:
/**
* 第四步:初始化小的div事件
*/
function initDivSmallEvent() {
// 鼠标移入事件
config.divSmall.onmouseenter = function () {
config.divMove.style.display = "block"; // 可移动div显示
config.divBig.style.display = "block"; // 大的div显示
}
// 鼠标移出事件
config.divSmall.onmouseleave = function () {
config.divMove.style.display = "none"; // 可移动div隐藏
config.divBig.style.display = "none"; // 大的div隐藏
}
}
图有了,框有了,可是他还不会动呢,要可以蹦沙卡拉卡那就完美了。揍~你。下面让他摇摆一下。
但是这怎么摇和怎么摆他可有思绪?
再为他添加一个移动事件就成。
// 鼠标移动事件
config.divSmall.onmousemove = function (e) {
// 把事件e传入getOffset函数中获取鼠标移动的距离。
var offset = getOffset(e);
console.log(offset);
}
/**
* 第五步: 根据鼠标事件参数,得到鼠标在divsmall中的坐标
* @param {MouseEvent} e
*/
function getOffset(e) {
console.log(e.offsetX)
// 如果事件源是config.divSmall
if (e.target === config.divSmall) {
// 直接返回
return {
x: e.offsetX,
y: e.offsetY
}
} else {
// 事件源是divMove,我们就要添加上他的left值,left怎么获的
var style = getComputedStyle(config.divMove); // 得到divMove最终样式
var left = parseFloat(style.left); // 取到他的left值 为啥要用parseFloat因为我们要的是Number,不是string,不用你试着打印出来是带px的。
var top = parseFloat(style.top); // 取到他的top值
return {
// 这里的加1是border的宽度,可以加可以不加。精确写。
x: e.offsetX + left + 1, // 返回时加上left值
y: e.offsetY + top + 1 // 返回时加上top值
}
}
}
可能到这儿您有些么么哒。没关系,请往下看看分析图

两张图够了吧,不够也没了。


下面就是让这个该死的div动起来,EV8D。
让他随鼠标的移动而改变可移动div的left,top值。
上代码;
config.divSmall.onmousemove = function (e) {
var offset = getOffset(e);
setPosition(offset); // 调用函数
}
/**
* 第六步: 根据鼠标坐标,设置divMove的坐标
* @param {*} offset
*/
function setPosition(offset) {
// 设置可移动div的left值; config.moveSize.width / 2; 可移动div的一半,为啥这样做。让你的十字架始终在可以移动div的中间(瞄的比较准)
var left = offset.x - config.moveSize.width / 2;
// 设置可移动div的top值
var top = offset.y - config.moveSize.width / 2;
// 判断边界
if (left < 0) {
left = 0;
}
if (top < 0) {
top = 0;
}
if (left > config.smallImgSize.width - config.moveSize.width) {
left = config.smallImgSize.width - config.moveSize.width
}
if (top > config.smallImgSize.height - config.moveSize.height) {
top = config.smallImgSize.height - config.moveSize.height
}
// 重新设置可移动div的left和top值
config.divMove.style.left = left + "px";
config.divMove.style.top = top + "px";
}

熬出头了???
设置大图的的背景图位置?
但是要如何设置呢?同样的需要计算比例
先分析一下:看下图

看明白了上代码:
config.divSmall.onmousemove = function (e) {
var offset = getOffset(e);
setPosition(offset);
setBigBgPosition(); //调用函数
}
/**
* 最后一步: 设置大图背景图位置
*/
function setBigBgPosition() {
var style = getComputedStyle(config.divMove); // 得到divMove最终样式
var left = parseFloat(style.left); // 取到他的left值
var top = parseFloat(style.top); // 取到他的top值
var bgLeft = left / config.smallImgSize.width * config.bigImgSize.width; // 看分析图
var bgTop = top / config.smallImgSize.height * config.bigImgSize.height; // 看分析图
config.divBig.style.backgroundPosition = `-${bgLeft}px -${bgTop}px`; // 设置背景图。
}
让我们看看完整的效果。
!
HTML部分:
<div class="small">
<div class="move"></div>
</div>
<div class="big"></div>
<script src="./index.js"></script>
CSS部分:
.small {
position: relative;
width: 350px;
height: 350px;
border: 1px solid #cccccc;
float: left;
background-clip: padding-box;
}
.big{
display: none;
width: 350px;
height: 350px;
border: 1px solid #cccccc;
float: left;
margin-left: 10px;
background-clip: padding-box;
}
.small .move{
display: none;
position: absolute;
left: 0;
top: 0;
background: rgba(255, 255, 0, .2);
border: 1px solid #cccccc;
box-sizing: border-box;
cursor: move;
}
JS部分:
/**
* 初始化
*/
(function () {
/**
* 第一步: 配置
*/
var config = {
smallBg: "images/mouse.jpg", // 小图背景路径
bigBg: "images/mouseBigSize.jpg", // 大图背景路径
divBig: document.querySelector(".big"), // 大图div dom元素
divSmall: document.querySelector(".small"), // 小图div dom元素
divMove: document.querySelector(".small .move"), // 可移动的div元素
smallImgSize: { // 小图尺寸
width: 350,
height: 350
},
divBigSize: { // 大的div尺寸
width: 350,
height: 350
},
bigImgSize: { // 大图尺寸
width: 800,
height: 800
}
};
// 第二步: 计算可移动的div的宽高
config.moveSize = {
width: config.divBigSize.width / config.bigImgSize.width * config.smallImgSize.width,
height: config.divBigSize.height / config.bigImgSize.height * config.smallImgSize.height
}
console.log(config)
initDivBg();
initMoveDiv();
initDivSmallEvent();
/**
* 初始化div背景
*/
function initDivBg() {
config.divSmall.style.background = `url("${config.smallBg}") no-repeat left top/100% 100%`;
config.divBig.style.background = `url("${config.bigBg}") no-repeat`;
}
/**
* 第三步: 初始化可移动的div
*/
function initMoveDiv() {
config.divMove.style.width = config.moveSize.width + "px";
config.divMove.style.height = config.moveSize.height + "px";
}
/**
* 初始化小图div的鼠标事件
*/
function initDivSmallEvent() {
config.divSmall.onmouseenter = function () {
config.divMove.style.display = "block";
config.divBig.style.display = "block";
}
config.divSmall.onmouseleave = function () {
config.divMove.style.display = "none";
config.divBig.style.display = "none";
}
config.divSmall.onmousemove = function (e) {
var offset = getOffset(e);
setPosition(offset);
setBigBgPosition();
}
/**
* 最后一步: 设置大图背景图位置
*/
function setBigBgPosition() {
var style = getComputedStyle(config.divMove);
var left = parseFloat(style.left);
console.log(left)
var top = parseFloat(style.top);
var bgLeft = left / config.smallImgSize.width * config.bigImgSize.width;
var bgTop = top / config.smallImgSize.height * config.bigImgSize.height;
config.divBig.style.backgroundPosition = `-${bgLeft}px -${bgTop}px`;
console.log(bgLeft)
}
/**
* 第六步: 根据鼠标坐标,设置divMove的坐标
* @param {*} offset
*/
function setPosition(offset) {
// 设置可移动div的left值; config.moveSize.width / 2; 可移动div的一半,为啥这样做。让你的十字架始终在可以移动div的中间(瞄的比较准)
var left = offset.x - config.moveSize.width / 2;
// 设置可移动div的top值
var top = offset.y - config.moveSize.width / 2;
// 判断边界
if (left < 0) {
left = 0;
}
if (top < 0) {
top = 0;
}
if (left > config.smallImgSize.width - config.moveSize.width) {
left = config.smallImgSize.width - config.moveSize.width
}
if (top > config.smallImgSize.height - config.moveSize.height) {
top = config.smallImgSize.height - config.moveSize.height
}
// 重新设置可移动div的left和top值
config.divMove.style.left = left + "px";
config.divMove.style.top = top + "px";
}
/**
* 根据鼠标事件参数,得到鼠标在divsmall中的坐标
* @param {MouseEvent} e
*/
function getOffset(e) {
if (e.target === config.divSmall) {
return {
x: e.offsetX,
y: e.offsetY
}
} else {
// 事件源是divMove
var style = getComputedStyle(config.divMove);
var left = parseFloat(style.left);
var top = parseFloat(style.top);
return {
x: e.offsetX + left + 1,
y: e.offsetY + top + 1
}
}
}
}
}())
结语
整完!
js 实现淘宝放大镜功能,可更改配置参数 带完整版解析代码[magnifier.js]的更多相关文章
- js 实现淘宝无缝轮播图效果,可更改配置参数 带完整版解析代码[slider.js]
前言: 本人纯小白一个,有很多地方理解的没有各位大牛那么透彻,如有错误,请各位大牛指出斧正!小弟感激不尽. 本篇文章为您分析一下原生JS写淘宝无缝轮播图效果 需求分析: ...
- js 实现图片瀑布流效果,可更改配置参数 带完整版解析代码[waterFall.js]
前言: 本人纯小白一个,有很多地方理解的没有各位大牛那么透彻,如有错误,请各位大牛指出斧正!小弟感激不尽. 本篇文章为您分析一下原生JS实现图片瀑布流效果 页面需求 1 ...
- js 实现文字滚动功能,可更改配置参数 带完整版解析代码。
前言: 本人纯小白一个,有很多地方理解的没有各位大牛那么透彻,如有错误,请各位大牛指出斧正!小弟感激不尽. 本篇文章为您分析一下原生JS写文字滚动效果 需求分析: 需要 ...
- js 实现对象的混合与克隆效果,带完整版解析代码[helpers.js]
前言: 本人纯小白一个,有很多地方理解的没有各位大牛那么透彻,如有错误,请各位大牛指出斧正!小弟感激不尽. 本篇文章为您分析一下原生JS写淘宝无缝轮播图效果 对象混合 ...
- JS仿淘宝详情页菜单条智能定位效果
类似于淘宝详情页菜单条智能定位 对于每个人来说并不陌生!如下截图所示:红色框的那部分! 基本原理: 是用JS侦听滚动事件,当页面的滚动距离(页面滚动的高度)大于或者等于 "对象"( ...
- vue实现淘宝购物车功能
淘宝购物车功能,效果如下图 非常简单的逻辑,没有做代码的封装,代码如下 <div class="list-container"> <div class=" ...
- js实现百度,淘宝搜索功能
Common.js //封装类名 function byClassName(sClassName){ if(document.getElementsBYClassName){ return d ...
- javascript项目实战之原生js模拟淘宝购物车
通过JavaScript实现类似与淘宝的购物车效果,包括商品的单选.全选.删除.修改数量.价格计算.数目计算.预览等功能的实现.实现的效果图: 相应的代码: shoppingCart.html < ...
- 模仿淘宝首页写的高仿页面,脚本全用的原生JS,菜鸟一枚高手看了勿喷哈
自己仿照淘宝首页写的页面,仿真度自己感觉可以.JS脚本全是用原生JavaScript写得,没用框架.高手看了勿喷,请多多指正哈!先上网页截图看看效果,然后上源码: 上源码,先JavaScript : ...
随机推荐
- NKOJ 7.7练习题A IP地址
问题描述 可以用一个网络地址和一个子网掩码描述一个子网(即连续的 IP 地址范围).其中子网掩码包含 32 个二进制位,前 32-n 位为 1,后 n 位为 0,网络地址的前 32-n 位任意,后 n ...
- Docker的MySQL镜像, 实行数据,配置信息,日志持久化
Docker的MySQL8镜像, 实行数据持久化 使用Docker的MySQL8.0.17实例化一个容器之后需要对其进行数据持久化操作, 使用 docker docker run -p 7797:33 ...
- 1047 Student List for Course (25分)
Zhejiang University has 40,000 students and provides 2,500 courses. Now given the registered course ...
- Android 图片裁剪库 uCrop
引语 晚上好,我是猫咪,我的公众号「程序媛猫咪」会推荐 GitHub 上好玩的项目,挖掘开源的价值,欢迎关注我. 现在 Android 开发,离不开图片,必然也需要图片裁剪功能,这个实现可以调用系统的 ...
- 使用webview查找元素,appium查找web页面元素
9 webview查找元素 9.1 webview 简介 WebView是android中一个非常重要的控件,它的作用是用来展示一个web页面.它使用的内核是webkit引擎,4.4版本之后,直接使用 ...
- c++用递归法将一个整数n转换成字符串
任务描述 用递归法将一个整数n转换成字符串.例如,输入483,应输出字符串“483”.n的位数不确定,可以是任意位数的整数. 测试输入: 预期输出: 程序源码: #include <stdio. ...
- 最全的中文NLP资源库,你确定不来看一下吗?
最全的中文NLP资源库,你确定不来看一下吗? 22/100 发布文章 qq_39248703 hello,小伙伴们大家好,今天给大家分享NLP资源库,可以说是最全的资源库了,很多包非常有趣,值得收藏, ...
- pgsql中json格式数组查询结果变成了字符串
场景复原 最近使用到了json的数组,用来存储多个文件的值,发现在连表查询的时候返回结果变成了字符串. { "id": "repl-placeholder-007&quo ...
- python基础:如何使用python pandas将DataFrame转换为dict
之前在知乎上看到有网友提问,如何将DataFrame转换为dict,专门研究了一下,pandas在0.21.0版本中是提供了这个方法的.下面一起学习一下,通过调用help方法,该方法只需传入一个参数, ...
- Cobalt Strike系列教程第六章:安装扩展
Cobalt Strike系列教程分享如约而至,新关注的小伙伴可以先回顾一下前面的内容: Cobalt Strike系列教程第一章:简介与安装 Cobalt Strike系列教程第二章:Beacon详 ...