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

其实,不需要借助于什么复杂的技术,仅仅通过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制作滚动广告板的更多相关文章
- 基于html5页面滚动背景图片动画效果
基于html5页面滚动背景图片动画效果是一款带索引按钮的页面滚动动画特效代码.效果图如下: 在线预览 源码下载 实现的代码. html代码: <div id="fullpage&q ...
- 基于JQuery实现滚动到页面底端时自动加载更多信息
基于JQuery实现滚动到页面底端时自动加载更多信息 关键代码: 代码如下: var stop=true; $(window).scroll(function(){ totalheight = par ...
- 【转】基于laravel制作APP接口(API)
这篇文章主要介绍了基于laravel制作APP接口(API)的相关资料,需要的朋友可以参考下 前期准备 前言,为什么做以及要做个啥本人姓小名白,不折不扣编程届小白一名,但是自从大一那会儿接触到编程这件 ...
- 基于CSS3制作的鼠标悬停动画菜单
之前分享了好多款css3实现的鼠标悬停效果.今天再给大家带来一款基于CSS3制作的鼠标悬停动画菜单.这款菜单适用浏览器:360.FireFox.Chrome.Safari.Opera.傲游.搜狗.世界 ...
- 制作滚动视图(ScrollView)
怎样判断是否应当使用滚动视图 所谓的滚动视图,是指一个可以滑动的视窗,视窗大小和位置固定不变,视窗内的内容用户可以通过手指滑动或者拖动滚动天来进行滚动浏览. 滚动视图的目的是为了解决同类内容过多,一个 ...
- Docker系列06—基于容器制作镜像并上传到Docker Registry
本文收录在容器技术学习系列文章总目录 1.制作镜像 1.1 镜像的生成途径 基于容器制作 dockerfile,docker build 本篇主要详细讲解基于容器制作镜像:基于dockerfile 制 ...
- 基于jQuery实现滚动新闻代码下载
分享一款基于jQuery实现滚动新闻代码下载.这是一款基于bootstrup 3实现的响应式jQuery滚动新闻插件.效果图如下: 在线预览 源码下载 实现的代码. html代码: <div ...
- 利用jquery制作滚动到指定位置触发动画
<!DOCTYPE html><html><head> <meta charset="utf-8"> <title>利用 ...
- Expression Design与Blend制作滚动的小球动画教程
原文:Expression Design与Blend制作滚动的小球动画教程 一,开发工具 Microsoft Expression Design & Blend 4.0 (3.0亦可). 这两 ...
随机推荐
- C#中base的作用
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threa ...
- NSCache 缓存
前言 NSCache 是苹果提供的一个专门用来做缓存的类,当内存 "不足" 或超过限制的时候,会自动清理缓存,使用时可以指定缓存的数量和成本. 用法与 NSMutableDicti ...
- Python爬虫从入门到放弃 之 Scrapy框架中Download Middleware用法
这篇文章中写了常用的下载中间件的用法和例子.Downloader Middleware处理的过程主要在调度器发送requests请求的时候以及网页将response结果返回给spiders的时候,所以 ...
- how to use windows azure market
here is the sample. namespace USCrime2006and2007 { class Program { static void Main(string[] args) { ...
- 降维之主成分分析法(PCA)
一.主成分分析法的思想 我们在研究某些问题时,需要处理带有很多变量的数据,比如研究房价的影响因素,需要考虑的变量有物价水平.土地价格.利率.就业率.城市化率等.变量和数据很多,但是可能存在噪音和冗余, ...
- 关于在VS 2013 Reshaper 中不能使用Alt+Enter 的解决
新装Vs 2013 ,感觉还是不错,但是很恶心的是居然,Resharper 万能的快捷键不能用,让洒家真是恶心极了. 通过Google 在StackOverflow 上发现了解决方法,但好像看他的 ...
- 谈谈easyui datagrid 的数据加载
文章目录 1url方式加载数据 1.1调用方式 1.2相关方法 1.3二次加载问题 2加载本地数据方式 2.1调用方式 2.2如何分页 2.3加载中效果 2.4如何不统计总数 这篇文章只谈jQuery ...
- gym 102082B dp
和51nod1055 一样: #include<iostream> #include<cstdio> #include<algorithm> #include< ...
- Fast Matrix Operations UVA - 11992 线段树
题意翻译 有一个r行c列的全0矩阵,有以下三种操作. 1 X1 Y1 X2 Y2 v 子矩阵(X1,Y1,X2,Y2)的元素加v 2 X1 Y1 X2 Y2 v 子矩阵(X1,Y1,X2,Y2)的元素 ...
- 1.1、Logistics Regression模型
1.线性可分VS线性不可分 对于一个分类问题,通常可以分为线性可分与线性不可分两种 .如果一个分类问题可以使用线性判别函数正确的分类,则称该问题为线性可分.如图所示为线性可分,否则为线性不可分: 下图 ...