寒假持续摸鱼中~此为老早以前博客的重写,当时还是分开写的,这里汇总重写,正好复习一遍~
春招我来了!
所有有意思的,一股脑先扔进收藏,然后再也不看哈哈,真是糟糕。 今日事,今日毕,说起来容易。 当时竟然不是用markdown
写的! 当时使用var还需要解决必报的问题!而如今使用ES6的let
,自带领域的感觉就是不一样!
Document
- 1
- 2
- 3
- 4
- 5
一.轮播是什么?
轮播其实就是一个定时变换的广告(卡片?图片?)。
在HTML结构上他们其实是ul
里面的li
。数据层面来说的话,他们就是list
的一条数据。 那么,这其中的变换其实也可以有很多种~你可能会知道现在的 vue-swiper
这么绚丽的轮播效果
- 滑动效果 --- position top位置的变化(意味着所有的
item
单/竖/横向排列) - 缓冲效果 --- 透明度变化(意味着一开始所有的
item
刚开始都是叠在一起的)
二.变化和上述的代码分析 --- 改变 top 则切换图片(我们以滑动效果来开刀)。
如上面的代码,只搭了个结构,我们看到wrap
层被设为了 1.position:relative
和 2.overflow:hidden
,本质上是为了子层的pic-group
服务的,我们设子层pic-group
为3.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给数字们添加上事件。
四.用户体验为王! 下面就开始出现分歧了,如何来切换图片呢?
滑动的轮播
滑动轮播,所有的图原先是排列着的。通过绝对定位来控制。同时外层设置
top变化 -> 切图。overflow:hidden
- 这里的难点主要是我们要在当前的基础
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 < 1return res;}
- 这里的难点主要是我们要在当前的基础
缓冲的轮播
缓冲的轮播,其实就是渐隐效果的实现。这是一个透明度变化。
透明度变化 -> 切图 -> 所有的图原先都是在同一层的,就像叠起来的千层饼。 下面是CSS上的差别。 缓冲轮播的主要改动在这里,因为缓冲轮播是千层饼,所以我们不能让它排列,让它重叠!~
.pic-group li { position: absolute;}.pic-group li.current { opacity: 1;}
在滑动中是下面这样的,注意下面这句话要删掉或是注视了。因为这里的absolute
会影响到子级 li
的absolute
。(加个 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.1const b = -a; // -1 -1 < -0.1const c = 0.6; // 0const d = -c; // -1
- Math.ceil 天花板:返回的永远大于等于原来的(上限)。
const a = 0.1; // 1const b = -a; // 0const c = 0.6; // 1const 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
.