您的位置:首页 > Web前端 > JavaScript

【自】JavaScript面向对象初探一:通过编写一个简单的Tab选项卡插件,让我们更直观的去认识面向对象的编程方式

2017-01-19 12:05 609 查看
一直都对面向对象这个东西了解的比较表面,真实原因是因为实践太少了,平时项目开发中多以面向过程开发为主,对于一个没有后台JAVA语言基础的前端来说,基本上去理解面向对象都是需要一个过程的,其实我一直都是想通过一个实际例子来让自己或者更多JS初学者来对面向对象可以有一个初步的概念。

我们就做一个如下图的,TAB切换的例子,这个在实际项目上的运用应该是比较广泛的



注意:

  题主建议:先到github上面把代码下载运行了,然后一步一步的往下走,这样会轻松些

  github:https://github.com/shiyou00/oop

我们在看实际例子之前,我们首先得知道JS的面向对象里面有哪些基本概念

对象、方法、属性



封装

聚合

重用与继承

多态

对象:

  简单的可以理解成一个具体的 "事物" 如 人,猫,狗是一个对象,你要实现的一个功能可以是一个对象譬如一个简单的Tab

一个对象里面有两种东西:

属性:

  一般是形容词,描述这个对象的一些特征叫做属性,例如:

function Tab(){
this.oTitle = document.querySelector('.title');
this.oContent = document.querySelector('.content');
}


这个tab是一个功能,我们把它看成一个对象,那么这些元素就是它的属性,当然它还有其他的属性。

方法:

  选项卡的头部是点击可以切换的,那么理所当然的来说,这个切换的功能就是它的一个方法,来看看。

function Tab(){
this.oWrapper = document.querySelector('.wrapper');
this.oTitle = this.oWrapper.querySelectorAll('.title');
this.oContent = this.oWrapper.querySelectorAll('.content');
this.iNow = 0;
this.init();
}
Tab.prototype.init = function(){
//需要先保存Tab对象的this
//下面就是一个普通的tab切换的代码了
var _this = this;
for(var i=0;i<this.oTitle.length;i++){
this.oTitle[i].index = i;
this.oTitle[i].addEventListener("click",function(){
_this.iNow = this.index;
for(var j=0;j<_this.oTitle.length;j++){

_this.oTitle[j].className = "title";
_this.oTitle[_this.iNow].className = "title active";

_this.oContent[j].className = "content";
_this.oContent[_this.iNow].className = "content show";
}
},false);
}
};

new Tab();


现在是一个粗略的写法,但是我们可以先分析下,我们给这个Tab对象,定义了属性,这些属性里面有:

1.html元素(毕竟最后的方法是作用于这些元素上面的)

2.iNow变量(用于保存索引值的)

方法目前我就定义了一个init的方法,然后一股脑的把所有的动作写在里面了,当然运行下也是可以的,而且完全没有问题的。

但是如果当我们需要有一个可以自动循环播放的Tab的时候,我们发现上述对象的方法,继承之后是完全没有作用的!那么我们应该对这个init方法进行下一步的拆分

function Tab(){
this.oWrapper = document.querySelector('.wrapper');
this.oTitle = this.oWrapper.querySelectorAll('.title');
this.oContent = this.oWrapper.querySelectorAll('.content');
this.iNow = 0;
this.init();
this.autoTab();
}
Tab.prototype.init = function(){
var _this = this;
for(var i=0;i<this.oTitle.length;i++){
this.oTitle[i].index = i;
this.oTitle[i].addEventListener("click",function(){
_this.iNow = this.index;
_this.titleShow();
_this.contentShow();
},false);
}
};
Tab.prototype.titleShow = function(){
var _this = this;
for(var j=0;j<_this.oTitle.length;j++){
_this.oTitle[j].className = "title";
_this.oTitle[_this.iNow].className = "title active";
}
};
Tab.prototype.contentShow = function(){
var _this = this;
for(var j=0;j<_this.oTitle.length;j++){
_this.oContent[j].className = "content";
_this.oContent[_this.iNow].className = "content show";
}
};


可以看下上面的代码,我们把标题的显示拆出来了,新写了一个方法titleShow,另外内容的显示我们也新写了一个方法contentShow方法;

这时候就有了工厂模式,即:把实现同一事情的相同代码,放到一个函数中,以后如果再想实现这个功能,就不需要重新编写这些代码了,只要执行当前的函数即可,这就是函数的封装,体现了高内聚、低耦合的思想:减少页面的中的冗余代码,提高代码的重复利用率:

下面我就要在这个基础Tab上加一个自动播放功能;

Tab.prototype.autoTab = function(){
var _this = this;
setInterval(function(){
_this.iNow++;
if(_this.iNow>2){
_this.iNow=0;
}
_this.titleShow();
_this.contentShow();
},3000);
};


有没有看到,定时器开启直接调用这两个方法,Tab就自动播放了,如果还像上面那样都写在init里面没有拆出来的话,那么想要加这个自动播放的功能就会产生很多的冗余的代码;当然这样写会有另外一个好处,就是利于继承,我们后面会讲到。

现在只能是自动播放,当我们鼠标移入的时候,其实我们是需要停止定时器的,当鼠标移出的时候在开启定时器的,我们来把这个功能加上

Tab.prototype.switchTab = function(){
var _this = this;
_this.oWrapper.addEventListener("mouseover",function(){
clearInterval(_this.clock);
},false);
_this.oWrapper.addEventListener("mouseout",function(){
_this.autoTab();
},false)
};


功能上的话就先到这里,但是上面的代码还有很多问题例如:

1.可配置性太差了,必须得完全按照这种格式来入手

2.基本没有办法复用了,还是上面的原因

那么我们在深入的做一些调整。让这个Tab是可以定制化的。

function Tab(options){
this.oWrapper = document.querySelector('.wrapper');
this.oTitle = this.oWrapper.querySelectorAll('.title');
this.oContent = this.oWrapper.querySelectorAll('.content');
this.len = this.oTitle.length;
this.iNow = 0;
this.clock = null;
var defaults = {
autoPlay:true, //自动轮播
autoTime:1000 //自动轮播时间间隔
};
this.ops = options || {};
for (var i in defaults) {
if (typeof options[i] === 'undefined') {
options[i] = defaults[i];
} else if (typeof options[i] === 'object') {
for (var j in defaults[i]) {
if (typeof options[i][j] === 'undefined') {
options[i][j] = defaults[i][j];
}
}
}
}
this.init();
if(this.ops.autoPlay === true){
this.autoTab();
this.switchTab();
}
}
Tab.prototype.init = function(){
var _this = this;
for(var i=0;i<this.len;i++){
this.oTitle[i].index = i;
this.oTitle[i].addEventListener("click",function(){
_this.iNow = this.index;
_this.titleShow();
_this.contentShow();
},false);
}
};
Tab.prototype.titleShow = function(){
var _this = this;
for(var j=0;j<_this.len;j++){
_this.oTitle[j].className = "title";
_this.oTitle[_this.iNow].className = "title active";
}
};
Tab.prototype.contentShow = function(){
var _this = this;
for(var j=0;j<_this.len;j++){
_this.oContent[j].className = "content";
_this.oContent[_this.iNow].className = "content show";
}
};
Tab.prototype.autoTab = function(){
var _this = this;
_this.clock=setInterval(function(){
_this.iNow++;
if(_this.iNow>(_this.len-1)){
_this.iNow=0;
}
_this.titleShow();
_this.contentShow();
},_this.ops.autoTime);
};
Tab.prototype.switchTab = function(){ var _this = this; _this.oWrapper.addEventListener("mouseover",function(){ clearInterval(_this.clock); },false); _this.oWrapper.addEventListener("mouseout",function(){ _this.autoTab(); },false) };
function tab(options) {
return new Tab(options);
}

tab({
autoPlay:true,
autoTime:3000
});


最后我们通过调用tab({...})函数就可以对这个Tab进行配置了,目前只支持配置两项,1是是否自动播放,2是自动播放的间隔时长,虽然配置简陋,但是也算是利用面向对象的方法完成了我们的第一个可以配置的小插件了

细心的你们应该发现了最后实现了一个tab函数 里面『return new Tab()』,这个Tab,当我们以new的方式实例化的时候,它就是一个构照函数, 构造函数模式的目的就是为了创建一个自定义类,并且创建这个类的实例。

回顾下我们主要讲了哪些知识点

1.面向对象的属性,方法

2.函数的封装

3.构照函数的概念

4.如何暴露对象的接口

5.简单插件的编写

预告:

  下一节我们主要来讲下,面向对象的一个很重要的特性:继承;以及this的用法
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: