一款几年前的轮播图|满满的兼容性味道

最近整理电脑偶然发现自己几年前的学习笔记,那时我才是刚入前端不久,每当看到新奇的js效果都忍不住惊叹,记得当时写过很多的练习作品,现在大多尘封在我的D盘,和岛国爱情片共享天伦之乐。

这是一个当年很流行的js轮播效果,那时候css3.0还不允许用,所以动画都是采用js的setTimeout来写的。

默认效果长这样,图片如有侵权请联系,立即就删。

屏幕快照 2021-06-30 15.39.33.png

滚动效果是这个样子的,现在看起来好像也挺好看的。

未命名.gif

记得去年好像在酷我音乐里面还见到了这样的滚动效果。

页面的布局很简单,一个div里面包裹了要滚动的内容和向前向后的操作按钮。由于刚学前端还不懂什么react,vue,代码都是写死的,写一句手动刷新一下浏览器,手动欢乐。

<body>
	<div id="content">
		<div class="prev_div"></div>
		<div class="next_div"></div>
		<ul>
			<li class="item_0">
				<img src="https://img.zcool.cn/community/01cc635cbdecbca801214168c7fa83.png@1280w_1l_2o_100sh.png">
			</li>
			<li class="item_1">
				<img src="https://img.zcool.cn/community/018b535cbdecbca801214168fe547d.png@1280w_1l_2o_100sh.png">
			</li>
			<li class="item_2">
				<img src="https://img.zcool.cn/community/01231d5cbdf17aa801214168294a22.jpg@1280w_1l_2o_100sh.jpg">
			</li>
			<li class="item_3">
				<img src="https://img.zcool.cn/community/01f4a05cbdecbca8012141689f5b58.png@1280w_1l_2o_100sh.png">
			</li>
			<li class="item_4">
				<img src="https://img.zcool.cn/community/01df655cbdf29aa801214168b005b6.jpg@1280w_1l_2o_100sh.jpg">
			</li>
			<li class="item_5">
				<img src="https://img.zcool.cn/community/0166c35cbdf29ba801208f8ba065df.jpg@1280w_1l_2o_100sh.jpg">
			</li>
			<li class="item_6">
				<img src="https://img.zcool.cn/community/013cdc5cbdecbda801208f8bc572cc.png@1280w_1l_2o_100sh.png">
			</li>
		</ul>
	</div>
</body>
复制代码

style样式也是随手就写,哪天什么less,sass。第一句肯定是这个。先重置样式

html, body, ul, li, img, a, p { padding: 0; margin: 0; }
li { list-style: none; }
img { border: none; width: 680px; height: 344px;}
body { background: #ececec; padding-top: 50px; }
复制代码

然后样式都是手动一级一级的向后写,最多的时候能写个五六级,而且特别容易出错,莫名其妙样式就被覆盖了。

#content { width: 970px; height: 344px; position: relative; margin: 0 auto; overflow: hidden; }

.prev_div { width: 130px; height: 72px; position: absolute; top: 128px; left: 92px; z-index: 5; background: red; filter: alpha(opacity=0); opacity: 0; cursor: pointer; }
.next_div { width: 130px; height: 72px; position: absolute; top: 128px; right: 92px; z-index: 5; background: red; filter: alpha(opacity=0); opacity: 0; cursor: pointer; }

#content ul { width: 970px; height: 344px; position: absolute; top: 0; left: 0; z-index: 1; }
#content li { position: absolute; }

#content .line { border: 4px solid #fff; width: 672px; height: 336px; position: absolute; top: 0; left: 50%; margin-left: -340px; z-index: 3; }

#content .item_0 { top: -104px; left: 0; z-index: 1; filter: alpha(opacity=0); opacity: 0; }
#content .item_1 { top: 104px; left: 0; z-index: 2; filter: alpha(opacity=60); opacity: 0.6; }
#content .item_2 { top: 43px; left: 50px; z-index: 3; filter: alpha(opacity=80); opacity: 0.8; }
#content .item_3 { top: 0; left: 145px; z-index: 4; }
#content .item_4 { top: 43px; right: 50px; z-index: 3; filter: alpha(opacity=80); opacity: 0.8; }
#content .item_5 { top: 104px; right: 0; z-index: 2; filter: alpha(opacity=60); opacity: 0.6; }
#content .item_6 { top: -104px; right: 0; z-index: 1; filter: alpha(opacity=0); opacity: 0; }
复制代码

细心的你肯定发现了filter: alpha,这还是兼容IE浏览器的代码,我的青春。

接着就是js了,首先第一句就是这个,真的持续了好长一段时间,做梦都是这样写。那时候面试也很喜欢问这个问题,为什么要这么写。

window.onload = function () {

}
复制代码

onload里面就开始操作dom啦,首先获取左右两个操作按钮,并且给他们绑定事件。对了要用var,哪有什么const和let,必须得是var。

var oPrevDiv = document.getElementsByClassName('prev_div')[0];
var oNextDiv = document.getElementsByClassName('next_div')[0];
复制代码

绑定事件都是这样写的。

oPrevDiv.onclick = function () {  //左

}

oNextDiv.onclick = function () {  //右

}
复制代码

这个效果的原理实现起来还是很简单的,这里有六张图片,布局完成之后记住每一张图片的位置数据, 宽高啊,透明度啊,将每一组定义为一个对象存储在数组中。当点击前一张的时候就把数组中的最后一个元素放在数组第一位,点击后一个就把第一个元素放在数组最后一位。

屏幕快照 2021-06-30 15.39.33.png

首先定义一个数组把没涨图片的布局数据存起来。

var aLi = document.getElementsByTagName('li');

var arr = [];

for (var i = 0; i < aLi.length; i++) {

    var oImg = aLi[i].getElementsByTagName('img')[0];

    arr.push([
        parseInt(getStyle(aLi[i], 'left')),
        parseInt(getStyle(aLi[i], 'top')), 
        getStyle(aLi[i], 'opacity') * 100, 
        getStyle(aLi[i], 'zIndex'), 
        oImg.width
    ]);
}

function getStyle(obj, attr) {
    if (obj.currentStyle) {
        return obj.currentStyle[attr];
    }
    else {
        return getComputedStyle(obj, false)[attr];
    }
}
复制代码

getStyle这个封装太有年代感了,DOM编程必备的,之所以封装也是为了解决兼容性问题。

接着点击按钮的时候只需要切换数组中元素的顺序就可以啦。点击想做的时候,将数组的第一个元素放在了数组尾部,并且删除了第一个,来实现交换位置。

然后还得循环来修正每一个标签对应的样式。这里还封装了一个move方法来实现运行效果。那时候基本都是先写代码,写完之后找相似的功能封装函数,再替换,效率真的低。

oPrevDiv.onclick = function () {  //左

	arr.push(arr[0]);
	arr.shift();

	for (var i = 0; i < aLi.length; i++) {

		var oImg = aLi[i].getElementsByTagName('img')[0];
		// 当前li的index属性修改,index是不支持做动画的。
		aLi[i].style.zIndex = arr[i][3];
		// 处理
		move(aLi[i], { left: arr[i][0], top: arr[i][1], opacity: arr[i][2] });
		// 处理img
		move(oImg, { width: arr[i][4] });

	}

};

oNextDiv.onclick = function () {  //右
	arr.unshift(arr[arr.length - 1]);
	arr.pop();

	for (var i = 0; i < aLi.length; i++) {

		var oImg = aLi[i].getElementsByTagName('img')[0];

		aLi[i].style.zIndex = arr[i][3];

		move(aLi[i], { left: arr[i][0], top: arr[i][1], opacity: arr[i][2] });
		move(oImg, { width: arr[i][4] });
	}
};
复制代码

move函数接收两个参数,第一个是要操作的DOM元素,第二个是要操作的的属性。

进入函数的时候我们首先会清空一次定时器,避免重复调用,然后再定义一个定时器setInterval,那时候真的很喜欢setInterval直到后来清楚了他的问题才慢慢转向setTimeout, 也没有什么requestAnimationFrame。

定时器里面就是改变每个属性的值,每次改动一点,直到改动完成,通过这样的方式来实现动画。

function move(obj, json) {

	clearInterval(obj.timer);

	obj.timer = setInterval(function () {

		var bBtn = true;

		for (var attr in json) {

			var iCur = 0;

			if (attr == 'opacity') {
				if (Math.round(parseFloat(getStyle(obj, attr)) * 100) == 0) {
					iCur = Math.round(parseFloat(getStyle(obj, attr)) * 100);

				} else {
					iCur = Math.round(parseFloat(getStyle(obj, attr)) * 100) || 100;
				}
			} else {
				iCur = parseInt(getStyle(obj, attr)) || 0;
			}

			var iSpeed = (json[attr] - iCur) / 8;
			iSpeed = iSpeed > 0 ? Math.ceil(iSpeed) : Math.floor(iSpeed);
			if (iCur != json[attr]) {
				bBtn = false;
			}

			if (attr == 'opacity') {
				obj.style.filter = 'alpha(opacity=' + (iCur + iSpeed) + ')';
				obj.style.opacity = (iCur + iSpeed) / 100;

			} else {
				obj.style[attr] = iCur + iSpeed + 'px';
			}
		}
		if (bBtn) {
			clearInterval(obj.timer);
		}
	}, 30);
}
复制代码

move函数是单独写在一个js文件里的,然后在html里面直接script进来,所有的变量都是全局变量才行,不然真的找不到,哈哈哈哈,根本没有什么模块化的概念。

满满的回忆,时间太快了,前端变化也太快了,我的青春啊!

自取链接: github.com/xiaoyindong…

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享