jQuery插件开发——全屏切换插件
这个插件包含三个部分:HTML结构、CSS代码和JS代码。
HTML结构是固定的,结构如下:
1 <!--全屏滚动--> 2 <div class="fullpage-container"> 3 <div class="fullpage-pagebox"> 4 <div id="fullpage-page1" class="fullpage-page-vertical"><h1>1</h1></div> 5 <div id="fullpage-page2" class="fullpage-page-vertical"><h1>2</h1></div> 6 <div id="fullpage-page3" class="fullpage-page-vertical"><h1>3</h1></div> 7 <div id="fullpage-page4" class="fullpage-page-vertical"><h1>4</h1></div> 8 <div id="fullpage-page5" class="fullpage-page-vertical"><h1>5</h1></div> 9 <div id="fullpage-page6" class="fullpage-page-vertical"><h1>6</h1></div> 10 </div> 11 </div>
其中元素的类名都是可以自己配置的,ID也不是必须的。
CSS代码,只贴出关键代码:
1 *{ 2 padding: 0; 3 margin: 0; 4 } 5 html,body{ 6 height: 100%;/*使html元素和body元素的高度始终等于视口高度*/ 7 } 8 .fullpage-container{ 9 position: relative; 10 height: 100%; 11 overflow: hidden; 12 } 13 .fullpage-pagebox{ 14 height: 100%; 15 position:relative; 16 } 17 18 .fullpage-page-vertical{ 19 height: 100%; 20 position:relative; 21 } 22 23 /***********分页样式--此处分页样式中的类名是直接写死在JS代码中的************/ 24 .fullpage-pagination{ 25 position:fixed; 26 left:17px; 27 top:50%; 28 margin:auto; 29 list-style: none; 30 31 } 32 .fullpage-pagination-item{ 33 width:20px; 34 height:15px; 35 margin:5px; 36 } 37 .fullpage-pagination-item a{ 38 display:block; 39 color: black; 40 text-decoration: none; 41 42 position: relative; 43 height:100%; 44 width:100%; 45 } 46 .fullpage-pagination-item:hover a .fullpage-point{ 47 background-color: black; 48 } 49 .fullpage-point{ 50 position:absolute; 51 width:8px; 52 height:8px; 53 top:0; 54 left:0; 55 bottom:0; 56 right:0; 57 margin: auto; 58 border:1px solid black; 59 border-radius: 4.5px; 60 } 61 .fullpage-point.fullpage-active{ 62 background-color: black; 63 }
JS代码:
1 ;(function($,window,document,undefined) { 2 function FullPage(elements,opt) { 3 this.elements = elements;//全屏切换DOM的最外层容器 4 this.defaults = {//默认的配置参数 5 fullpagebox: '.fullpage-pagebox',//全屏页面的父容器 6 fulleachpage: '.fullpage-page-vertical',//全屏页面 7 index: 0, //存储页面编号 8 duration: 500,//全屏页面的切换时间 9 easing: "swing",//切换时的Timming Function,与jQuery的animate()方法的取值一样 10 loop: false,//是否允许循环切换 11 callback: null,//每一屏切换完成时的回调函数 12 paginable: true //是否添加分页模块 13 }; 14 this.options = $.extend({},this.defaults,opt || {}); 15 } 16 17 FullPage.prototype = { 18 //初始化函数,插件中的方法都在该函数里调用 19 initialize: function() { 20 this.fullpagebox = this.elements.find(this.options.fullpagebox); 21 this.fulleachpage = this.elements.find(this.options.fulleachpage); 22 this.pagesnumber = this.fulleachpage.length; 23 this.index = this.options.index; 24 this.slidable = true;//起到优化滚轮事件的作用 25 this.pagination(); 26 this.bindEvent(); 27 28 var position = this.fulleachpage.eq(this.index).position(); 29 this.fullpagebox.css({top: -position.top + "px"}); 30 //alert(this.pagesnumber); 31 }, 32 33 //插件中的事件绑定都由该函数完成 34 bindEvent: function() { 35 var that = this; 36 //鼠标滚轮事件 37 this.elements.on("mousewheel DOMMouseScroll",function(event) { 38 if(that.slidable) { 39 //移除分页样式 40 if(that.options.paginable) { 41 that.pagination.find('.fullpage-point').eq(that.index).removeClass('fullpage-active'); 42 } 43 event = event || window.event; 44 var delta = (event.originalEvent.wheelDelta && (event.originalEvent.wheelDelta > 0 ? 1 : -1)) || // chrome & ie 45 (event.originalEvent.detail && (event.originalEvent.detail > 0 ? -1 : 1)); // firefox 46 if (delta > 0) { // 向上滚 47 if(that.index === 0) { 48 if(that.options.loop) { 49 that.index = that.pagesnumber - 1; 50 //that.slide(); 51 } 52 } else if(that.index > 0 && that.index < that.pagesnumber) { 53 that.index--; 54 //that.slide(); 55 } 56 } else if (delta < 0) { // 向下滚 57 58 if(that.index === that.pagesnumber - 1) { 59 if(that.options.loop) { 60 that.index = 0; 61 //that.slide(); 62 } 63 } else if(that.index >= 0 && that.index < that.pagesnumber-1) { 64 that.index++; 65 //that.slide(); 66 } 67 } 68 69 that.slide(); 70 //添加分页样式 71 if(that.options.paginable) { 72 that.pagination.find('.fullpage-point').eq(that.index).addClass('fullpage-active'); 73 } 74 //console.log(that.index); 75 } 76 }); 77 //分页点击事件 78 if(this.options.paginable) { 79 this.pagination.find('.fullpage-point').click(function() { 80 that.pagination.find('.fullpage-point').eq(that.index).removeClass('fullpage-active'); 81 that.index = $(this).index('.fullpage-point'); 82 //alert(that.index); 83 //alert($(this).index('.fullpage-point')); 84 that.slide(); 85 that.pagination.find('.fullpage-point').eq(that.index).addClass('fullpage-active'); 86 }); 87 } 88 89 //窗口resize事件 90 $(window).on('resize',function() { 91 //var count = that.index; 92 //that.pagination.find('.fullpage-point').eq(that.index).addClass('fullpage-active'); 93 var position = that.fulleachpage.eq(that.index).position(); 94 that.fullpagebox.css({top: -position.top + "px"}); 95 }); 96 97 }, 98 99 //滑动动画函数,实现页面向前或向后滑动 100 slide: function() { 101 var that = this; 102 that.slidable = false; 103 //获取目标屏的位置 104 var position = this.fulleachpage.eq(this.index).position(); 105 //(selector).animate({styles},speed,easing,callback) 106 this.fullpagebox.animate({top: -position.top + "px"},this.options.duration,this.options.easing, function() { 107 that.slidable = true; 108 if(that.options.callback && Object.prototype.toString.call(that.options.callback)=== '[object Function]') { 109 that.options.callback(); 110 } 111 }); 112 }, 113 114 //分页功能 115 pagination: function() { 116 if(this.options.paginable) { 117 var paginationHTML = ''; 118 for (var i = 0; i < this.pagesnumber; i++) { 119 paginationHTML+='<li class="fullpage-pagination-item"><a href="#"><span class="fullpage-point"></span></a></li>'; 120 } 121 this.pagination = $('<ul class="fullpage-pagination">'+paginationHTML+'</ul>'); 122 this.pagination.appendTo(this.elements); 123 //分页居中 124 var margintop = -parseInt(this.pagination.css('height'))/2; 125 this.pagination.css('margin-top',margintop+'px'); 126 //alert(pagination.css('margin-top')); 127 this.pagination.find('.fullpage-point').eq(this.index).addClass('fullpage-active'); 128 129 } 130 } 131 }; 132 133 $.fn.fullpage = function(cfg) { 134 var a = new FullPage(this,cfg); 135 //this.cfg = $.extend({},this.options,cfg||{}); 136 a.initialize(); 137 console.log(this); 138 }; 139 //使用该组件时直接用该组件的最外层容器调用fullpage(obj)方法即可 140 //obj是一个对象字面量,接受构造函数中列举的默认配置参数 141 })(jQuery,window,document)
下面把插件开发过程中用到的知识点总结一下。
1.面向对象
定义一个构造函数用来保存和获取代码中用到的参数:包括默认的配置参数和调用插件时传入的参数。
在构造函数的原型上添加插件的方法,包括:插件初始化方法,事件绑定方法,切换动画实现方法和分页模块方法。
jQuery中的对象扩展:extend()方法
构造函数中使用了jQuery的extend()方法来整合默认参数和传入的参数。
extend()方法有两种使用方法:
1.挂到jQuery上的方法,通过$.extend()调用。本插件中就是用的这种调用方式。
2.挂到jQuery.fn上的方法,通过jQuery的实例对象调用。
先贴两篇文章:
- jQuery.extend 函数使用详解 具体讲extend()的使用方法
- jQuery extend方法使用及实现 具体讲extend()的使用方法和实现原理以及源码解析
下面只贴出来使用方法。
1、$.extend(obj) 只传入一个对象类型参数
这种用法是将obj合并到jQuery的全局对象上去。
例:
1 $.extend({hello: 2 function() { 3 console.log('Hello!'); 4 } 5 }); 6 $.hello();//Hello!
2、$.extend(target, obj1, obj2, obj3,......)
合并obj1~ objN到target对象上。本插件用的就是这种用法。
例:
1 var target = {a:'A',b:'B'}; 2 $.extend(target,{x:'X',y:'Y'},{name:'jack',age:'18'}); 3 4 console.log(target.a);//A 5 console.log(target.y);//Y 6 console.log(target.age);//18
3、$.extend(boolean,target,obj1,obj2,obj3...)
是否深度复制合并对象。第一个参数是boolean类型,为true时,表示将obj1~ objN深度复制后合并到target中。关于深度复制,是将除null、undefined、window对象、dom对象以及通过继承创建的对象之外的其它对象深度复制后保存到target中。(测试结果,只有当boolean为true时才会将obj1~ objN深度复制后合并到target中;boolean为false时,target不变,而是将target,obj1~ objN深度复制后合并到返回的新对象中,所以说尽量不要传入false值,而仅仅在需要深复制时传入true)
例:
var target = {a:'A',b:'B'}, obj = {person:{name:'jack',age:18}}; $.extend(true,target,obj); console.log(target.person.age);//18 obj.person.age = 20; console.log(target.person.age)//18
$.extend(false,target,obj);//传入false,target.person.age报错,age属性未定义;target对象没有变化 console.log(target.person.age);
以下写法不会报错
var target = {a:'A',b:'B'}, obj = {person:{name:'jack',age:18}}; var result = $.extend(false,target,obj);//此时传入false不报错 console.log(result.person.age);//18 obj.person.age = 20; console.log(result.person.age)//20
4.$.fn.extend(obj)
$.fn = $.prototype =jQuery.prototype
将obj对象的属性和方法扩展到jQuery全局对象的原型上,那么jQuery的实例对象就可以调用这些扩展来的属性和方法。
例如:
$.fn.extend({say: function() { console.log('OK!'); } }); $("p").on("click",function(){ $(this).say(); //ok });
插件内部的功能划分
根据插件的需求在内部将插件划分为几个功能方法并对这些功能方法进行封装,在编写插件时只要根据需要调用这些功能方法即可。
在本插件中划分出的功能方法有:
1.初始化方法 initialize()
顾名思义该方法主要是完成插件的初始化,包括DOM节点的获取,参数的初始化,其他功能方法的调用等。
2.事件的绑定方法 bindEvent()
这里主要是鼠标滚轮事件的绑定和分页模块点击事件的绑定,还有窗口resize事件的绑定。
这里主要记录一下通过jQuery的 on() 绑定事件时,传入事件处理程序的事件对象 event 的注意点。
使用 on() 方法绑定事件时,原生的事件对象保存在 event.originalEvent这个对象中,而 event 是经过jQuery兼容过后的事件对象,它包含以下封装后通用的事件属性和方法:
Event 对象的属性:
属性 | 初始版本 | 描述 |
---|---|---|
currentTarget | 1.3 | 返回事件冒泡阶段中的当前DOM元素。 |
data | 1.1 | 返回绑定事件时传入的附加数据。 |
delegateTarget | 1.7 | 返回"受委托"调用当前事件处理函数的DOM元素。 |
metaKey | 1.0.4 | 指示触发事件时是否按下了Meta键。 |
namespace | 1.4.3 | 返回触发事件时指定的命名空间。 |
pageX | 1.0.4 | 返回鼠标相对于当前文档的x坐标。 |
pageY | 1.0.4 | 返回鼠标相对于当前文档的y坐标。 |
relatedTarget | 1.1.4 | 返回事件涉及到的其它DOM元素。 |
result | 1.3 | 返回当前事件绑定的上一个事件处理函数的返回值。 |
target | 1.3 | 最初触发该事件的DOM元素。 |
timeStamp | 1.2.6 | 返回事件触发的当前时间与1970年1月1日午夜之间的毫秒数。 |
type | 1.0 | 返回事件的类型。例如:"click"、"focus"等。 |
which | 1.1.3 | 返回触发事件时按下的鼠标按钮或键盘按键。 |
Event 对象的方法:
方法 | 初始版本 | 描述 |
---|---|---|
isDefaultPrevented() | 1.3 | 是否调用了preventDefault()方法。 |
isImmediatePropagationStopped() | 1.3 | 是否调用了stopImmediatePropagation()方法。 |
isPropagationStopped() | 1.3 | 是否调用了stopPropagation()方法。 |
preventDefault() | 1.0 | 阻止触发事件的默认行为。 |
stopImmediatePropagation() | 1.3 | 阻止该元素当前触发事件剩余的事件处理函数的执行,并停止事件的冒泡传递。 |
stopPropagation() | 1.0 | 停止事件的冒泡传递。 |
jQuery框架中on()方法的用法介绍,参考:jQuery.on() 函数详解。
注意:要删除通过on()绑定的事件,请使用off()函数。如果要附加一个事件,只执行一次,然后删除自己,请使用one()函数。
3. 切换动画方法 slide()
主要是用jQuery的animate()方法控制相对定位元素的top属性实现的。
jQuery框架中 animate() 方法的用法介绍,参考:jQuery.animate() 函数详解
4.分页方法 pagination()
分页功能的HTML结构直接在JS代码中生成。
2、this与$(this)
this是原生JS中的this,只支持原生JS的属性和方法,不支持jQuery类型的属性和方法。
要想使this支持jQuery类型的属性和方法要用$()函数对原生的this进行包装:$(this)。
例如:
<p>Click this <span>paragraph.</span></p> <script> $(document).ready(function(){ $("p").on("click",function(){ this.css("color","red");//报错this.css is not a function $(this).css("color","red");//不报错 }); }); </script>
3、jQuery的index()和eq()方法
index() 返回匹配元素的索引;
eq() 返回对应索引的jQuery对象;
这里主要记录index()的用法:
语法:
jQueryObject.index( [ object ] )
-
如果没有指定参数
object
,则返回 jQueryObject 在其所有同辈元素中的索引位置。 -
如果
object
为String类型,则将其视作选择器,返回 jQueryObject 在选择器所匹配的元素中的索引位置。如果该选择器不匹配任何元素或者 jQueryObject 不在匹配到的元素内,则返回-1。 -
如果
object
为DOM元素或jQuery对象,则返回该元素(或该jQuery对象中的第一个元素)在当前jQuery对象所匹配的元素中的索引位置。
例如:
<div id="div1"> <ul id="ul1"> <li id="n1" class="list">item1</li> <li id="n2" class="list">item2</li> <li id="n3" class="list">item3</li> </ul> <ul id="ul2" style="background-color:green;"> <li id="n4" class="list">item4</li> <li id="n5" class="list">item5</li> <li id="n6" class="list">item6</li> </ul> </div>
JS代码:
$('li').click(function() { console.log($(this).index());//返回this在其所有兄弟元素中的索引 console.log($(this).index('.list'));//返回this在所有类名为list的元素中的索引 console.log($(this).index($('#n2')));//返回this中id为n2的元素的索引 }); $('#ul2').click(function() { alert($(this).index());//1 alert($('li').index($('#n6')));//5 });
4、jQuery的position()方法
position()函数用于返回当前匹配元素相对于其被定位的祖辈元素的偏移(不包含margin),也就是相对于被定位的祖辈元素的坐标。该函数只对可见元素有效。
所谓"被定位的元素",就是元素的CSS position属性值为absolute、relative或fixed(只要不是默认的static即可)。
该函数返回一个坐标对象,该对象有一个left属性和top属性。属性值均为数字,它们都以像素(px)为单位。
例如:
<style type="text/css"> *{ padding:0; margin:0; } #div2{ position:relative; width:300px; height:200px; background-color:black; overflow:hidden; } #div3{ margin:auto; width:50px; height:50px; background-color:#fff; } </style> <div id="div2"> <div id="div3"></div> </div> <script> var position = $('#div3').position(); console.log(position);//{left:0,top:0} </script>
(完)
参考教程:
2、全屏切换效果