很多网站在其门户页面的上方正中央都会放置一个滚动广告板,用于显示一些推荐信息,用户点击即可进入浏览。比较常见的就是各个公司的官网,电商网站的首页等。

下面是天猫的滚动广告板截图。

其实,不需要借助于什么复杂的技术,仅仅通过setTimeout函数,就能实现这种滚动广告板的效果。

分析

仔细观察这个滚动广告版,我们发现,其功能无非就两点:

  • 无限循环的不停滚动显示每一条广告
  • 当点击某一个广告的索引时,以那条广告为起点,无限循环滚动

先分析一下第一个功能点。

要做到无限循环的不停滚动显示每一条广告,那么只需要关注两个相邻广告页的切换(暂且称为函数doSwitch),然后通过设置定时任务不停的运行doSwitch就可以了。因此,我们有了一个基本的雏形:

function doSwitch() {
//switch adjacent ad pages
} function autoSwitch() {
doSwitch();
}; setTimeout(autoSwitch, someInterval)

现在,我们只需要重点关注switch的实现就可以了。

上面截图中,广告页通过淡入淡出效果来进行切换,很容易就联想到css3中的opacity属性(天猫也是这么实现的),但是考虑到IE8的存在,opacity就不适用了,由于具体的切换效果与今天的主题关系不大,所以改成了横向滚动切换效果。

横向滚动有很多种实现效果,最直接的方式,就是通过margin-left来实现。设广告页的宽度为w,以当前广告页左边的边框为基准线,将当前广告页的margin-left由0逐渐递减至-w,将下一广告页的margin-left由w逐渐减至0(广告板的父容器设置overflow:hidden)。因此,doSwitch可以简单实现如下:

function doSwitch() {
var curPage = document.getElementById(curPageId),
nextPage = document.getElementById(nextPageId);
curPage.style.marginLeft -= step; // 此处忽略了单位处理
nextPage.style.marginLeft -= step; if (nextPage.style.marginLeft > 0) {
setTimeout(doSwitch, someInnerInterval);
} else {
setTimeout(autoSwitch, someInterval);
}
}

由于切换效果的时间应该远小于广告停留的时间,所以此处someInnerInterval小于someInterval.

注意到,每次广告页的切换,广告页下方的索引按钮也会跟着切换,因此,上方的autoSwitch函数中还要增加一项设置当前选中索引的功能,暂且成为setCurIndex函数,则autoSwitch实现修改如下:

function autoSwitch() {
setCurIndex();
doSwitch();
}

到此,无限循环滚动显示广告的功能就完成了.

上面的代码只做基本原理介绍,实际操作过程中还有很多细节需要处理。

再看第二个功能点。

当用户点击某个广告页的索引时,当前广告会立即被切换到选中的广告页,并从选中的广告页开始循环滚动。咋一看跟功能点一很像,似乎只需要在用户点击某个索引的时候将当前广告页设置为用户选中的广告页就可以了。但是很多时候,最直接的想法往往是不对的,这里需要考虑到setTimeout的原理。

setTimeout函数的正确使用姿势应该像下面的代码一样:

var timeout = setTimeout(function () {
//do something after at least 1s
}, 1000); // clearTimeout(timeout); //cancel setTimeout handler function

我们知道,JavaScript是单线程的,定时器只是计划代码在未来的某个时间点执行,但是,执行时机是不能保证的。在页面的生命周期中,不同时间可能有其他代码控制着JavaScript线程。例如在页面下载完后的代码运行、事件处理程序、Ajax请求的回调函数等都必须使用同样的线程来执行。实际上,浏览器负责进行排序,指派某段代码在某个时间点运行的优先级。在浏览器内部管理着一个代码队列,随着页面生命周期的推移,代码会按照执行顺序添加入队列。例如,当某个按钮被按下时,它的事件处理程序代码就会被添加到队列中,并在下一个可能的时间里执行。当接到某个Ajax响应时,回调函数的代码会被添加到队列。浏览器通过事件循环的机制从这个队列中取出处理函数代码并执行。



定时器对队列的工作方式是,在指定时间过去后,将代码插入队列。请注意,给队列添加代码并不意味着它会立即执行,而只能表示它会尽快执行。与setTimeout函数成对出现的是clearTimeout函数,用于取消setTimeout设置的延时执行的函数。该函数只接受一个参数,那就是setTimeout返回的延时调用ID。

回到刚才的问题中,功能一中,通过setTimeout函数,不停的将doSwitch和autoSwitch函数添加到队列中,如果当用户点击某个广告页索引时,只是简单的将当前广告设置为选中的广告页,然后调用autoSwitch的话,将会导致两个无限循环滚动同时运行,这必将导致广告页显示的混乱。

那么如何解决这个问题呢?

当用户点击某个索引时,我们只需要终止之前一直运行的循环滚动,然后开启新的循环滚动即可。那么问题就聚焦在如何终止上一个循环滚动上面来了。实际上,我们可以通过clearTimeout来实现。我们只需要在doSwitch中添加一个状态检测,如果用户当前点击了某个索引,则退出函数执行。样例如下:

function doSwitch() {
if (paused) {
return;
} // other
}

这时候,我们只需要在用户点击某个广告索引时,设置paused为true,然后在新一轮的循环滚动开始前将paused设置为false就可以了。代码如下:

indexDom.onclick = function () {
setCurIndex();
paused = true; setTimeout(function () {
paused = false;
autoSwitch();
}, someInterval);
}

需要注意的一点是,这里的someInterval与功能点一中的someInterval要保持相同。由于someInnerInterval小于someInterval,所以在下一个循环滚动开始之前,上一个循环滚动已经停止了。

到此,实际上基本功能就已经结束了,但是在完成基本功能之后,我们还要照顾到异常场景的存在。这里就需要处理短时间内连续点击不同索引的情况。

其实也很简单,只需要在onclick时间处理函数中保存一个curClick索引,然后在延时函数中比对curClick是否与当前的curIndex一致就可以了。

所以上面的onclick可以改写如下:

indexDom.onclick = function () {
var curClick = indexDom["data-index"]; //get the index of indexDom
setCurIndex();
curIndex = curClick;
setTimeout(function () {
if (curIndex !== curClick) {
return;
}
paused = true;
setTimeout(function () {
paused = false;
authSwitch();
}, someInterval)
}, 0);
}

到此,整个滚动广告板就做完了,但是实现功能仅仅是第一步,下一步还需要将其组件化,将一些内部状态隐藏,抽象出组件接口。在使用的时候,只需要实例化一个组件实例,然后使用必要的数据调用组件接口就可以了。

下面是实现的效果图:

源代码稍后放出:)

基于setTimeout制作滚动广告板的更多相关文章

  1. 基于html5页面滚动背景图片动画效果

    基于html5页面滚动背景图片动画效果是一款带索引按钮的页面滚动动画特效代码.效果图如下: 在线预览   源码下载 实现的代码. html代码: <div id="fullpage&q ...

  2. 基于JQuery实现滚动到页面底端时自动加载更多信息

    基于JQuery实现滚动到页面底端时自动加载更多信息 关键代码: 代码如下: var stop=true; $(window).scroll(function(){ totalheight = par ...

  3. 【转】基于laravel制作APP接口(API)

    这篇文章主要介绍了基于laravel制作APP接口(API)的相关资料,需要的朋友可以参考下 前期准备 前言,为什么做以及要做个啥本人姓小名白,不折不扣编程届小白一名,但是自从大一那会儿接触到编程这件 ...

  4. 基于CSS3制作的鼠标悬停动画菜单

    之前分享了好多款css3实现的鼠标悬停效果.今天再给大家带来一款基于CSS3制作的鼠标悬停动画菜单.这款菜单适用浏览器:360.FireFox.Chrome.Safari.Opera.傲游.搜狗.世界 ...

  5. 制作滚动视图(ScrollView)

    怎样判断是否应当使用滚动视图 所谓的滚动视图,是指一个可以滑动的视窗,视窗大小和位置固定不变,视窗内的内容用户可以通过手指滑动或者拖动滚动天来进行滚动浏览. 滚动视图的目的是为了解决同类内容过多,一个 ...

  6. Docker系列06—基于容器制作镜像并上传到Docker Registry

    本文收录在容器技术学习系列文章总目录 1.制作镜像 1.1 镜像的生成途径 基于容器制作 dockerfile,docker build 本篇主要详细讲解基于容器制作镜像:基于dockerfile 制 ...

  7. 基于jQuery实现滚动新闻代码下载

    分享一款基于jQuery实现滚动新闻代码下载.这是一款基于bootstrup 3实现的响应式jQuery滚动新闻插件.效果图如下: 在线预览   源码下载 实现的代码. html代码: <div ...

  8. 利用jquery制作滚动到指定位置触发动画

    <!DOCTYPE html><html><head> <meta charset="utf-8"> <title>利用 ...

  9. Expression Design与Blend制作滚动的小球动画教程

    原文:Expression Design与Blend制作滚动的小球动画教程 一,开发工具 Microsoft Expression Design & Blend 4.0 (3.0亦可). 这两 ...

随机推荐

  1. 关于.net DateTime 的一些事儿

    最近开发的过程中遇到一种情况,在.net 程序中获取的Datetime格式的时间,在存入SQL server中,毫秒部分丢失. 这个是个很奇怪的状况,因为在Debug的时候,Datetime的变量的确 ...

  2. Mysql避免重复插入记录方法

    一.mysql replace用法 1.replace into  replace into table (id,name) values('1','aa'),('2','bb')  此语句的作用是向 ...

  3. Jquery 页面元素事件绑定

    场景: 用一个Table来展示数据信息列表,通过鼠标点击Table中的Tr来获取到当前选中的数据行信息. <table class="Table" width="1 ...

  4. javascript webstorm用法

    javascript  webstorm用法 一.什么是webstorm?       WebStorm 是jetbrains公司旗下一款JavaScript 开发工具.被广大中国JS开发者誉为“We ...

  5. day2学python 数据类型+深浅拷贝+循环

    数据类型+深浅拷贝+循环 别的语言的数组 python不用定义 直接使用 color=['红','橙','黄','绿','青','蓝','紫'] print(color[1:3]) //打印[1,3) ...

  6. React进阶篇(2) -- Redux

    前言 如果还不知道为什么要使用Redux,说明你暂时还不需要它. 三大原则 单一数据源 整个应用的 state 被储存在一棵 object tree 中,并且这个 object tree 只存在于唯一 ...

  7. 【bzoj1014】: [JSOI2008]火星人prefix 平衡树-字符串-hash-二分

    [bzoj1014]: [JSOI2008]火星人 用平衡树维护字符串的hash 然后询问的时候二分一下就好了 /* http://www.cnblogs.com/karl07/ */ #includ ...

  8. 【微服务】之七:轻松搞定SpringCloud微服务-API权限控制

    权限控制,是一个系统当中必须的重要功能.张三只能访问输入张三的特定功能,李四不能访问属于赵六的特定菜单.这就要求对整个体系做一个完善的权限控制体系.该体系应该具备针区分用户.权限.角色等各种必须的功能 ...

  9. Tomcat类加载机制触发的Too many open files问题分析(转)

    https://blog.csdn.net/ctrip_tech/article/details/53337137 说起Too many open files这个报错,想必大家一定不陌生.在Linux ...

  10. github上传Python被识别为css--解决

    在项目根目录新建文件.gitattributes 添加如下: *.css linguist-language=python把.css结尾的文件识别为python语言