1.面向对象:
- 易维护: 采用面向对象思想设计的结构,可读性高,由于继承的存在,即使改变需求,那么维护也只是在局部模块,所以维护起来是非常方便和较低成本的。
- 质量高: 在设计时,可重用现有的,在以前的项目的领域中已被测试过的类使系统满足业务需求并具有较高的质量。
- 效率高: 在软件开发时,根据设计的需要对现实世界的事物进行抽象,产生类。使用这样的方法解决问题,接近于日常生活和自然的思考方式,势必提高软件开发的效率和质量。
- 易扩展: 由于继承、封装、多态的特性,自然设计出高内聚、低耦合的系统结构,使得系统更灵活、更容易扩展,而且成本较低。
2.Tab组件
用jquery实现tab效果并不难,来看下主要代码:
$('.ct>li').on('click',function(){
var $this =$(this)
var index = $(this).index();//被点中的下标 .index()jquery方法;
console.log(index);
$this.siblings().removeClass('active');
$this.addClass('active')
$this.parents('.wrap').find('.panel').removeClass('active')
$this.parents('.wrap').find('.panel').eq(index).addClass('active')
})
如何用面向对象写成组件?
function Tab(ct){ //写一个构造函数;
this.ct = ct;
this.init();//init()初始化
this.bind();//bind()//绑定事件处理;
}
Tab.prototype.init = function (){ //给原型上帮定初始化函数;
this.tabLis = this.ct.querySelectorAll('.ct>li')//选中所有的li
this.panels = this.ct.querySelectorAll('.panel')//选中所有的panel
}
Tab.prototype.bind = function (){
var _this =this ;//保存this指向
this.tabLis.forEach(function(tabli){//循环所有的的li,
tabli.onclick = function(e){//当点击时
var target = e.target;//被点中的的目标li;
var index = [].indexOf.call(_this.tabLis,target)//借用数组方法;获取被点中的li下标;
_this.tabLis.forEach(function(li){//循环所有的的li,
li.classList.remove('active');//循环所有的的li,去掉active
})
![20170424_000601.gif](http://upload-images.jianshu.io/upload_images/3407000-940252b56661b894.gif?imageMogr2/auto-orient/strip)
target.classList.add('active');//给点中的li加上 active
_this.panels.forEach(function(panel){//循环所有的的panel,
panel.classList.remove('active')//循环所有的的panel,去掉active
})
_this.panels[index].classList.add('active')//给对应li小标的panel加上active
}
})
}
new Tab(document.querySelectorAll('.wrap')[0])
new Tab(document.querySelectorAll('.wrap')[1])
new Tab(document.querySelectorAll('.wrap')[2])
//完成后只需new出构造函数的对象就可以了;
3. 轮播组件
用jquery实现轮播效果,来看下主要代码:
var $imgCt =$('.img-ct'),
$preBtn = $('.btn-pre'),
$nextBtn = $('.btn-next'),
$bullet = $('.bullet');
var $firstImg = $imgCt.find('li').first(),
$lastImg = $imgCt.find('li').last();
var pageIndex = 0; //第几个页的变量;
var imgLength =$imgCt.children().length; //获取在克隆前有多少张图片
var isAnimate = false;//防止重复点击
$imgCt.prepend($lastImg.clone())//把最后一个图clone一次添加到第一张的前面;
$imgCt.append($firstImg.clone())//把最前一个图clone一次添加到最后一张的后面;
$imgCt.width($firstImg.width()*$imgCt.children().length) //设定ul的宽度
$imgCt.css({'left':'-'+$firstImg.width()+'px'})//把第一张图放入可视区域
auto()
$preBtn.on('click',function(e){
e.preventDefault()//阻止页面刷新
playPre()
})
$nextBtn.on('click',function(e){
e.preventDefault()
playNext()
})
$bullet.find('li').on('click',function(e){
e.preventDefault()
var idx = $(this).index();
if(idx>pageIndex){
playNext(idx-pageIndex)
}else if(idx
如何用面向对象写成组件?
function Carousel($ct){
this.$ct = $ct;
this.init();//初始化
this.bind();//事件处理
this.auto();//自动播放函数
}//与Tab原理一样写一个构造函数
Carousel.prototype.init = function(){//给原型上帮定初始化函数
var $imgCt =this.$imgCt = this.$ct.find('.img-ct'),
$preBtn =this.$preBtn = this.$ct.find('.btn-pre'),
$nextBtn =this.$nextBtn=this.$ct.find('.btn-next'),
$bullet = this.$bullet= this.$ct.find('.bullet');
var $firstImg =this.$firstImg= $imgCt.find('li').first(),
$lastImg =this.$lastImg= $imgCt.find('li').last();
//这里注意下 其他函数要用的变量要用this.
this.pageIndex = 0; //第几个页的变量;
this.imgLength =$imgCt.children().length; //获取在克隆前有多少张图片
this.isAnimate = false;//防止重复点击
$imgCt.prepend($lastImg.clone())//把最后一个图clone一次添加到第一张的前面;
$imgCt.append($firstImg.clone())//把最前一个图clone一次添加到最后一张的后面;
$imgCt.width($firstImg.width()*$imgCt.children().length) //设定ul的宽度
$imgCt.css({'left':'-'+$firstImg.width()+'px'})//把第一张图放入可视区域
}
Carousel.prototype.bind = function(){
var _this = this;//保存this;
this.$preBtn.on('click',function(e){
e.preventDefault()//阻止页面刷新
_this.playPre()//this指定的是按钮所以要用保存起来的_this;下面的一样
})
this.$nextBtn.on('click',function(e){
e.preventDefault()
_this.playNext()
})
this.$bullet.find('li').on('click',function(e){
e.preventDefault()
var idx = $(this).index();
if(idx> _this.pageIndex){
_this.playNext(idx- _this.pageIndex)
}else if(idx< _this.pageIndex){
_this.playPre( _this.pageIndex-idx)
}
})
}
下面四个函数都绑定到原型上,实现效果 注意this的指向;与上面一样;
Carousel.prototype.playNext = function(idx){
var _this = this;
var idx = idx ||1
if(this.isAnimate) return
this.isAnimate = true;
this.$imgCt.animate({
left:'-='+(this.$firstImg.width()*idx)
},function(){
_this.pageIndex= _this.pageIndex+idx;
if(_this.pageIndex === _this.imgLength){//如果页数=图片的最后一个,就让图片回到第一张;即data-index=0;
_this.$imgCt.css({'left':'-'+_this.$firstImg.width()+'px'})
_this.pageIndex = 0;
}
_this.isAnimate =false;
_this.setBullet()
})
}
Carousel.prototype.playPre = function(idx){
var _this = this;
var idx = idx ||1
if(this.isAnimate) return
this.isAnimate = true;
this.$imgCt.animate({
left:'+='+this.$firstImg.width()*idx
},function(){
_this.pageIndex=_this.pageIndex-idx;
if(_this.pageIndex < 0 ){
_this.$imgCt.css({'left':'-'+_this.imgLength*_this.$firstImg.width()+'px'})
_this.pageIndex = _this.imgLength - 1;
}
_this.isAnimate =false;
_this.setBullet()
})
}
Carousel.prototype.setBullet = function (){
this.$bullet.children()
.removeClass('active')
.eq(this.pageIndex)
.addClass('active')
}
Carousel.prototype.auto = function(){
var _this = this;
var lock = setInterval(function(){
_this.playNext()
},3000)
//最后根据需要new出构造函数的对象就可以了
new Carousel($('.carousel').eq(0));
new Carousel($('.carousel').eq(1));
new Carousel($('.carousel').eq(2));
4. 轮播的二次封装
代码基本没变化;
var Carouse = (function(){
return {
Toinit:function($ct){
$ct.each(function(index,node){
new _Carousel($(node));
})
}
}
})() //写一个立刻执行函数,返回Toinit函数new出对象;把上面的代码放入这个立刻执行函数,注意名字不用起重复;
var Carousel = (function(){
function _Carousel($ct){//构造函数
this.$ct = $ct;
this.init();
this.bind();
this.auto();
}
_Carousel.prototype.init = function(){
var $imgCt =this.$imgCt = this.$ct.find('.img-ct'),
$preBtn =this.$preBtn = this.$ct.find('.btn-pre'),
$nextBtn =this.$nextBtn=this.$ct.find('.btn-next'),
$bullet = this.$bullet= this.$ct.find('.bullet');
var $firstImg =this.$firstImg= $imgCt.find('li').first(),
$lastImg =this.$lastImg= $imgCt.find('li').last();
this.pageIndex = 0; //第几个页的变量;
this.imgLength =$imgCt.children().length; //获取在克隆前有多少张图片
this.isAnimate = false;//防止重复点击
$imgCt.prepend($lastImg.clone())//把最后一个图clone一次添加到第一张的前面;
$imgCt.append($firstImg.clone())//把最前一个图clone一次添加到最后一张的后面;
$imgCt.width($firstImg.width()*$imgCt.children().length) //设定ul的宽度
$imgCt.css({'left':'-'+$firstImg.width()+'px'})//把第一张图放入可视区域
}
_Carousel.prototype.bind = function(){
var _this = this;
this.$preBtn.on('click',function(e){
e.preventDefault()//阻止页面刷新
_this.playPre()
})
this.$nextBtn.on('click',function(e){
e.preventDefault()
_this.playNext()
})
this.$bullet.find('li').on('click',function(e){
e.preventDefault()
var idx = $(this).index();
if(idx> _this.pageIndex){
_this.playNext(idx- _this.pageIndex)
}else if(idx< _this.pageIndex){
_this.playPre( _this.pageIndex-idx)
}
})
}
_Carousel.prototype.playNext = function(idx){
var _this = this;
var idx = idx ||1
if(this.isAnimate) return
this.isAnimate = true;
this.$imgCt.animate({
left:'-='+(this.$firstImg.width()*idx)
},function(){
_this.pageIndex= _this.pageIndex+idx;
if(_this.pageIndex === _this.imgLength){//如果页数=图片的最后一个,就让图片回到第一张;即data-index=0;
_this.$imgCt.css({'left':'-'+_this.$firstImg.width()+'px'})
_this.pageIndex = 0;
}
_this.isAnimate =false;
_this.setBullet()
})
}
_Carousel.prototype.playPre = function(idx){
var _this = this;
var idx = idx ||1
if(this.isAnimate) return
this.isAnimate = true;
this.$imgCt.animate({
left:'+='+this.$firstImg.width()*idx
},function(){
_this.pageIndex=_this.pageIndex-idx;
if(_this.pageIndex < 0 ){
_this.$imgCt.css({'left':'-'+_this.imgLength*_this.$firstImg.width()+'px'})
_this.pageIndex = _this.imgLength - 1;
}
_this.isAnimate =false;
_this.setBullet()
})
}
_Carousel.prototype.setBullet = function (){
this.$bullet.children()
.removeClass('active')
.eq(this.pageIndex)
.addClass('active')
}
_Carousel.prototype.auto = function(){
var _this = this;
var lock = setInterval(function(){
_this.playNext()
},3000)
}
return {
Toinit:function($ct){
$ct.each(function(index,node){
new _Carousel($(node));
})
}
}
})()
Carousel.Toinit($('.carousel')); //new出页面所有class= carousel的对象;
//与上面的第一种效果是一样~
5. 曝光组件-懒加载
用jquery实现tab效果并不难,来看下主要代码:
check();//先加载出在可数去里的图片
$(window).on('scroll', check)//当窗口滚动加载图片
function check(){
$('.container img').not('.load').each(function(){
if(isShow($(this))){
show($(this))
}
})
}
function show($imgs){//改变src的值;
$imgs.each(function(){
var imgUrl = $(this).attr('data-src');
$(this).attr('src',imgUrl);
$(this).addClass('load')
})
}
function isShow($node){//判断图片是否出现在可视区里
var windowHeight = $(window).height(),
scrollTop = $(window).scrollTop(),
offsetTop = $node.offset().top,
nodeHeight = $node.height();
if(windowHeight+scrollTop>offsetTop && scrollTop< offsetTop+nodeHeight){
return true;
}else{
return false;
} //scrollTop< offsetTop+nodeHeight浏览器上边缘
//windowHeight+scrollTop>offsetTop浏览器下边缘
}
如何用面向对象写成组件?
var Lazy =(function(){ //写一个立即执行函数
function Exposure($target,callback,isOnce){//构造函数
this.$target = $target;
this.callback = callback;
this.isOnce = isOnce;
this.hasShow = false; //用于判断是否继续执行
this.bind();//事件绑定
this.check();
}
Exposure.prototype.showImg = function($node){
var imgUrl = $node.attr('data-src');
$node.attr('src',imgUrl);
}
Exposure.prototype.bind = function(){
var _this = this;
$(window).on('scroll', function(){
_this.check();
})
}
Exposure.prototype.check = function(){
if(this.isOnce){// 如果传入第3个参数就执行;
if(this.isShow() && !this.hasShow){//如果两个条件都成立执行;
this.callback(this.$target)
this.hasShow = true;
//这里是为了构造的对象的callback函数执行一次还是多次
}
}else {// 如果没有传入第3个参数就执行;
if(this.isShow()){
this.callback(this.$target)
}
}
}
Exposure.prototype.isShow = function(){
var windowHeight = $(window).height(),
scrollTop = $(window).scrollTop(),
offsetTop = this.$target.offset().top,
nodeHeight = this.$target.height();
if(windowHeight+scrollTop>offsetTop && scrollTop< offsetTop+nodeHeight){
return true;
}else{
return false;
}
}
return {
init :function($targets,callback){//多次执行callback;
$targets.each(function(idx,target){
new Exposure($(target),callback)
})
},
one:function($target,callback){//执行一次callback;
$target.each(function(idx,target){
new Exposure($(target),callback,true)
})
}
}
})()
Lazy.one($('#hello'),function($node){
$node.text($node.text()+'只加一次');
})
Lazy.init($('#world'),function($node){
$node.text($node.text()+'加多次');
})
Lazy.one($('.container img'),function($node){
this.showImg($node);
})
6. Modal 组件
如何用面向对象写成组件? 看下主要的代码:
// 用模块定义的方式创建一个对象,把new Modal 的过程封装到模块里,这样用这就可以直接通过Dialog.open()的方法调用
var Dialog =(function(){
function Modal(){
this.createDialog();
this.bind();
}
Modal.prototype = {
defaults:{//设置初始参数
title:'',
message:'',
ShowCloseBtn:true,
ShowConfirmBtn:false,
onClose:function(){},
onConfirm:function(){}
},
open:function(opts){//当点击按钮时传入参数;
this.setOpts(opts);//设置参数;
console.log(this.opts);
this.setDialog();//设置Dialog
this.showDialog()//显示Dialog
},
createDialog:function(){//创建Dialog
var tpl = ''
+ ''
+ ''
+ 'X'
+ ''
+ ' '
+ ''
+'' ;
this.$ct = $(tpl);
$('body').append(this.$ct);
},
bind:function(){
var _this = this;
_this.$ct.find('.btn-close').on('click',function(e){//当点击.btn-close时
e.preventDefault();//阻止默认事件;
_this.opts.onClose()
_this.hideDialog()
});
_this.$ct.find('.btn-confirm').on('click',function(e){
e.preventDefault();
_this.opts.onConfirm()
_this.hideDialog()
});
},
setOpts:function(opts){
if(typeof opts === 'string'){//如果为字符串;参数值变为
this.opts = $.extend({},this.defaults,{message:opts})//参数值变为一个新的对象
}else if (typeof opts === 'object'){//如果为对象
this.opts = $.extend({},this.defaults,opts);//参数值变为一个新的对象
}
},
setDialog:function(){//设置Dialog的样式
var $ct = this.$ct;
if(!this.opts.title){
$ct.find('.dialog-head').hide()
}else{
$ct.find('.dialog-head').show()
}
if(!this.opts.ShowCloseBtn){
$ct.find('.dialog-footer .btn-close').hide();
}else{
$ct.find('.dialog-footer .btn-close').show();
}
if(!this.opts.ShowConfirmBtn){
$ct.find('.dialog-footer .btn-confirm').hide();
}else{
$ct.find('.dialog-footer .btn-confirm').show();
}
$ct.find('.dialog-head h3').text(this.opts.title);
$ct.find('.dialog-content').html(this.opts.message);
},
showDialog:function(){
this.$ct.show()//Dialog显示
},
hideDialog:function(){
this.$ct.hide()//Dialog隐藏
}
};
return new Modal();
})()
//通过传入不同的参数;来改变dialog的样式
$('.open1').on('click',function(){
Dialog.open('Welcome to the world of IT');
})
$('.open2').on('click',function(){
Dialog.open(''+'百度'+'');
})
$('.open3').on('click',function(){
Dialog.open({
title:'World',
message:'Welcome to the world of IT',
ShowCloseBtn:true,
ShowConfirmBtn:true,
onClose:function(){
alert('close')
},
onConfirm:function(){
alert('确定')
}
});
})
$('.open4').on('click',function(){
var tpl = '- '+'列表1'+'
- '+'列表2'+'
- '+'列表3'+'
'
Dialog.open({
title:'World',
message:tpl,
ShowCloseBtn:true,
ShowConfirmBtn:true,
onClose:function(){
alert('close')
},
onConfirm:function(){
alert('确定')
}
});
})
$('.open5').on('click',function(){
Dialog.open({
title:'World',
message:'Welcome to the world of IT',
ShowCloseBtn:false,
ShowConfirmBtn:false,
onClose:function(){
alert('close')
}
});
})
7.GoTop组件
如何用面向对象写成组件? 看下主要的代码:
var GoTop = function(ct,target){
this.ct = ct;
this.target = $('回到顶部')
this.target.css({
position:'fixed',
right:'100px',
bottom:'50px',
display:'none',
padding:'8px',
cursor:'pointer',
border:'1px solid',
borderRadius:'4px'
})
}
GoTop.prototype.creatNode = function(){
this.ct.append(this.target);
}
GoTop.prototype.bindEvent = function(){
var _this = this;
var $window = $(window);
$window.on('scroll',function(){
var $top = $window.scrollTop()
if($top>100){
_this.target.css('display','block')
}else{
_this.target.css('display','none')
}
})
this.target.on('click',function(){
_this.ct.animate({
scrollTop : 0
})
})
}
var Gotop =new GoTop($('body'))
Gotop.creatNode();
Gotop.bindEvent();
8. 日历组件
如何用面向对象写成组件? 看下主要的代码:
function DatePicker($target) {
//初始化当前日期
this.init($target);
//渲染日历模板
this.render();
//设置模板里面的数据
this.setData();
//绑定事件
this.bind();
}
DatePicker.prototype = {
init: function($target) {
this.$target = $target;
if (this.isValidDate($target.attr('date-init'))) {
this.date = new Date($target.attr('date-init')); //当前日期或者指定的要展示的日期
this.watchDate = new Date($target.attr('date-init')); //用户在切换月份时所看到的日期,初始为当前日期
} else {
this.date = new Date();
this.watchDate = new Date();
}
},
render: function() {
var tpl = '