原生JS轮播-各种效果的极简实现(二)面向对象版本的实现和优化
之前写了一篇原生JS轮播,不过是非面向对象的,并且也没有添加上自动轮播。这里来写一下如何优化和进阶。
这里简单地介绍一下之前的代码,这是html结构
<body>
<div class="wrap">
<ul class="pic-group">
<li><img src="./pic1.jpg" alt=""></li>
<li><img src="./pic2.jpg" alt=""></li>
<li><img src="./pic3.jpg" alt=""></li>
<li><img src="./pic4.jpg" alt=""></li>
<li><img src="./pic5.jpg" alt=""></li>
</ul>
<ol class="num-group">
<li class="current">1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ol>
</div>
</body>
css结构
<style type="text/css">
* {
margin: 0;
padding: 0;
}
ul, li {
list-style: none;
}
body {
background-color: #000;
}
.wrap {
position: relative;
border: 8px solid #fff;
margin: 100px auto;
width: 400px;
height: 250px;
overflow: hidden;
}
.pic-group {
position: absolute;
}
.pic-group li img {
display: block;
width: 100%;
height: 100%;
}
.num-group {
position: absolute;
bottom: 5px;
right: 0;
height: 20px;
}
.num-group li {
float: left;
width: 20px;
height: 20px;
line-height: 20px;
font-size: 10px;
margin-right: 10px;
background-color: #089e8a;
color: #eee;
text-align: center;
border-radius: 10px;
cursor: pointer;
opacity: 0.8;
}
.num-group li:hover {
box-shadow: 0 0 18px #000;
}
.num-group li.current {
opacity: 1;
color: #089a8a;
background-color: #000;
}
</style>
JS 结构
const oImage = document.getElementsByClassName("pic-group")[0];
const oNumber = document.getElementsByClassName("num-group")[0];
const numList = oNumber.getElementsByTagName("li");
for (let i = 0; i < numList.length; i++) {
numList[i].onmouseover = () => {
clearNumState();
show(i);
}
}
const clearNumState = () => {
for (const item of numList) {
item.className = "";
}
}
let timer = null;
const show = (index) => {
numList[index].className = "current";
if (timer) clearInterval(timer);
const target = -250 * index;
let now = oImage.offsetTop;
timer = setInterval(() => {
if (now === target) {
clearInterval(timer);
} else {
now += move(target);
oImage.style.top = now + "px";
console.log(oImage.offsetTop);
}
}, 20);
}
const move = (target) => {
// 当前值
const now = oImage.offsetTop;
const differ = target - now;
console.log(differ / 10);
const res = differ > 0 ? Math.ceil(differ / 10) : Math.floor(differ / 10);
return res;
}
进阶1:我们可以通过offsetHeight获取图片元素的高度。好处1是我们的移动函数不用限死。也为后来将其变为通用的一组代码做铺垫。
这里遇到一个不该出现的问题。常常我们看到直接获取高度的时候是 0,原因是:一些元素是根据内容的高度自动调整的,即所谓的自适应高度,它的高度取决于内容的多少。
获取这样的自适应高度元素主要有两种办法
- currentStyle
- offsetHeight
但用在这里我的offsetHeight竟然是0?不是说好了能获取自适应高度的吗!
const oHeight = oImage.getElementsByTagName("li")[0].offsetHeight;
console.log(oHeight); // 0 !!! 0 !!!
经过我的发现,我知道了问题出在这里?JS代码跑完了?但是图片是否加载完毕了呢?
window.onload = function() {
const oT = document.getElementsByClassName("pic-group")[0];
const oI = oT.getElementsByTagName("li");
console.log(oI[0].offsetHeight); // 250
}
图片没有加载完。当然这里还有一个疑问,为什么控制台有了答案?(这个留待以后探究)


https://www.cnblogs.com/hanxingli/p/5513116.html
这里第 5 句 正是解答,图片还在加载中,先执行了代码。
那么,解决方案是什么呢?
我们需要的是等图片加载完后执行JS的办法
http://www.jb51.net/article/79233.htm
思前想后,这只是个简单的轮播,我选择了window.onload,还有一个不太破坏代码的是async/await,可是那需要加载新的库支持,所以这里选择了最开始的window.onload。
进阶2:添加自动轮播,同时,我们也可以发现,clearNumState应该放在show函数里面
const oImage = document.getElementsByClassName("pic-group")[0];
const oNumber = document.getElementsByClassName("num-group")[0];
const numList = oNumber.getElementsByTagName("li");
const imageList = oImage.getElementsByTagName("li");
const oHeight = imageList[0].offsetHeight;
for (let i = 0; i < numList.length; i++) {
numList[i].onmouseover = () => {
// clearNumState();
show(i);
}
}
const clearNumState = () => {
for (const item of numList) {
item.className = "";
}
}
let timer = null;
const show = (index) => {
clearNumState();
numList[index].className = "current";
if (timer) clearInterval(timer);
const target = -oHeight * index;
let now = oImage.offsetTop;
timer = setInterval(() => {
if (now === target) {
clearInterval(timer);
} else {
now += move(target);
oImage.style.top = now + "px";
console.log(oImage.offsetTop);
}
}, 20);
}
const move = (target) => {
const now = oImage.offsetTop;
const differ = target - now;
console.log(differ / 10);
const res = differ > 0 ? Math.ceil(differ / 10) : Math.floor(differ / 10);
return res;
}
let autoTimer = null;
let index = 0;
const auto = () => {
autoTimer = setInterval(() => {
show(index);
index < numList.length - 1 ? index++ : index = 0;
}, 2000);
}
auto();
进阶3:还需要添加上鼠标移动前后的东西
oImage.onmouseover = function() {
if (autoTimer) clearInterval(autoTimer);
}
oImage.onmouseout = function() {
auto();
}
进阶4:细节优化:关于我们若是我们刚好按到当前显示的轮播页,这个时间问题,就跟下面一起写了~
进阶5:最后就是将代码模式变为面向对象的模式,使得同一页面上的多个轮播结构能够一起进行。这里的改动比较大,就直接上代码了。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style type="text/css">
* {
margin: 0;
padding: 0;
}
ul, li {
list-style: none;
}
body {
background-color: #000;
}
.wrap {
position: relative;
border: 8px solid #fff;
margin: 100px auto;
width: 400px;
height: 250px;
overflow: hidden;
}
.pic-group {
position: absolute;
}
.pic-group li img {
display: block;
width: 100%;
height: 100%;
}
.num-group {
position: absolute;
bottom: 5px;
right: 0;
height: 20px;
}
.num-group li {
float: left;
width: 20px;
height: 20px;
line-height: 20px;
font-size: 10px;
margin-right: 10px;
background-color: #089e8a;
color: #eee;
text-align: center;
border-radius: 10px;
cursor: pointer;
opacity: 0.8;
}
.num-group li:hover {
box-shadow: 0 0 18px #000;
}
.num-group li.current {
opacity: 1;
color: #089a8a;
background-color: #000;
}
</style>
</head>
<body>
<div class="wrap">
<ul class="pic-group">
<li><img src="./pic1.jpg" alt=""></li>
<li><img src="./pic2.jpg" alt=""></li>
<li><img src="./pic3.jpg" alt=""></li>
<li><img src="./pic4.jpg" alt=""></li>
<li><img src="./pic5.jpg" alt=""></li>
</ul>
<ol class="num-group">
<li class="current">1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ol>
</div>
</body>
<script type="text/javascript">
var Carousel = function(cname) {
this.init(cname);
}
Carousel.prototype = {
init: function(cname) {
let me = this;
me.oWrap = document.getElementsByClassName(cname)[0];
me.oImage = me.oWrap.getElementsByTagName("ul")[0];
me.imageList = me.oImage.getElementsByTagName("li");
me.imageHeight = me.imageList[0].offsetHeight;
me.oNumber = me.oWrap.getElementsByTagName("ol")[0];
me.numberList = me.oNumber.getElementsByTagName("li");
me.index = 0;
me.moveTimer = null;
me.autoTimer = null;
for (let i = 0; i < me.numberList.length; i++) {
me.numberList[i].onmouseover = function() {
me.index = i;
me.Show(i);
}
}
me.Auto();
me.oImage.onmouseover = function() {
clearInterval(me.autoTimer);
}
me.oImage.onmouseout = function() {
me.Auto();
}
},
Show: function(index) {
let me = this;
me.clearClass(index);
me.Move(index);
},
Move(index) {
let me = this;
let target = -index * me.imageHeight;
let now;
let speed;
if (me.moveTimer) clearInterval(me.moveTimer);
me.moveTimer = setInterval(() => {
now = me.oImage.offsetTop;
speed = (target - now) / 10;
speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);
now === target ? clearInterval(me.moveTimer) : me.oImage.style.top = now + speed + "px";
}, 20);
},
Auto() {
let me = this;
me.autoTimer = setInterval(() => {
me.index < me.imageList.length - 1 ? me.index++ : me.index = 0;
me.Show(me.index);
}, 2000);
},
clearClass(index) {
let me = this;
for (let i = 0; i < me.numberList.length; i++) {
me.numberList[i].className = "";
}
me.numberList[index].className = "current";
}
}
window.onload = function() {
new Carousel("wrap");
}
</script>
</html>
原生JS轮播-各种效果的极简实现(二)面向对象版本的实现和优化的更多相关文章
- 原生JS轮播-各种效果的极简实现
寒假持续摸鱼中~此为老早以前博客的重写,当时还是分开写的,这里汇总重写,正好复习一遍~ 春招我来了! 所有有意思的,一股脑先扔进收藏,然后再也不看哈哈,真是糟糕. 今日事,今日毕,说起来容易. 当时竟 ...
- js原生实现轮播图效果(面向对象编程)
面向对象编程js原生实现轮播图效果 1.先看效果图 2.需要实现的功能: 自动轮播 点击左右箭头按钮无缝轮播 点击数字按钮切换图片 分析:如何实现无缝轮播? 在一个固定大小的相框里有一个ul标签,其长 ...
- js___原生js轮播
原生js轮播 作为一名前端工程师,手写轮播图应该是最基本掌握的技能,以下是我自己原生js写的轮播,欢迎指点批评: 首先css代码 a{text-decoration:none;color:#3DBBF ...
- javascript原生js轮播图
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- 原生js轮播图
//用原生js实现了一个简单的轮播图效果 <!DOCTYPE html><html> <head> <meta charset="UTF-8&quo ...
- 原生js轮播以及setTimeout和setInterval的理解
下面这个代码是从一个群下载下来的,为了帮助自己理解和学习现在贴出来,与初学者共勉. <!DOCTYPE html> <html> <head> <meta c ...
- 手把手原生js轮播图
在团队带人,突然被人问到轮播图如何实现,进入前端领域有一年多了,但很久没自己写过,一直是用大牛写的插件,今天就写个简单的适合入门者学习的小教程.当然,轮播图的实现原理与设计模式有很多种,我这里讲的是用 ...
- 用require.js封装原生js轮播图
index.html页面: <!DOCTYPE html><html> <head> <meta charset="UTF-8"> ...
- 原生js轮播图实现
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
随机推荐
- 【遍历二叉树】12往二叉树中添加层次链表的信息【Populating Next Right Pointers in Each Node II】
本质上是二叉树的层次遍历,遍历层次的过程当中把next指针加上去. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ...
- Gym - 100513K :Treeland (按距离还原一棵树)
题意:一个顶点数为N的生成树,对于每个点i,我们按照与i的距离给出顺序,即dis i 1<=dis i 2<=dis i 3<=...,现在让你输出N-1条边,即还原这棵树. 思路: ...
- Python的几种版本的不同实现
Python自身作为一门编程语言,它有多种实现.这里的实现指的是符合Python语言规范的Python解释程序以及标准库等.这些实现虽然实现的是同一种语言,但是彼此之间,特别是与CPython之间还是 ...
- Centos6.5上的iptables
1.Centos6.5默认开启了iptables 当Centos6.5上安装了MySQL后,在远程连接它,如果出现10060的错误,说明iptables在起作用. 关闭iptables即可,sudo ...
- asp.net中日志框架Log4Net的使用
Log4Net是用来记录日志的,可以将程序运行过程中的信息输出到一些地方(文件.数据库.EventLog等),日志就是程序的黑匣子,可以通过日志查看系统的运行过程,从而发现系统的问题.日志的作用:将运 ...
- Java中读取输入方式的性能比较
程序开发过程中,需要从键盘获取输入值是常有的事,但Java它偏偏就没有像c语言给我们提供的scanf(),C++给我们提供的cin()获取键盘输入值的现成函数!Java没有提供这样的函数也不代表遇到这 ...
- Python:os.walk()和os.path.walk()用法
转于:https://www.cnblogs.com/zmlctt/p/4222621.html 博主:zmlctt 一.os.walk() 函数声明:os.walk(top,topdown=True ...
- java代码for循环+缓冲流类
总结:这个结果竟然是对的.我错了. package com.da; //创建一个String对象的数组,然后执行读取文本,把文本每一行存入数组,它将读取到100行 //或直接到你按”stop“才停止, ...
- 加固mysql服务器
实验环境:CentOS7 [root@~ localhost]#yum -y install mariadb-server [root@~ localhost]#mysql_secure_instal ...
- k8s组件简介
Kubernetes is constructed using several components, as follows:f Kubernetes masterf Kubernetes nodes ...