QQ空间在对长图的处理的时候,将长图显示在了一个固定宽高并且隐藏溢出部分的容器内,然后在鼠标移动到容器的时候滚动显示其他部分。那么如何实现呢?
先不考虑移动的效果,先看一下布局:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <title>qq空间长图滚动效果</title> <meta name="description" content=""> <meta name="keywords" content=""> <link href="" rel="stylesheet"> <style type="text/css"> .imgBox { display: inline-block; vertical-align: top; max-width: 560px; max-height: 384px; overflow: hidden; position: relative; } .imgBox img { max-width: 100%; } </style> </head> <body> <a href="javascript:void(0);" class="imgBox"> <img src="psb.jpg"> </a> </body> </html>
这样子长图就只会显示容器的大小部分了。接下来就需要做鼠标移动到容器的不同部分,上下滚动图片了。
分析一下:
1、鼠标移入容器我们可以根据鼠标的位置判断鼠标相对于容器在上部还是在下部(判断依据是元素的竖向中心线),进而判断元素需要向上滚动还是向下滚动。
2、滚动过程通过不断改变图片节点的marginTop值来实现,向上滚动marginTop<0,向下滚动marginTop>0,但需要注意最上端和最下端两个极值。
3、鼠标在容器内移动,需要实时计算鼠标相对于容器的位置,并向上或者向下移动。
4、鼠标移出容器,图片停止滚动并停留在当前位置。
最终代码:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <title>qq空间长图滚动效果</title> <meta name="description" content=""> <meta name="keywords" content=""> <link href="" rel="stylesheet"> <style type="text/css"> .imgBox { display: inline-block; vertical-align: top; max-width: 560px; max-height: 384px; overflow: hidden; position: relative; } .imgBox img { max-width: 100%; } .imgBox .long-pic { display: inline-block; position: absolute; bottom: 10px; right: 10px; padding: 3px 10px; font-style: normal; color: #fff; background: rgba(0, 0, 0, 0.5); border-radius: 5px; } </style> </head> <body> <a href="javascript:void(0);" class="imgBox"> <img src="psb.jpg"> </a> <script type="text/javascript"> const heightLimit = 384; var timer = null; var img = document.querySelector('.imgBox img'); loadImg(img.getAttribute('src'), function(w, h) { img.width = w; img.height = h; if (h>heightLimit) { var parentNode = img.parentNode; bindEvents(parentNode); createTip(parentNode, 'long-pic', '长图'); } }); function bindEvents(node) { node.addEventListener('mousemove', function(e) { var offset = getOffset(this), deltaY = e.pageY - offset.y, direction = 0; if (deltaY < heightLimit / 2) { // 鼠标在容器上部 direction = -1; } else { direction = 1; } slide(img, direction); }, false); node.addEventListener('mouseleave', function(e) { clearInterval(timer); }, false); } function slide(img, direction) { timer && clearInterval(timer); timer = setInterval(function() { var imgMarginTop = parseFloat(getStyle(img, 'marginTop')); if (direction < 0) { // 向上 if (imgMarginTop<0) { imgMarginTop ++; } else { clearInterval(timer); } } else { // 向下 if (Math.abs(imgMarginTop) + heightLimit<img.getAttribute('height')) { imgMarginTop --; } else { clearInterval(timer); } } img.style.marginTop = imgMarginTop + 'px'; }); } function getStyle(node, attr) { if (node.currentStyle) { return node.currentStyle[attr]; } else { return getComputedStyle(node, false)[attr]; } } function getOffset(node) { var offsetX = 0, offsetY = 0; while (node) { offsetX += node.offsetLeft; offsetY += node.offsetTop; node = node.offsetParent; } return { x: offsetX, y: offsetY }; } function createTip(parentNode, className, text) { var i = document.createElement('i'); i.className = className; if (text) { i.innerText = text; } parentNode.appendChild(i); return i; } function loadImg(src, callback) { var im = new Image(); im.src = src; im.onload = function() { callback && callback(this.width, this.height); } } </script> </body> </html>