最近在做一个网站的时候用到了图片联动的效果,然后觉得不错,就把其中图片联动的部分copy出来分享一下,其中包含图片的左右滚动,自定义滚动条,滚动条控制图片的滚动。
html部分:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>javascript实现动画的联动</title>
<link rel="shortcut icon" href="favicon.ico" />
<link rel="stylesheet" type="text/css" href="css/experience01.css" />
</head>
<body>
<div class="con_wrap">
<div id="contentbox1">
<div class="scrollImg">
<div class="scrollImg_left">
<a id="scroll_leftbtn" href="javascript:"></a>
<a id="scroll_rightbtn" href="javascript:"></a>
<ul id="scrollimg_list">
<li><img src="img/experience01/scrollimg01.jpg"/></li>
<li><img src="img/experience01/scrollimg02.jpg"/></li>
<li><img src="img/experience01/scrollimg03.jpg"/></li>
<li><img src="img/experience01/scrollimg04.jpg"/></li>
<li><img src="img/experience01/scrollimg05.jpg"/></li>
<li><img src="img/experience01/scrollimg06.jpg"/></li>
<li><img src="img/experience01/scrollimg07.jpg"/></li>
</ul>
</div>
<div id="scrollImg_right" class="scrollImg_right">
<ul id="scrollImg_right_list">
<li class="active"><img src="img/experience01/scrollimg01.jpg"/></li>
<li><img src="img/experience01/scrollimg02.jpg"/></li>
<li><img src="img/experience01/scrollimg03.jpg"/></li>
<li><img src="img/experience01/scrollimg04.jpg"/></li>
<li><img src="img/experience01/scrollimg05.jpg"/></li>
<li><img src="img/experience01/scrollimg06.jpg"/></li>
<li><img src="img/experience01/scrollimg07.jpg"/></li>
</ul>
<div id="scrollwrap">
<div id="scrollbtn"></div>
</div>
</div>
</div>
<div class="height50"></div>
<div class="height50"></div>
</div>
</div>
<script src="js/experience01.js" type="text/javascript" charset="utf-8"></script>
<script src="js/move.js" type="text/javascript" charset="utf-8"></script>
</body>
</html>
个人习惯用scss,如果你也在用那么可以直接看scss部分跳过css部分,如果习惯写css的同学可以跳过scss部分。
scss部分:
$mainColor: #50c8d7;
* {
margin: 0;
padding: 0;
font-family: "microsoft yahei";
}
a {
border: 0;
text-decoration: none;
}
li {
list-style: none;
}
img {
border: none;
}
.height50 {
width: 100%;
height: 50px;
}
#contentbox1 {
position: relative;
width: 1000px;
margin: 50px auto 0;
background: #fff;
.scrollImg {
clear: both;
width: 909px;
height: 432px;
margin: 10px 0 0 50px;
.scrollImg_left {
position: relative;
width: 674px;
height: 433px;
overflow: hidden;
float: left;
#scroll_leftbtn,
#scroll_rightbtn {
z-index: 5;
display: block;
width: 40px;
height: 40px;
position: absolute;
top: 170px;
opacity: 0.5;
filter:alpha(opacity=50);
}
#scroll_leftbtn:hover,
#scroll_rightbtn:hover {
opacity: 1;
filter:alpha(opacity=100);
}
#scroll_leftbtn {
left: 0;
background: #000 url("../img/experience01/scrollimg_left.png") no-repeat center center;
}
#scroll_rightbtn {
right: 0;
background: #000 url("../img/experience01/scrollimg_right.png") no-repeat center center;
}
ul {
clear: both;
position: absolute;
left: 0;
top: 0;
li {
display: block;
float: left;
width: 674px;
height: 433px;
img {
width: 100%;
height: 100%;
}
}
}
}
.scrollImg_right {
position: relative;
width: 235px;
height: 433px;
overflow: hidden;
float: left;
ul {
position: absolute;
left: 0;
top: 0;
width: 225px;
overflow: hidden;
li {
width: 215px;
height: 141px;
box-sizing: border-box;
margin: 0 5px 5px;
img {
display: block;
width: 100%;
height: 100%;
}
}
li.active {
border: 4px solid #fcb616;
}
}
#scrollwrap {
width: 10px;
height: 420px;
position: absolute;
right: 0;
top: 5px;
border-radius: 10px;
#scrollbtn {
width: 10px;
position: absolute;
top: 0;
left: 0;
height: 50px;
background: #bfbfbf;
border-radius: 10px;
}
}
}
}
}
css部分:
* {
margin: 0;
padding: 0;
font-family: "microsoft yahei"; }
a {
border: 0;
text-decoration: none; }
li {
list-style: none; }
img {
border: none; }
.height50 {
width: 100%;
height: 50px; }
#contentbox1 {
position: relative;
width: 1000px;
margin: 50px auto 0;
background: #fff; }
#contentbox1 .scrollImg {
clear: both;
width: 909px;
height: 432px;
margin: 10px 0 0 50px; }
#contentbox1 .scrollImg .scrollImg_left {
position: relative;
width: 674px;
height: 433px;
overflow: hidden;
float: left; }
#contentbox1 .scrollImg .scrollImg_left #scroll_leftbtn,
#contentbox1 .scrollImg .scrollImg_left #scroll_rightbtn {
z-index: 5;
display: block;
width: 40px;
height: 40px;
position: absolute;
top: 170px;
opacity: 0.5;
filter: alpha(opacity=50); }
#contentbox1 .scrollImg .scrollImg_left #scroll_leftbtn:hover,
#contentbox1 .scrollImg .scrollImg_left #scroll_rightbtn:hover {
opacity: 1;
filter: alpha(opacity=100); }
#contentbox1 .scrollImg .scrollImg_left #scroll_leftbtn {
left: 0;
background: #000 url("../img/experience01/scrollimg_left.png") no-repeat center center; }
#contentbox1 .scrollImg .scrollImg_left #scroll_rightbtn {
right: 0;
background: #000 url("../img/experience01/scrollimg_right.png") no-repeat center center; }
#contentbox1 .scrollImg .scrollImg_left ul {
clear: both;
position: absolute;
left: 0;
top: 0; }
#contentbox1 .scrollImg .scrollImg_left ul li {
display: block;
float: left;
width: 674px;
height: 433px; }
#contentbox1 .scrollImg .scrollImg_left ul li img {
width: 100%;
height: 100%; }
#contentbox1 .scrollImg .scrollImg_right {
position: relative;
width: 235px;
height: 433px;
overflow: hidden;
float: left; }
#contentbox1 .scrollImg .scrollImg_right ul {
position: absolute;
left: 0;
top: 0;
width: 225px;
overflow: hidden; }
#contentbox1 .scrollImg .scrollImg_right ul li {
width: 215px;
height: 141px;
box-sizing: border-box;
margin: 0 5px 5px; }
#contentbox1 .scrollImg .scrollImg_right ul li img {
display: block;
width: 100%;
height: 100%; }
#contentbox1 .scrollImg .scrollImg_right ul li.active {
border: 4px solid #fcb616; }
#contentbox1 .scrollImg .scrollImg_right #scrollwrap {
width: 10px;
height: 420px;
position: absolute;
right: 0;
top: 5px;
border-radius: 10px; }
#contentbox1 .scrollImg .scrollImg_right #scrollwrap #scrollbtn {
width: 10px;
position: absolute;
top: 0;
left: 0;
height: 50px;
background: #bfbfbf;
border-radius: 10px; }
javascript部分:函数部分+主体部分
/**
* 兼容IE获取样式函数
* @param {Object} obj
* @param {Object} name
*/
function getStyle(obj, name)
{
if(obj.currentStyle)
{
return obj.currentStyle[name];
}
else
{
return getComputedStyle(obj, false)[name];
}
}
/**
* 阻止默认事件
* @param {Object} e
*/
function preventDefa(e){
if(window.event){
//IE中阻止函数器默认动作的方式
window.event.returnValue = false;
}
else{
//阻止默认浏览器动作(W3C)
e.preventDefault();
}
}
/**
* 运动函数
* @param {Object} obj
* @param {Object} attr
* @param {Object} iTarget
* @param {Object} fnend
*/
function startMove2(obj, attr, iTarget,fnend)
{
var cur=parseInt(getStyle(obj, attr));
var speed=(iTarget-cur)/15;
speed=speed>0?Math.ceil(speed):Math.floor(speed);
clearInterval(obj.timer);
obj.timer=setInterval(function (){
if(attr=='opacity')
{
cur=Math.round(parseFloat(getStyle(obj, attr))*100);
}
else
{
cur=parseInt(getStyle(obj, attr));
}
if(Math.abs(iTarget - cur) < Math.abs(speed))
{
obj.style[attr]=iTarget+'px';
clearInterval(obj.timer);
if(fnend) fnend();
}
else
{
if(attr=='opacity')
{
obj.style.filter='alpha(opacity:'+(cur+speed)+')';
obj.style.opacity=(cur+speed)/100;
}
else
{
obj.style[attr]=cur+speed+'px';
}
}
}, 30);
}
函数封装部分前两个函数均是为了兼容IE,第三个运动函数之前有写过传送门,不再赘述。
window.onload = function() {
imgscroll(); //页面中部左侧图片滚动
imgscrollList();//页面中部右侧图片滚动
}
function imgscroll() {
//获取盒子和按钮
var scrImgList = document.getElementById('scrollimg_list');
var list = scrImgList.getElementsByTagName('li');
var lbtn = document.getElementById('scroll_leftbtn');
var rbtn = document.getElementById('scroll_rightbtn');
//单张图片的宽
var imgW = list[0].offsetWidth;
//增加一倍长度用于滚动
scrImgList.innerHTML = scrImgList.innerHTML + scrImgList.innerHTML;
scrImgList.style.width = imgW * list.length + "px";
//根据当前ul的left值计算页码
var page = scrImgList.offsetLeft / imgW;
//设置一个开关,当点击一个按钮的事件未完成时候另一个按钮不能点击。
var bool = true;
//获取右边盒子图片数组
var scrImgR = document.getElementById('scrollImg_right_list');
var listR = scrImgR.getElementsByTagName('li');
//右边盒子
var boxR = document.getElementById('scrollImg_right');
//单张图片的高——包含margin
var imgRH = scrImgR.offsetHeight / listR.length;
//向左滚动
lbtn.onclick = function() {
if(bool) {
//设置开关,此次循环未结束不能点击下一张
bool = !bool;
//判断是否到达临界点,到达则重置
if(page >= list.length / 2) {
scrImgList.style.left = 0 + "px";
page = 0;
}
page++; //页码放在这里可以连续按按钮,如果放在回调函数中则要等上一步进行完下一次点击才有用
//左右盒子的联动
//最上面一张图的处理
if(page % listR.length == 0) {
startMove2(scrImgR, 'top', 0);
}
//最下面一张图的处理
else if(page % listR.length == listR.length - 1) {
//此处多减去的 5 为margin值,为了保证最后一个盒子下面没有空隙
startMove2(scrImgR, 'top', -(scrImgR.offsetHeight - boxR.offsetHeight - 5));
}
//其他情况的处理
else {
startMove2(scrImgR, 'top', -(page % listR.length - 1) * imgRH);
}
startMove2(scrImgList, 'left', -(page) * imgW, function() {
bool = !bool;
//遍历页面,清除类并激活当前的图片
for(var i = 0; i < listR.length; i++) {
listR[i].className = "";
}
listR[page % listR.length].className = "active";
});
}
}
//向右
rbtn.onclick = function() {
if(bool) {
bool = !bool;
if(page <= 0) {
scrImgList.style.left = -imgW * (list.length / 2) + "px";
page = list.length / 2;
}
page--;
if(page % listR.length == 0) {
startMove2(scrImgR, 'top', 0);
} else if(page % listR.length == listR.length - 1) {
startMove2(scrImgR, 'top', -(scrImgR.offsetHeight - boxR.offsetHeight - 5));
} else {
startMove2(scrImgR, 'top', -(page % listR.length - 1) * imgRH);
}
startMove2(scrImgList, 'left', -(page) * imgW, function() {
bool = !bool;
for(var i = 0; i < listR.length; i++) {
listR[i].className = "";
}
listR[page % listR.length].className = "active";
});
}
}
}
function imgscrollList() {
//最外层的盒子,需要设置溢出隐藏的那个
var box = document.getElementById('scrollImg_right');
//图片盒子
var scrImgList = document.getElementById('scrollImg_right_list');
//图片数组,获取每一张图片
var list = scrImgList.getElementsByTagName('li');
//滚动条外层
var scrollwrap = document.getElementById('scrollwrap');
//滚动条内部的按钮
var scrollbtn = document.getElementById('scrollbtn');
//图片可滚动的高度,而不是图片加起来的高度
var imgT = scrImgList.offsetHeight - box.offsetHeight;
//左侧图片盒子
var scrImgListL = document.getElementById('scrollimg_list');
//左侧图片数组
var listL = scrImgListL.getElementsByTagName('li');
//根据图片数组的长度确定滚动按钮的高
scrollbtn.style.height = scrollwrap.offsetHeight - list.length * 30 + "px";
//鼠标滚动兼容处理
if(box.addEventListener) {
box.addEventListener("DOMMouseScroll", fn, false);
}
box.onmousewheel = fn; //兼容IE、chrome
//鼠标滚动函数
function fn(ev) {
var ev = ev || event;
preventDefa(ev); //阻止浏览器默认事件
var bool = false;
var maxT = scrollwrap.offsetHeight - scrollbtn.offsetHeight;
var n = 30; //一次移动的距离
var scal = n / maxT; //比例系数
//IE、chrome 向上:120,向下:-120
if(ev.wheelDelta) {
bool = ev.wheelDelta > 0 ? true : false;
}
//firefox 向上:-3,向下:3
else {
bool = ev.detail < 0 ? true : false;
}
if(bool) {
//向上滚动,到达最后一次的滚动距离时就不能滚动
if(scrollbtn.offsetTop >= n) {
scrollbtn.style.top = scrollbtn.offsetTop - n + "px";
scrImgList.style.top = scrImgList.offsetTop + scal * imgT + "px";
} else {
scrollbtn.style.top = 0;
}
} else {
//向下滚动,到达最后一次的滚动距离时就不能滚动
if(scrollbtn.offsetTop <= maxT - n) {
scrollbtn.style.top = scrollbtn.offsetTop + n + "px";
scrImgList.style.top = scrImgList.offsetTop - scal * imgT + "px";
} else {
scrollbtn.style.top = maxT + "px";
}
}
}
//鼠标拖动滚动条
scrollbtn.onmousedown = function(ev) {
var ev = event || ev;
var disY = ev.clientY - scrollbtn.offsetTop;
document.onmousemove = function(ev) {
var ev = event || ev;
var t = ev.clientY - disY;
//控制滚动按钮的位置在一个范围内
if(t < 0) {
t = 0;
} else if(t > (scrollwrap.offsetHeight - scrollbtn.offsetHeight)) {
t = scrollwrap.offsetHeight - scrollbtn.offsetHeight;
}
//比例系数,用来计算图片在图片盒子中的相对位置
var scal = t / (scrollwrap.offsetHeight - scrollbtn.offsetHeight);
scrImgList.style.top = -scal * imgT + "px";
scrollbtn.style.top = t + "px";
}
document.onmouseup = function() {
document.onmousemove = null;
document.onmousedown = null;
}
return false;
}
//右边li点击事件
for(var i=0;i<list.length;i++){
list[i].index = i;
list[i].onclick = function () {
//控制左边跳转到相应的页码
startMove2(scrImgListL, 'left', -this.index*listL[0].offsetWidth);
for(var j=0;j<list.length;j++){
list[j].className = '';
}
this.className = 'active';
}
}
}
在这部分javascript代码中,注释已经非常详细,主要还是理解其思想。
首先,左边是一个图片轮播,而且不需要自动滚动,这个就是点击左右按钮执行切换的函数即可,在切换到第一张和最后一张的时候要注意图片位置的归零,这样滚动才能显得更加的顺畅。本文采用的方法是使用两倍数量的图片,当进行到最后一张或者第一张时,先执行运动切换,然后瞬间将图片位置进行一个移动,这在人眼是无法察觉的。
第二个,右边的滚动条,这个滚动条的制作之前也有写过传送门,核心是鼠标对滚动条的拖动和鼠标滚动控制滚动条的移动,然后我们实现滚动条的位置控制右边图片在盒子的相对位置,原理是利用滚动条在盒子中的相对位置计算出一个比例系数,然后利用比例系数确定图片在盒子中的相对位置。
第三个,左右联动之左边控制右边,当左边切换到某张图片时,右边的对应的图片要切换classname为active,同时要保证这种图片时在装图片的盒子的可视区域。这里我使用的方法是通过左边图片距离盒子左边的相对位置除以单张图片的宽度确定现在图片是第几张,然后激活右边对应的图片;至于图片保持在装图片盒子的可视区域,这个就需要用到一个判断,主要分为两步:1.第一张和最后一张的特殊处理,第一张和最后一张不能在盒子的中间,所以是直接移动到底部或者顶部。2.其他图片通过距离顶部的距离和每张图片在盒子中的相对位置进行计算定位到盒子中间,这里需要注意的是要把margin也计算进去。
第四个,左右联动之右边控制左边,这个相对简单,我们此时点击的是第几张,直接使用其索引计算左边图片需要移动到的位置即可。
总结:每个模块都不是太难,主要难点是在控制左右联动,本文的左右联动是通过判定位置确定页码,同时建议大家在这种比较多参数需要处理的时候将不同的模块分开来写,让不同的模块公用少数几个参数或者不用共同的参数,通过返回值来传递参数,这样出错的几率会很小,同时也便于日后的复用和思路的梳理。