寒假持续摸鱼中此为老早以前博客的重写,当时还是分开写的,这里汇总重写,正好复习一遍

春招我来了!

所有有意思的,一股脑先扔进收藏,然后再也不看哈哈,真是糟糕。

今日事,今日毕,说起来容易。

当时竟然不是用markdown写的!

当时使用var还需要解决必报的问题!而如今使用ES6的let,自带领域的感觉就是不一样!

<!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;
top: -250px;
}
.pic-group li img {
display: block;
width: 100%;
height: 100%;
}
</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>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ol>
</div>
</body>
</html>

一.轮播是什么?

轮播其实就是一个定时变换的广告(卡片?图片?)。

在HTML结构上他们其实是ul里面的li。数据层面来说的话,他们就是list的一条数据。

那么,这其中的变换其实也可以有很多种~你可能会知道现在的 vue-swiper这么绚丽的轮播效果

  • 滑动效果 --- position top位置的变化(意味着所有的item单/竖/横向排列)
  • 缓冲效果 --- 透明度变化(意味着一开始所有的item刚开始都是叠在一起的)

二.变化和上述的代码分析 --- 改变 top 则切换图片(我们以滑动效果来开刀)。

如上面的代码,只搭了个结构,我们看到wrap层被设为了 1.position:relative2.overflow:hidden,本质上是为了子层的pic-group服务的,我们设子层pic-group3.position:absolute,这样的话 3 就可以根据 1和2 来达到 => 改变top位置(top位置为图片高度的 n 倍哦!)

为了极简!!!!!我这里只设置了 .pic-group li img 的宽高。一般情况下其实每个外层元素都会写一个具体的高宽的。

  • 为什么我给.pic-group li img 设置 display:block ?

    实际上呢,img 它是行内元素。行内元素有默认的 4px 边距。去除的办法有 font-size:0等诸多方法,这里我追求代码极简。所以一句话,变成块级元素吧少年。

  • 为什么我只给.pic-group li img 设置了 宽高?

    依旧为了极简~实际上应该根据要求都设置一下宽高的。这里的结果就是

    a.内层 img 宽高继承了最外的 400 250

    =>

    b.继而作为 li 的子层撑开了 li

    =>

    c.li 再继续撑开 .pic-group

    =>

    d.因为.pic-group的高度被老大的overflow:hidden限制了,最后就变成了一张图片。

    原来的样子应该是好几层图片~

三.变化的契机 --- 谁来改变 top?

我们给我们的轮播案例加上数字,通过点击数字来按下改变世界的开关!

首先这是我们给数字添加的样式

.num-group {
position: absolute;
bottom: 0;
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;
}

这里就不多解释了,上面是是样式的部分。

下面是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++) {
// 关键:我们要把我们的 索引index 传进 onclick/onmouseover 里面
numList[i].onclick = () => {
// numList[i].className = "current";
clearNumState();
numList[i].className = "current";
const topValue = - i * 250;
oImage.style.top = topValue + "px";
}
}
// 每次新点击 num,先置空所有list的current的类,此后再添加当前索引
const clearNumState = () => {
for (const item of numList) {
item.className = "";
}
}
通过上面的代码我们已经可以实现点击数字按钮进行对图片的切换了.

改变世界的最终还是 JS,而不是CSS,我们用JS给数字们添加上事件。



四.用户体验为王! 下面就开始出现分歧了,如何来切换图片呢?

  • 滑动的轮播

滑动轮播,所有的图原先是排列着的。通过绝对定位来控制。同时外层设置overflow:hidden

top变化 -> 切图。

* 这里的难点主要是我们要在当前的基础top上滚动,并且滚动的效果要平滑。

// 首先,获取我们要改变的元素
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++) {
// 关键:我们要把我们的 索引index 传进 onclick/onmouseover 里面
numList[i].onmouseover = () => {
clearNumState();
show(i);
}
}
// 每次新点击 num,先置空所有list的current的类,此后再添加当前索引
const clearNumState = () => {
for (const item of numList) {
item.className = "";
}
}
// 滑动轮播,原则: 每次获取当前位置,每次滚动的时间应该一致。(这是效果)
// 即是说,差的越远,滚动越快。
// obj.offsetTop 指的是 obj 距离上方或者父级元素(position非static)的位置。
// 整型。单位像素。属性为只读!!只读!!只读!!
let timer = null;
const show = (index) => {
if (timer) clearInterval(timer);
const pre = oImage.offsetTop;
let now = pre;
const pos = -250 * index;
const dis = pos - pre;
const avg = dis / 10;
timer = setInterval(() => {
if (now === pos) {
clearInterval(timer);
} else {
now += avg;
console.log(now);
oImage.style.top = now + "px";
}
}, 20);
}

通过以上的代码,我们基本能够实现滑动轮播了,但是滑动的太僵硬了,没有一种平时物体滑动的那种惯性。

简单的来说,它是匀速运动的!

我们要让它先 加速运动 -> 匀速运动 -> 减速运动.

So!修改代码如下

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);
// 为什么呢?唉,基础差导致这里还写错了。
// 如果是 -0.1,我们要让它为 -1,所以这里要用地板(返回的值更小)
// -1 < -0.1
// 如果是 0.1, 我们要让它为 1,所以这里要用天花板(返回的值更大)
// 0.1 < 1
return res;
}

滑动轮播完整代码

  • 缓冲的轮播

缓冲的轮播,其实就是渐隐效果的实现。这是一个透明度变化。

透明度变化 -> 切图 -> 所有的图原先都是在同一层的,就像叠起来的千层饼。

下面是CSS上的差别。

缓冲轮播的主要改动在这里,因为缓冲轮播是千层饼,所以我们不能让它排列,让它重叠!~

.pic-group li {
position: absolute;
}
.pic-group li.current {
opacity: 1;
}

在滑动中是下面这样的,注意下面这句话要删掉或是注视了。因为这里的absolute会影响到子级 liabsolute。(加个 li, 完事儿)

.pic-group {
position: absolute;
}

然后下面是JS的一些差别,这个比较简单。如果滑动的话,是只要控制 外层的 ul滚动就可以了

缓冲轮播的话则是要控制 imageList里面的每一张图的透明度,所以这里多获取一个东西。

const numList = oNumber.getElementsByTagName("li");

缓冲轮播完整代码

五.重要知识点!!

时代在进步,刀耕火种的JS --- 谈谈重写之前用var,重写之后用let的变化

不用纠结闭包的问题了!!!!

哦草!

我他妈竟然忘了!

秀一秀古老的onclick

  for (var i = 0; i < oList.length; i++) {
oList[i].onclick = function () {
console.log(i);
}
}

这样写的后果是,无论怎么写,最后的i的结果都会是oList.length

闭包(匿名函数)要使用外部作用于中变量的结果,这也是由于匿名函数本身无法传递参数,

故无法维护自己的作用域。

当函数调用外部变量就构成一个闭包,里面的变量会受到别的地方的影响。不可抗力!所以解决的方式是:构建一个只有匿名函数本身才可以访问的闭包,保存只供本身使用的变量。

  • 古老的解决方案一.使用过去的 function 式函数,将 当前的 i 赋值给 index
  for (var i = 0; i < oList.length; i++) {
oList[i].index = i;
oList[i].onclick = function () {
console.log(this.index);
}
}
  • 古老的解决方案二.使用匿名函数的方式隔离外部的i => 匿名函数:这就是我的领域,魔法-画地为牢!!!
  for (var i = 0; i < oList.length; i++) {
(function (i) {
oList[i].onclick = () => {
console.log(i);
}
})(i);
}
  • 然而我是现代人,能坐车我干嘛要走路???So !
  for (let i = 0; i < oList.length; i++) {
oList[i].onclick = () => {
console.log(i);
}
}

正所谓四两拨千斤!什么?你说没差别? var -> let

归根结底还是作用域的问题,let 是自带领域的。

六.相关知识点- Math.floor()、Math.ceil()、Math.round

我们在滑动轮播中为了达到距离越远滑动越快的效果。

我们的解决方案:

令每一次的 interval 时间一致。

改变每一次的移动距离来实现。

每次的移动距离由 当前offsetTop 和 目的地 决定。

每次的移动距离都有最小值。

同时怕计算得出的值相加会超出原先设定的 目的地。

所以使用到了上面的两个函数。(目的地和当前的offsetTop的差可正可负).

  • Math.floor 地板:返回的永远小于等于原来的(下限)。
const a = 0.1; // 0      0 < 0.1
const b = -a; // -1 -1 < -0.1
const c = 0.6; // 0
const d = -c; // -1
  • Math.ceil 天花板:返回的永远大于等于原来的(上限)。
const a = 0.1; // 1
const b = -a; // 0
const c = 0.6; // 1
const d = -c; // 0
  • Math.round 返回最近的。
const a = 0.1; // 0 四舍
const b = -a; // -0 依旧四舍
const c = 0.6; // 1 五入
const d = -c; // -1 五入

当我们的移动距离为 -0.1 的时候,用 Math.ceil 意味着它的 top 永远为0了QAQ.

当我们的移动距离为 0.1 的时候,用 Math.floor 也以为这 移动top 为0.

原生JS轮播-各种效果的极简实现的更多相关文章

  1. 原生JS轮播-各种效果的极简实现(二)面向对象版本的实现和优化

    之前写了一篇原生JS轮播,不过是非面向对象的,并且也没有添加上自动轮播.这里来写一下如何优化和进阶. 这里简单地介绍一下之前的代码,这是html结构 <body> <div clas ...

  2. js原生实现轮播图效果(面向对象编程)

    面向对象编程js原生实现轮播图效果 1.先看效果图 2.需要实现的功能: 自动轮播 点击左右箭头按钮无缝轮播 点击数字按钮切换图片 分析:如何实现无缝轮播? 在一个固定大小的相框里有一个ul标签,其长 ...

  3. js___原生js轮播

    原生js轮播 作为一名前端工程师,手写轮播图应该是最基本掌握的技能,以下是我自己原生js写的轮播,欢迎指点批评: 首先css代码 a{text-decoration:none;color:#3DBBF ...

  4. javascript原生js轮播图

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  5. 原生js轮播图

    //用原生js实现了一个简单的轮播图效果 <!DOCTYPE html><html> <head> <meta charset="UTF-8&quo ...

  6. 原生js轮播以及setTimeout和setInterval的理解

    下面这个代码是从一个群下载下来的,为了帮助自己理解和学习现在贴出来,与初学者共勉. <!DOCTYPE html> <html> <head> <meta c ...

  7. 手把手原生js轮播图

    在团队带人,突然被人问到轮播图如何实现,进入前端领域有一年多了,但很久没自己写过,一直是用大牛写的插件,今天就写个简单的适合入门者学习的小教程.当然,轮播图的实现原理与设计模式有很多种,我这里讲的是用 ...

  8. 用require.js封装原生js轮播图

    index.html页面: <!DOCTYPE html><html> <head> <meta charset="UTF-8"> ...

  9. 原生js轮播图实现

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

随机推荐

  1. FFMPEG实现H264的解码(从源代码角度)

    农历2014年底了,将前段时间工作中研究的FFMPEG解码H264流程在此做一下整理,也算作年终技术总结了! H264解码原理: H264的原理参考另一篇博文 http://blog.csdn.net ...

  2. 使用pjsip传输已经编码的视频,源码在github

    pjsip功能很强,做sip rtp语音通话库首选.在2.0之后,也支持视频.不过,它的视频功能缺省是从视频设备采集,然后进行编译,再发送出去的.假设,我们已经有了视频源,比如IP摄像机,不需要采集和 ...

  3. CodeForces - 1019D(BZOJ3707圈地):Large Triangle (几何,找面积为S的三角形)

    题意:给定平面上N个点,问是否存在三角形,其面积为S. 思路:选择Y轴,枚举这个Y轴,面积大小只与|y-Y|有关,然后二分,具体的可以先去做BZOJ3707. 具体的: 1,先对点排序,X坐标为第一关 ...

  4. ACM学习历程—POJ3090 Visible Lattice Points(容斥原理 || 莫比乌斯)

    Description A lattice point (x, y) in the first quadrant (x and y are integers greater than or equal ...

  5. rsync 介绍和参数说明

    Rsync 介绍: 我们经常需要在不同目录或者服务器之间做文件同步和更新,Linux提供了很多内置命令可以使用比如scp等等,但是今天我们介绍一个更加强大的工具rsync.rsync 命令是一个远程同 ...

  6. AI-Info-Micron-Menu:Products

    ylbtech-AI-Info-Micron-Menu:Products 我们制造业界最广泛的存储器和存储技术产品组合:DRAM,NAND,NOR和3D XPoint™存储器. 凭借紧密的行业合作伙伴 ...

  7. Makefile经典教程

    转自:http://blog.csdn.net/ruglcc/article/details/7814546/       makefile很重要 什么是makefile?或许很多Winodws的程序 ...

  8. 【jQuery】praseFloat()方法的用法及注意事项

    [jQuery]praseFloat()方法的用法及注意事项 praseFloat():  用于解析一个字符串,并返回一个浮点数 语法:                praseFloat(strin ...

  9. jquery获取设置服务器控件的方法

    jquery获取设置服务器控件的方法 获取TextBox,HiddenField,Label的值.例如: <asp:TextBox ID="txtBoxID" runat=& ...

  10. C语言入门题

    1. 如下语句通过算术运算和逻辑运算之后 i 和 j 的结果是()         int i=0;         int j=0;         if((++i>0)||(++j>0 ...