JavaScript之手把手教你做轮播图,前端程序员必会

04-23 1446阅读 0评论

📖 首尾无缝衔接原理

首尾无缝衔接的实现,是第二道分水岭,那首尾无缝衔接,到底是什么意思呢?我相信很多人一直没有搞明白,那我继续用图片给大家解释:

JavaScript之手把手教你做轮播图,前端程序员必会,词库加载错误:未能找到文件“C:\Users\Administrator\Desktop\火车头9.8破解版\Configuration\Dict_Stopwords.txt”。,我们,设置,下载,第1张

请看,当我们的大盒子继续移动,使得最后一张图呈现在小盒子里之后,下一个时刻,我们知道它应该回到第一张图了。那么,传统的做法是:

判断是否是最后一张,如果是最后一张图,那么在播完最后一张图后,滑动到第一张图。

这么做理论上是没有任何问题的,但是当你实际操作的时候,你会发现一个很尴尬的问题,我们演示一下尴尬在哪里:

JavaScript之手把手教你做轮播图,前端程序员必会

看出来了吗?

当我们从最后一张图切换到第一张的时候,尽管还是平滑的,但是由于距离太长了(从末尾的left值到开头的left值,是很长的),所以看到了一串连续的回滚,这就很不理想了,因为我们想要的是和正向播放一样的滚动效果,而不是上面的这种回滚。

于是这就是无缝衔接的诞生原因了,我们可以这么实现无缝衔接:

我们在大容器的首位和最后一位,分别额外放置最后一张图和第一张图,也就是说,我们的大盒子里放的图片是这样的次序:

JavaScript之手把手教你做轮播图,前端程序员必会,词库加载错误:未能找到文件“C:\Users\Administrator\Desktop\火车头9.8破解版\Configuration\Dict_Stopwords.txt”。,我们,设置,下载,第3张

这样做之后,当我们每一次到达图片4时,我们要做如下两件事:

(1) 让大盒子继续正常的向前滑动,滚到"第一张图",就和前面的滑动一致

(2) 滑动结束后,立刻把大盒子的left值设置为显示第一张图的left值,注意,这里不是用动画滚动到第一张图的left值,是瞬间修改!否则就无效了

那为什么这样做,就看起来无缝了呢?

其实这是人眼的欺诈性,我们在看到它滚动到大盒子的最后那个位置,也就是第一张图之后,此时让大盒子的left值做瞬间的修改,由于视觉的短暂停留,我们的视觉上还是第一张图,我们是看不到这中间的修改的,于是视觉上,我们认为是平滑的。


📖 防鼠标连续点击原理

最后,防鼠标重复点击,防止的是重复点击前进、后退的按键,那么它的实现主要基于两个角度共同作用:

(1) 当我们点击了一次前进或后退按钮之后,首先解除外部的定时器和前进、后退按钮的时间绑定。

(2) 当该次动画结束后,在动画的回调函数中恢复定时器和事件绑定。

这部分可能暂时你看不懂,这是因为我们没有封装动画函数,等动画函数封装后,你就能明白这其中的道理,于是我们过渡到下一部分,开始解释动画函数。


II. 封装动画函数


关于动画函数封装的讲解,我不想循规蹈矩的讲思路,而是直接给大家上代码,而后通过代码分析原理:

function animate(obj, target, callback) {

clearInterval(obj);

obj.timer = setInterval(function () {

var step = (target - parseInt(obj.css(“left”))) / 10;

console.log(obj.css(“left”))

console.log(step)

step = step > 0 ? Math.ceil(step) : Math.floor(step);

if (parseInt(obj.css(“left”)) == target) {

clearInterval(obj.timer);

if (callback) {

callback();

}

}

obj.css(“left”, parseInt(obj.css(“left”)) + step + “px”);

}, 30)

}

代码展示之后,我们从代码里面研究动画函数到底干了啥事:

首先,参数有三个,分别是obj,target和callback,我们先一笔带过callback,它就是一个函数,这个函数会在整个动画执行完毕之后调用,因此不需要管这个参数;再一笔带过第一个参数,obj,它就是需要被执行动画的对象,在本例子里,就是外部的大盒子是obj。

target我们不能一笔带过了,它的意思是我们需要的目标位置,这个位置是从left样式的角度给出的,举个例子,例如我们想要大盒子移动到left值为-1000px,那么我们的target传入的参数值就是-1000。

参数说完了,我们看看是怎么实现的平滑滚动:

其实是利用了之前我们讲过的setInterval函数,以30ms的速度,让left值进行不断的修改逼近目标值,而30ms由于很短,所以我们认为是在连续的运动,但其实有30ms的间隔,只不过这个间隔我们是看不出来的。

其中,还有一个细节是:

var step = (target - parseInt(obj.css(“left”))) / 10;

这里有人有看不懂了,说不对啊,难道不应该是等分当前位置与目标位置,而后按照等分的距离移动吗?为什么每一部分的距离要通过这个式子去计算,其实这里涉及到一个逐渐变慢的移动,也就是减速运动,具体的原理,由于不是我们本次讲解的重点,大家可以先不用过度理解,先拿去用。

总之,通过上面封装的动画函数,我们传入一个目标left值,它就可以平滑的移动到目的left值。这个动画函数,大家也可以下载下来保存一下,以后做项目的时候可以直接导入这个函数,就不用再次编码。(这里由于篇幅原因,动画函数的封装我说的不是很细,但是后面会专门出一期文章给大家讲解匀速运动和减速运动的原理)


III. 实现定时和点击滚动


定时和点击滚动,其实是比较简单的部分,但是我还是给大家说一下:

首先是定时,定时其实可以用一个定时器来实现,实现的思路是,给定时器设置一个周期,这个周期就是最终轮播的周期,注意这个周期要大于执行上面那个减速运动的时间,否则会出现滚动混乱,它的实现是这样的:

var timer = null;

// 自动轮播定时器的封装

function startTimer() {

timer = setInterval(function () {

var target = parseInt(container.css(“left”)) - 311;

if (target != -2799) {

// 加解绑定 同下面的解绑

btn_pre.unbind(“click”, display_pre);

btn_next.unbind(“click”, display_next);

animate(container, target, function () {

btn_pre.bind(“click”, display_pre);

btn_next.bind(“click”, display_next);

});

}

else {

btn_pre.unbind(“click”, display_pre);

btn_next.unbind(“click”, display_next);

animate(container, target, function () {

container.css(“left”, “-933px”);

btn_pre.bind(“click”, display_pre);

btn_next.bind(“click”, display_next);

}

}

}, 1800);

}

其中**1800毫秒是通过计算,在本例中能够满足执行动画后还有一小段空闲的一个时间,**大家做项目的时候,可自行测试一下动画的执行时间,并相应调整这个时间。

前进和后退按键的事件封装和绑定类似于定时器,是这样实现的:

// 封装上一幕、下一幕的函数

function display_next()

var target = parseInt(container.css(“left”)) - 311;

stopTimer();

// 暂时解绑定上一幕和下一幕按钮,防止多次点击

btn_next.unbind(“click”, display_next);

btn_pre.unbind(“click”, display_pre);

if (target != -2799) {

animate(container, target, function () {

btn_pre.bind(“click”, display_pre);

btn_next.bind(“click”, display_next);

startTimer();

});

}

else {

animate(container, target, function () {

btn_pre.bind(“click”, display_pre);

btn_next.bind(“click”, display_next);

container.css(“left”, “-933px”);

startTimer();

});

}

function display_pre() {

var target = parseInt(container.css(“left”)) + 311;

// 停止外圈的活动

stopTimer();

// 暂时解绑定上一幕和下一幕按钮,防止多次点击

btn_pre.unbind(“click”, display_pre);

btn_next.unbind(“click”, display_next);

if (target != -622) {

animate(container, target, function () {

btn_pre.bind(“click”, display_pre);

btn_pre.bind(“click”, display_next);

startTimer();

});

}

else {

animate(container, target, function () {

container.css(“left”, “-2488px”);

btn_pre.bind(“click”, display_pre);

btn_pre.bind(“click”, display_next);

startTimer();

});

}

}


IV. 处理第一张图和最后一张图的无缝衔接


第一张图和最后一张图的无缝衔接,原理刚才讲给大家听了,那么代码层面上,是这样实现的:

if (target != -2799) {

animate(container, target, function () {

btn_pre.bind(“click”, display_pre);

btn_next.bind(“click”, display_next);

startTimer();

});

}

else {

animate(container, target, function () {

btn_pre.bind(“click”, display_pre);

btn_next.bind(“click”, display_next);

container.css(“left”, “-933px”);

startTimer();

});

通过判定,最后一张的时候,首先执行动画,并在回调函数中,以迅雷不及掩耳之速度,把left值修改,这样就用人眼的视觉停留,形成了无缝衔接!


V. 处理鼠标快速点击事件


最后,我们要处理一下鼠标快速点击前进后退按钮事件,当然了如果单纯说轮播图,其实已经给大家讲完了,但是我觉得有必要再补充一下这部分,否则鼠标重复点击,会造成轮播的混乱(堤防熊孩子!)

我们按照之前原理分析那样,把防止重复点击分成两部分解决:

// 停止外圈的活动

stopTimer();

// 暂时解绑定上一幕和下一幕按钮,防止多次点击

btn_pre.unbind(“click”, display_pre);

btn_next.unbind(“click”, display_next);

if (target != -622) {

animate(container, target, function () {

btn_pre.bind(“click”, display_pre);

btn_pre.bind(“click”, display_next);

startTimer();

});

}

else {

animate(container, target, function () {

container.css(“left”, “-2488px”);

btn_pre.bind(“click”, display_pre);

btn_pre.bind(“click”, display_next);

startTimer();

});

}

当我们点击了按钮,立刻停掉定时器,同时给按钮本身解绑;而后在回调函数中,恢复定时器和绑定。

另外为了防止点击的同时,刚好轮播图也在因定时器的执行而切换图片,造成混乱,我们给最外面的定时器也做一下处理:

if (target != -2799) {

// 加解绑定 同下面的解绑

btn_pre.unbind(“click”, display_pre);

btn_next.unbind(“click”, display_next);

animate(container, target, function () {

btn_pre.bind(“click”, display_pre);

btn_next.bind(“click”, display_next);

});

}

else {

btn_pre.unbind(“click”, display_pre);

btn_next.unbind(“click”, display_next);

animate(container, target, function () {

container.css(“left”, “-933px”);

btn_pre.bind(“click”, display_pre);

btn_next.bind(“click”, display_next);

});

这样,当每一次轮播图要自己切换的时候,它会把按键解绑,防止两个时间发生冲突。

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

JavaScript之手把手教你做轮播图,前端程序员必会

JavaScript之手把手教你做轮播图,前端程序员必会

JavaScript之手把手教你做轮播图,前端程序员必会

JavaScript之手把手教你做轮播图,前端程序员必会

JavaScript之手把手教你做轮播图,前端程序员必会

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

JavaScript之手把手教你做轮播图,前端程序员必会

JavaScript之手把手教你做轮播图,前端程序员必会

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V:vip1024c 备注前端获取(资料价值较高,非无偿)

JavaScript之手把手教你做轮播图,前端程序员必会

总结
  • 对于框架原理只能说个大概,真的深入某一部分具体的代码和实现方式就只能写出一个框架,许多细节注意不到。

    开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

    • 算法方面还是很薄弱,好在面试官都很和蔼可亲,擅长发现人的美哈哈哈…(最好多刷一刷,不然影响你的工资和成功率???)

    • 在投递简历之前,最好通过各种渠道找到公司内部的人,先提前了解业务,也可以帮助后期优秀 offer 的决策。

    • 要勇于说不,对于某些 offer 待遇不满意、业务不喜欢,应该相信自己,不要因为当下没有更好的 offer 而投降,一份工作短则一年长则 N 年,为了幸福生活要慎重选择!!!

      JavaScript之手把手教你做轮播图,前端程序员必会

      第一次跳槽十分忐忑不安,和没毕业的时候开始找工作是一样的感受,真的要相信自己,有条不紊的进行。如果有我能帮忙的地方欢迎随时找我,比如简历修改、内推、最起码,可以把烦心事说一说,人嘛都会有苦恼的~

      mg-xw2MC58d-1711554122825)]

      总结
      • 对于框架原理只能说个大概,真的深入某一部分具体的代码和实现方式就只能写出一个框架,许多细节注意不到。

        开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

        • 算法方面还是很薄弱,好在面试官都很和蔼可亲,擅长发现人的美哈哈哈…(最好多刷一刷,不然影响你的工资和成功率???)

        • 在投递简历之前,最好通过各种渠道找到公司内部的人,先提前了解业务,也可以帮助后期优秀 offer 的决策。

        • 要勇于说不,对于某些 offer 待遇不满意、业务不喜欢,应该相信自己,不要因为当下没有更好的 offer 而投降,一份工作短则一年长则 N 年,为了幸福生活要慎重选择!!!

          JavaScript之手把手教你做轮播图,前端程序员必会

          第一次跳槽十分忐忑不安,和没毕业的时候开始找工作是一样的感受,真的要相信自己,有条不紊的进行。如果有我能帮忙的地方欢迎随时找我,比如简历修改、内推、最起码,可以把烦心事说一说,人嘛都会有苦恼的~

          祝大家都有美好的未来,拿下满意的 offer。


免责声明
本网站所收集的部分公开资料来源于AI生成和互联网,转载的目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。
文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。

发表评论

快捷回复: 表情:
评论列表 (暂无评论,1446人围观)

还没有评论,来说两句吧...

目录[+]