移动轮播图我看到两类,

一款是无线天猫的m.tmall.com和携程,实现了无缝轮播。

一款是蘑菇街的,没有实现无缝轮播。

我自己重写一个,类似天猫。

1.页面代码

 <!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="UTF-8">
<head>
<meta charset="UTF-8">
<title>基于jQuery的移动轮播图(支持触屏)</title>
<meta name="viewport" content="maximum-scale=1,initial-scale=1,user-scalable=0"> <style type="text/css"> img
{
border:0;
*display:inline;
}
li
{
border:0;
list-style-type :none;
}
ul
{
list-style:none;
margin:0;
padding:0;
}
body{
overflow-x:hidden;
margin:0 auto;
padding:0;
width: 100%;
height: 100%;
}
.WSCSlideWrapper{
width:100%;
position: relative;
margin:0 auto;
//cursor:move;
}
#WSCSlideWrapperTwo{
width:50%;
position: relative;
margin:10px auto;
//cursor:move;
} </style>
<script type="text/javascript" src="http://sandbox.runjs.cn/uploads/rs/215/auboqjjr/jquery-1.8.2.min.js"></script> <script type="text/javascript" src="http://sandbox.runjs.cn/uploads/rs/215/auboqjjr/touchslide-1.1.js"></script>
</head>
<body> <div class="WSCSlideWrapper" id="WSCSlideWrapper" > <div> <a href="http://www.baidu.com"><img src="http://sandbox.runjs.cn/uploads/rs/215/auboqjjr/1.jpg" /></a>
<a href="http://m.tmall.com"><img src="http://sandbox.runjs.cn/uploads/rs/215/auboqjjr/2.jpg" /></a>
<a href="http://huaban.com"><img src="http://sandbox.runjs.cn/uploads/rs/215/auboqjjr/3.jpg" /></a>
</div> </div> <div class="WSCSlideWrapper" id="WSCSlideWrapperTwo" >
<div>
<a><img src="http://sandbox.runjs.cn/uploads/rs/215/auboqjjr/1 (1).jpg" /></a>
<a><img src="http://sandbox.runjs.cn/uploads/rs/215/auboqjjr/1 (2).jpg" /></a>
<a><img src="http://sandbox.runjs.cn/uploads/rs/215/auboqjjr/1 (3).jpg" /></a>
<a><img src="http://sandbox.runjs.cn/uploads/rs/215/auboqjjr/1 (4).jpg" /></a>
</div> </div>
<script type="text/javascript"> $(document).ready(function(){ $('.WSCSlideWrapper').height($('.WSCSlideWrapper').width()*0.3);
$('#WSCSlideWrapperTwo').height($('#WSCSlideWrapperTwo').width()*1.5);
$('.WSCSlideWrapper').touchslide({timecontrol:3000,animatetime:300,direction:'left',navshow:true,canvassuport:true});
}); </script>
</body>
</html>

2.js插件代码

 /*
* touchslide 1.1
* Copyright (c) 2014 BowenLuo http://www.luobo.com/
* Date: 2014-06-08
* Example:$('.WSCSlideWrapper').touchslide({timecontrol:3000,animatetime:300,direction:'left',navshow:true,canvassuport:true});
* Update:增加对IE9+等非Safari内核浏览器的鼠标拖动图片功能
*/
(function($){
$.fn.touchslide = function(options){
var defaults = {
timecontrol:3000,//图片停留时间
animatetime:300, //图片滑动所需时间
direction:'left', //轮播方向
navshow:true,//是否显示图片导航栏
canvassuport:true//图片导航栏是否开启cavas绘制圆
}
var options = $.extend(defaults, options);
var timecontrol = options.timecontrol||3000;
var animatetime = options.animatetime||300;
var direction = options.direction||'left';
var navshow = options.navshow;
this.each(function(){
var slideWrapper=$(this);
var slideImgWrapper = slideWrapper.children('div:first');
var slideAs = slideImgWrapper.children('a');
var slideImgs = slideAs.children('img');
var imgcount = slideImgs.length;
var imgcountrealy = slideImgs.length;
var navimgs;
var circlewrapper;
var circles;
var canvassuport = true;
var circler = 0;
if(imgcount>1){
$((slideImgWrapper.html().split("/a>")[0]+"/a>"+slideImgWrapper.html().split("/a>")[1]+"/a>")).insertAfter(slideAs.last());
if(navshow){
$("<div class='navimgs'></div>").insertAfter(slideImgWrapper);
navimgs = slideWrapper.children('div:last');
navimgs.append("<div class='circlewrapper'></div>");
circlewrapper = navimgs.children('div:first');
for(var i=0;i<imgcountrealy;i++){
circlewrapper.append("<canvas class='circle' width='15' height='15'></canvas>");
}
circles = circlewrapper.children('canvas');
var myCanvas = circles[1];
if (!myCanvas.getContext)
{
canvassuport =false;
}else
{
canvassuport =options.canvassuport;
}
}
}
slideAs = slideImgWrapper.children('a');
slideImgs = slideAs.children('img');
imgcount = slideImgs.length;
var slideWrapperWidth = slideWrapper.width();
var slideWrapperHeight = slideWrapper.height();
slideWrapper.css({"overflow":"hidden","width":slideWrapperWidth,"height":slideWrapperHeight});
slideImgWrapper.css({'position':"absolute","z-index":"1","overflow":"hidden","width":slideWrapperWidth*imgcount,"height":slideWrapperHeight});
slideAs.css({'position':"relative","overflow":"hidden","float":"left","width":slideWrapperWidth,"height":slideWrapperHeight});
slideImgs.css({'position':"relative","z-index":"1","width":slideWrapperWidth,"height":slideWrapperHeight});
if(typeof(navimgs)!=='undefined'){
if(navshow){
navimgs.css({"position":"absolute","z-index":"3","overflow":"hidden","display":"block","width":slideWrapperWidth,"height":slideWrapperWidth*0.05,"bottom":"0"});
if(slideWrapperWidth*0.05>15){
navimgs.height(24);
}
circlewrapper.css({"position":"relative","overflow":"hidden","width":(slideWrapperWidth*0.05*imgcountrealy),"height":slideWrapperWidth*0.04,"margin":"auto"});
circles.css({'position':"relative","float":"left","max-width":15,"max-height":15,"margin-left":slideWrapperWidth*0.01});
if(slideWrapperWidth*0.03>15){
circler=15;
}else{
circler = slideWrapperWidth*0.03;
}
circles.attr("width",circler);
circles.attr("height",circler);
canvacircle(0);
for(var i=0;i<circles.length;i++){
navclick(i);
}
}else{
navimgs.css({"display":"none"});
}
}
if(imgcount<4){
return;
}
slideImgWrapper.css({'left':-slideWrapperWidth});
var st;
var sts;
sts = setTimeout(function(){
timedCount();
},timecontrol); slideWrapper.hover(function(){
stopAll();
},
function(){
sts = setTimeout(function(){
timedCount();
},timecontrol);
});
mouseDrag(slideWrapper);
touchDrag(slideWrapper); function timedCount()
{
if(direction=='left'){
turnleft();
}if(direction=='right'){
turnright();
}
clearTimeout(st);
st=setTimeout(function(){
timedCount();
},timecontrol);
} function stopCount()
{
if (st !=""){
clearTimeout(st);
}
} function stopAll()
{
stopCount();
clearTimeout(sts);
slideImgWrapper.stop(true);
} function navclick(navnum){
circlewrapper.children('canvas:eq('+navnum+')').click(function(e){
scideimgskip(navnum+1);
})
} function scideimgskip(imgnum){
stopAll();
turnleftwidth = imgnum*slideWrapperWidth;
slideImgWrapper.stop(true).animate({left:-turnleftwidth},animatetime,function(){
var imgnum = turnleftwidth/slideWrapperWidth-1;
if(imgnum==0){
imgnum=imgcountrealy;
}
if((imgnum-imgcountrealy)==0){
imgnum=0;
}
canvacircle(imgnum);
});
} function canvacircle(canvanum){
circles.attr("width",circler);
circles.attr("height",circler);
for(var i=0;i<circles.length;i++){
if(canvassuport){
var navCanvas=circles[i];
var cxt=navCanvas.getContext("2d");
if(i==canvanum){
cxt.fillStyle="#0182D7";
}else{
cxt.fillStyle="#ddd";
}
cxt.arc(circler*0.5,circler*0.5,circler*0.5,0,Math.PI*2,true);
cxt.closePath();
cxt.fill();
}else{
circles.css("background","#ddd");
circlewrapper.children('canvas:eq('+canvanum+')').css("background","#0182D7");
} }
} var turnleftwidth = slideWrapperWidth;
function turnleft(){
turnleftwidth = turnleftwidth+slideWrapperWidth;
if(turnleftwidth>(imgcount-2)*slideWrapperWidth){
slideImgWrapper.css({'left':0});
turnleftwidth = slideWrapperWidth;
}
slideImgWrapper.stop(true).animate({left:-turnleftwidth},animatetime,function(){
var imgnum = turnleftwidth/slideWrapperWidth-1;
if(imgnum==0){
imgnum=imgcountrealy;
}
if((imgnum-imgcountrealy)==0){
imgnum=0;
}
canvacircle(imgnum);
});
}
function turnright(){
turnleftwidth = turnleftwidth-slideWrapperWidth;
if(turnleftwidth==0){
slideImgWrapper.css({'left':-slideWrapperWidth*(imgcount-1)});
turnleftwidth = slideWrapperWidth*(imgcount-2);
}
slideImgWrapper.stop(true).animate({left:-turnleftwidth},animatetime,function(){
var imgnum = turnleftwidth/slideWrapperWidth-1;
if(imgnum==0){
imgnum=imgcountrealy;
}
if((imgnum-imgcountrealy)==0){
imgnum=0;
}
canvacircle(imgnum);
});
} var distanceX=0; function toLeft(){
if(turnleftwidth>(imgcount-3)*slideWrapperWidth){
slideImgWrapper.css({"left":distanceX});
turnleftwidth = 0;
}
turnleft();
sts = setTimeout(function(){
timedCount();
},timecontrol);
} function toRight(){
if(turnleftwidth==slideWrapperWidth){
slideImgWrapper.css({'left':-slideWrapperWidth*(imgcount-1)+distanceX});
turnleftwidth = slideWrapperWidth*(imgcount-1);
}
turnright();
sts = setTimeout(function(){
timedCount();
},timecontrol);
} function mouseDrag($element) {
var eventEle = $element;
var stx = etx = curX = 0;
var MAction = false;
var ahrefs = [];
for(var i=0;i<slideAs.length;i++){
if(typeof(slideImgWrapper.children('a:eq('+i+')').attr('href'))!=='undefined'){
ahrefs.push(slideImgWrapper.children('a:eq('+i+')').attr('href'));
}
}
eventEle.mouseover(function(){
for(var i=0;i<slideAs.length;i++){
if(typeof(slideImgWrapper.children('a:eq('+i+')').attr('href'))!=='undefined'){
slideImgWrapper.children('a:eq('+i+')').attr('href',ahrefs[i]);
}
}
});
eventEle.mousemove(function(event){
if(MAction){
var changeX = event.pageX-stx;
slideImgWrapper.css({"left":-turnleftwidth+changeX});
distanceX = changeX;
}
event.preventDefault();
}).mousedown(function(event){
stopAll();
MAction = true;
stx = event.pageX;
event.preventDefault();
});
eventEle.mouseup(function(event){
etx = event.pageX;
curX = etx-stx;
MAction = false;
if(curX>5){
slideAs.attr("href","javascript:void(0)");
toRight();
}
if(curX<-5){
slideAs.attr("href","javascript:void(0)");
toLeft();
}
event.preventDefault();
});
} function touchDrag($element) {
var gundongX = 0;
var gundongY = 0;
var moveEle = $element;
var stx = sty = etx = ety = curX = curY = 0; var ImgWidth_arr = [];
for (var i = 0; i < imgcount; i++) {
ImgWidth_arr.push(i * slideWrapperWidth);
} moveEle.on("touchstart", function(event) { //touchstart
stopAll();
var event = event.originalEvent;
gundongX = 0;
gundongY = 0;
// 元素当前位置
etx = parseInt(getT3d(moveEle, "x"));
ety = parseInt(getT3d(moveEle, "y"));
// 手指位置
stx = event.touches[0].pageX;
sty = event.touches[0].pageY;
});
moveEle.on("touchmove", function(event) {
var event = event.originalEvent;
// 防止拖动页面
event.preventDefault(); // 手指位置 减去 元素当前位置 就是 要移动的距离
gundongX = event.touches[0].pageX - stx;
gundongY = event.touches[0].pageY - sty; // 目标位置 就是 要移动的距离 加上 元素当前位置
curX = gundongX + etx;
curY = gundongY + ety;
slideImgWrapper.css({"left":-turnleftwidth+curX});
distanceX = curX;
});
moveEle.on("touchend", function(event) {
//alert(gundongX);
if(Math.abs(gundongX)>5){
event.preventDefault(); // 手指接触屏幕的位置
var oriX = etx;
var oriY = ety;
// 手指离开屏幕的位置
etx = curX;
ety = curY;
var slidePosition = 0;
for (var i = 0; i < imgcount - 1; i++) {
if (Math.abs(etx) > ImgWidth_arr[i]) { if (oriX > etx) {
// 左滑
toLeft();
} else {
// 右滑
toRight();
}
}
}
} }); function getT3d(elem, ename) {
var elem = elem[0];
var str1 = elem.style.webkitTransform;
if (str1 == "") return "0";
str1 = str1.replace("translate3d(", "");
str1 = str1.replace(")", "");
var carr = str1.split(","); if (ename == "x") return carr[0];
else if (ename == "y") return carr[1];
else if (ename == "z") return carr[2];
else return "";
}
}
});
};
})(jQuery);

在线演示

3.整体思路

a.创建显示窗口,显示容器大小位置自定义;

b.创立图片容器,通过改变图片容器的位置来改变显示窗口中展示的图片。

  难点在于如何改变图片容器位置来显示需要的图片和无缝轮播。可以想象一下以前的胶带式电影,如果放映速度慢下来就跟图片轮播类似了。所以可以把图片容器看成胶带,图片就是其中的一帧图像,显示窗口就是电影屏幕。

  如果以一个显示窗口的宽为一个单位,我们把图片水平排放在图片容器中,每张图片恰好占用一个显示窗口的宽高,有多少张图片,图片容器的宽就为多少个单位宽。然后使图片向左移动一个单位的距离,就可以展示下一张图片了。为了使图片展示效果更美观,我用了jquery的动画效果animate()来改变图片容器的位置。如果设定间隔多少时间图片容器左移一个单位,达到最后一张图片时,图片容器恢复到原始位置,进行下一轮移动。这样,就可以实现图片的水平轮播了。至于无缝轮播,我采取的做法是把前两张图片复制一份,放到所有图片的最后面。首次显示第二张图片,当移动到倒数第二张图片时,在下一次移动时先改变容器的left,让第一张图片被显示出来,因为这个动作很快,看起来好像并没有进行任何操作(达到欺骗眼球的效果,呵呵),然后使用animate显示第二张图片,在视觉上实现无缝轮播。从第二张图片右移时也与此类似。这样做的主要目的是为了确保左右都有能被展示的图片,确保不会显示空白,以实现无缝切换。这里,会用到的主要知识点有:

  (1).setTimeout和clearTimeout:

  用于延迟执行、循环执行和终止循环。setTimeout延迟执行确定图片的显示时间,循环执行为了自动展示下一张图片。当需要停止轮播的时候就可以用clearTimeout来终止循环了。关于setTimeout和clearTimeout的具体用法,可以参照代码,这里就不再赘述了。

  (2).jquery选择器:

  无需多说,所有jquery动作的基础。

  (3).jquery操作css:

  为了保证使用的简单性,只需确定显示容器的样式(需确保overflow:hidden;插件中已设置),其子元素包括图片容器(这里只支持div标签slideWrapper.children('div:eq(0)'))和图片及其链接的样式都在插件中确定,包括:保证图片水平排列,大小恰好为显示窗口的大小;确定图片容器的大小恰好容下所有图片。

  (4).jquery添加元素insertAfter:

  复制前两张图片到所有图片的最后面$((slideImgWrapper.html().split("/div>")[0]+"/div>"+slideImgWrapper.html().split("/div>")[1]+"/div>")).insertAfter(slideAWra.last())。

  (5).jquery动画效果animate: 

 var turnleftwidth = slideWrapperWidth;
function turnleft(){
turnleftwidth = turnleftwidth+slideWrapperWidth;
if(turnleftwidth>(imgcount-2)*slideWrapperWidth){
slideImgWrapper.css({'left':0});
turnleftwidth = slideWrapperWidth;
}
slideImgWrapper.stop(true).animate({left:-turnleftwidth},animatetime);
}
function turnright(){
turnleftwidth = turnleftwidth-slideWrapperWidth;
if(turnleftwidth==0){
slideImgWrapper.css({'left':-slideWrapperWidth*(imgcount-1)});
turnleftwidth = slideWrapperWidth*(imgcount-2);
}
slideImgWrapper.stop(true).animate({left:-turnleftwidth},animatetime);
}

  其中imgcount为进行图片复制后图片的元素个数,slideWrapperWidth为显示窗口的宽。 turnleft()用于无缝左移,turnright()用于无缝右移。

  现在来说说触屏支持。主要是用了jquery的on方法监听touch事件。具体怎么写,无非就是设置初始触摸位置,然后监听滑动的位置,根据水平滑动的具体实时改变图片容器的left,实现拖拽的效果。滑动结束后根据结束时的位置与初始位置的差判断左滑还是右滑,再来改变图片容器的left,使图片正好居中显示。跟PC端的鼠标拖拽类似。说到鼠标拖拽,不得不喷俩句。一般拖拽元素,基本都是mousedown、mousemove、mouseup三部曲。但是碰上图片就头疼了,特别是这图片的父亲还是a标签。mousedown没问题,mousemove能一个三五步,mousemove出问题mouseup也就失效了。弄了半天,终于通过 event.preventDefault()实现了对大部分浏览器的支持。废话不多说,让大家一起纠结下。

 <!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="UTF-8">
<head>
<meta charset="UTF-8">
<style>
body{
overflow-x:hidden;
margin:0 auto;
padding:0;
width: 100%;
height: 100%;
}
.aWrapper{
position: relative;
margin:0 auto;
width:400px;
height:600px;
overflow:hidden;
//float:left;
}
.testa{
position: relative;
margin:0 auto;
width:400px;
height:600px;
//float:left;
}
.testimg{
position: absolute;
width:400px;
height:600px;
z-index:0;
}
.imgmask{
position: relative;
width:400px;
height:600px;
z-index:1;
opacity:0.2;
background:#333;
}
</style>
</head>
<body>
<div class="aWrapper">
<a href="http://www.baidu.com" class="testa">
<img src="http://sandbox.runjs.cn/uploads/rs/215/auboqjjr/1 (1).jpg" class="testimg"/>
<div class='imgmask'></div>
</a>
</div>
</body>
</html>

  上面测试页面只有在Safari内核的浏览器(如Chrome)下才能够拖拽的,而且当图片遮罩层的position设置为absolute或者a标签设置float时都会失效,实在是搞不明白。而且要说一下可以很容易的阻止事件向上冒泡,有什么办法触发父元素事件是不要触发子元素的该事件么?还是以上面的测试页面为例,要拖拽aWrapper的div,就要设置该元素的mousedown、mousemove、mouseup事件。但是这里有一个问题,在mousedown和mouseup之后会触发click事件,导致触发子元素a标签的click而跳转页面。如果仅仅在mouseup时设置a标签的click返回false,那么这个链接就永远失效了。具体处理方法,大家还是看代码吧,反正被我搞得复杂得很,说多了都是泪。

  最后说说这个导航栏,就是下面的方方圈圈,用来显示第几张和点击跳转的。如果直接在页面上编写,问题倒还简单。在JS中就复杂多了。为了确保插件的独立性,除了对jquery的依赖外,我不想它有任何其他依赖。所以一般用图片来表示状态的方法就行不通了。我用的是html5的canvas绘制圆形。如果浏览器不支持或者担心浏览器消耗的话,可以关闭掉,直接用背景色表示,只是只能为方块块了。反正我觉得我自己弄的既不美观又不优雅,大家就当参照吧。

  

最新文章

  1. C# Struct结构体里数组长度的指定
  2. 《Entity Framework 6 Recipes》中文翻译系列 (18) -----第三章 查询之结果集扁平化和多属性分组
  3. Unity运行时检测Altas使用情况
  4. ionic 发送请求返回一直都是404
  5. office 2003和office 2013同时安装使用的问题
  6. 《梦断代码》读书笔记第0篇——“软件时间”、“死定了”、“Agenda之魂“
  7. python基础教程(五)
  8. gcd,最大公约数,lcm,最小公倍数
  9. ip001
  10. Windows下安装TensorFlow
  11. OpenStreetMap、googleMap等经纬度和行列号之间相互转化
  12. 第三方布局框架Neon初探
  13. mongo 使用find的返回值,转换为数组形式
  14. u-boot 编译,启动流程分析,移植
  15. VHDL 类型转换
  16. 跟着刚哥深入学maven(通俗易懂)
  17. Python3 贝叶斯分类
  18. Windows: 打开关闭网络连接的方法
  19. Android Studio 项目中,哪些文件应该忽略而不提交到svn的服务器中?
  20. OC NSNumber和NSValue和NSDate和NSData

热门文章

  1. Python爬取招聘信息,并且存储到MySQL数据库中
  2. css实现正方形div的3种方式
  3. 传智播客Springmvc_mybatis学习笔记
  4. 解析图书 XML
  5. 不带 www 跳转 到 带 www 网站..
  6. git 各个区的区别
  7. C++_基础3-循环和关系表达式
  8. [转] 商业应用中Java浮点数的精确计算及表示
  9. casper爬虫操作记录
  10. archlinux安装的软件