完成一个放大镜的功能
当鼠标经过小方块时,旁边会出现一个放大镜,跟随鼠标的移动可以放大各种位置
html代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
*{
margin: 0;
padding: 0;
}
.box{
width: 1000px;
height: 600px;
background:#ccc;
margin:100px auto;
}
img{
display:block;
}
.show{
width: 350px;
height: 350px;
position:relative;
border:2px solid #000;
float:left;
}
.mask {
width: 200px;
height: 200px;
background-color:yellow;
opacity:0;
position:absolute;
left: 0;
top: 0;
}
.bigBox{
width: 400px;
height: 400px;
border:2px solid red;
overflow:hidden;
float:left;
margin-left: 20px;
opacity: 0;
position:relative;
}
.bigBox img{
position:absolute;
left: 0;
top: 0;
}
</style>
</head>
<body>
<div class="box">
<div class="show">
<div class="mask"></div>
<img src="img/show.jpg" />
</div>
<div class="bigBox">
<img src="./img/big.jpg" />
</div>
</div>
<script src="./js/utils.js"></script>
<script src="./js/index.js"></script>
<script>
const m1 = new Magnifier()
m1.init()
</script>
</body>
</html>
utils.js
/*
工具类函数
*/
/*
检测一个字符串是否是可回文字符串
@param a 要检测的字符串
@return 返回值是一个布尔值
*/
function fn(a) {
return a.split('').reverse().join('') === a ? true : false
}
/*
求一个范围之间的随机数
@param a 范围下限
@param b 范围上限
@return 范围之间的随机数
*/
function getRandom(a, b) {
return Math.floor(Math.random() * (b - a + 1) + a)
}
/*
随机颜色
@return 随机颜色字符串
*/
function getColor() {
return "rgb(" + getRandom(0, 255) + "," + getRandom(0, 255) + "," + getRandom(0, 255) + ")"
}
/*
通过选择器获取元素
@param selector 要获取的元素的 id/class/标签名
@param context 从哪个范围获取
@return 获取到的元素或者元素伪数组
*/
function my$(selector, context) {
context = context || document
if (selector.indexOf('#') === 0) {
return document.getElementById(selector.slice(1))
}
if (selector.indexOf('.') === 0) {
return context.getElementsByClassName(selector.slice(1))
}
return context.getElementsByTagName(selector)
}
/*
获取/设置元素的样式
@param ele 元素
@param attr 要获取/设置的属性
@param value 要获取/设置的属性值
@return 获取/设置好的属性值
*/
function css(ele, attr, value) {
if (value) {
ele.style[attr] = value
}
// 有第三个参数就是设置 没有就是获取
return window.getComputedStyle ? window.getComputedStyle(ele)[attr] : ele.currentStyle[attr]
}
/*
绑定事件 兼容处理
@param ele 要绑定事件的元素
@param type 事件类型
@param fn 事件处理函数
*/
function on(ele, type, fn) {
if (ele.addEventListener) {
if (type.indexOf('on') === 0) {
type = type.slice(2)
}
ele.addEventListener(type, fn)
} else {
if (type.indexOf('on') !== 0) {
type = 'on' + type
}
ele.attachEvent(type, fn)
}
}
function off(){
}
/*
对 ie8 不支持 pageX pageY 做的兼容处理
@param e event 对象
@return 光标距离页面左边和上边的距离数据对象
*/
function page(e) {
if (e.pageX) {
return { x: e.pageX, y: e.pageY }
}
var _x = document.documentElement ? document.documentElement.scrollLeft + e.clientX : document.body.scrollLeft + e.clientX
var _y = document.documentElement ? document.documentElement.scrollTop + e.clientY : document.body.scrollTop + e.clientY
return { x:_x,y:_y}
}
/*
运动框架函数
@param ele 执行运动的元素
@param options 终点值 是一个对象
@param duration 运动的总时间
@param fn 运动执行完毕的回调函数
*/
function animate(ele, options, duration,fn) {
clearInterval(ele.timer)
const start = {}, range = {}
for (var key in options) {
start[key] = parseFloat(css(ele, key))
range[key] = options[key] - start[key]
}
const startTime = +new Date()
ele.timer = setInterval(() => {
let nowTime = +new Date()
let timeDifference = Math.min(nowTime - startTime,duration)
for (let attr in options) {
let result = start[attr] + range[attr] / duration * timeDifference
result = attr === 'opacity' ? result : result + 'px'
ele.style[attr] = result
}
if (timeDifference === duration) {
clearInterval(ele.timer)
fn && fn()
}
}, 10)
}
/*
淡入
*/
function fadeIn(ele,time,fn){
css(ele,'display','block')
css(ele,'opacity','0')
animate(ele,{opacity:1},time,fn)
}
/*
淡出
*/
function fadeOut(ele,time,fn){
css(ele,'display','block')
css(ele,'opacity','1')
animate(ele,{opacity:0},time,fn)
}
index.js
function Magnifier(options) {
options = options || {}
this.box = options.box || document.querySelector('.box')
this.show = options.show || this.box.querySelector('.show')
this.showInfo = {
width: this.show.offsetWidth,
height: this.show.offsetHeight
}
this.mask = options.mask || this.box.querySelector('.mask')
this.maskInfo = {
width: this.mask.offsetWidth,
height: this.mask.offsetHeight
}
this.bigBox = options.bigBox || this.box.querySelector('.bigBox')
this.bigBoxInfo = {}
this.bigImg = options.bigImg || this.bigBox.querySelector('img')
this.bigImgInfo = {
width: this.bigImg.offsetWidth,
height: this.bigImg.offsetHeight
}
}
Magnifier.prototype.init = function () {
// 1、计算比例 重置大盒子大小
this.resetBigBox()
// 2、限定范围拖拽
this.enterOut()
this.move()
// 3、计算比例 设置大图在大盒子里面的移动距离
}
Magnifier.prototype.resetBigBox = function () {
/*
mask 在 show 盒子里面 移动
大图 是在 bigBox 里面移动
mask bigBox
----- = --------
show bigImg
bigBoxwidth = maskwidth * bigImgWidth / showWidth
*/
const bigBoxWidth = this.maskInfo.width * this.bigImgInfo.width / this.showInfo.width
const bigBoxHeight = this.maskInfo.height * this.bigImgInfo.height / this.showInfo.height
this.bigBoxInfo = {
width:bigBoxWidth,
height:bigBoxHeight
}
css(this.bigBox, 'width', bigBoxWidth + 'px')
css(this.bigBox, 'height', bigBoxHeight + 'px')
}
Magnifier.prototype.enterOut = function () {
// 此时 箭头函数里面的 this 指向 实例化对象
on(this.show, 'mouseenter', () => {
css(this.mask, 'opacity', '0.3')
css(this.bigBox, 'opacity', '1')
})
on(this.show, 'mouseleave', () => {
css(this.mask, 'opacity', '0')
css(this.bigBox, 'opacity', '0')
})
}
Magnifier.prototype.move = function () {
on(this.show, 'mousemove', (e) => {
let _left = e.pageX - this.box.offsetLeft - this.maskInfo.width / 2
let _top = e.pageY - this.box.offsetTop-this.maskInfo.height / 2
if(_left <= 0 ){
_left = 0
}else if(_left >= this.showInfo.width - this.maskInfo.width){
_left = this.showInfo.width - this.maskInfo.width
}
if(_top <= 0){
_top = 0
}else if(_top >= this.showInfo.height - this.maskInfo.height){
_top = this.showInfo.height - this.maskInfo.height
}
// 计算大图 移动的比例
/*
mask 移动的距离 大图移动的距离
---------------------- = -------------------
mask 能够移动的最大距离 大图能够移动的最大距离
大图移动的距离 = mask 移动的距离 * 大图能够移动的最大距离 / mask 能够移动的最大距离
*/
const bigImgLeft = _left * (this.bigImgInfo.width - this.bigBoxInfo.width) / (this.showInfo.width - this.maskInfo.width)
const bigImgTop = _top * (this.bigImgInfo.height - this.bigBoxInfo.height) / (this.showInfo.height - this.maskInfo.height)
// 设置大图 的 left 和 top 值
this.bigImg.style.left = -bigImgLeft + 'px'
this.bigImg.style.top = -bigImgTop + 'px'
this.mask.style.left = _left + 'px'
this.mask.style.top = _top + 'px'
})
}