本文是在我开始学习JavaScript继承时,对原型继承的一些理解和运用。文中所述的继承方式均是使用js特有的原型链方式,实际上有了ES6的类之后,实现继承的就变得十分简单了,所以这种写法现在也不在推荐使用了,对于对象的继承更推荐使用ES6的class来实现。我会在后续的文章中详细介绍这种实现继承的方式,欢迎关注。

2017年6月24日更新

------------------------------------------------------------------------------------------

以下为原文:

上一篇文中完成的封装,还存在一个小问题,就是该轮播对象不能在同一页面中重复使用,本文将通过组合使用javascript的构造函数和原型模式创建对象来解决这个问题。

没有看过上一篇文章的朋友可以点此查看上一篇文章 (jQuery图片轮播(一)轮播实现并封装)

首先回顾一下,上文的问题所在,上文中的carsouel对象是采用字面量的方式来定义的,这样carsouel本就是一个实例,想要使用在多处时,这个对象的方法会发生冲突,最终只会执行最后的那一个。而通过采用构造函数的方式来定义对象carsouel,每次需要使用时只需要用new操作符来实例化一个新对象,页面中需要几处轮播就实例化几个对象,这样就可以满足需求。所以,将代码改成以下形式。

function Carousel(){
this.now = 0; //当前显示的图片索引
this.hasStarted = false; //是否开始轮播
this.interval = null; //定时器
this.liItems = null; //要轮播的li元素集合
this.len = 0; //liItems的长度
this.aBox : null; //包含指示器的dom对象
this.bBox : null; //包含前后按钮的dom对象 /**
* 初始化及控制函数
* @param bannnerBox string 包含整个轮播图盒子的id或class
* @param aBox string 包含指示器的盒子的id或class
* @param btnBox string 包含前后按钮的盒子的id或class
*/
this.startPlay = function(bannnerBox,aBox,btnBox) {
//初始化对象参数
var that = this;
this.liItems = $(bannnerBox).find('ul').find('li');
this.len = this.liItems.length;
this.aBox = $(bannnerBox).find(aBox);
this.bBox = $(bannnerBox).find(btnBox);
//让第一张图片显示,根据轮播图数量动态创建指示器,并让第一个指示器处于激活状态,隐藏前后按钮
this.liItems.first('li').css({'opacity': 1, 'z-index': 1}).siblings('li').css({'opacity': 0, 'z-index': 0});
var aDom = '';
for (var i = 0; i < this.len; i++){
aDom += '<a></a>';
}
$(aDom).appendTo(this.aBox);
this.aBox.find('a:first').addClass("indicator-active");
this.bBox.hide();
//鼠标移入banner图时,停止轮播并显示前后按钮,移出时开始轮播并隐藏前后按钮
$(bannnerBox).hover(function (){
that.stop();
that.bBox.fadeIn(200);
}, function (){
that.start();
that.bBox.fadeOut(200);
});
//鼠标移入指示器时,显示对应图片,移出时继续播放
this.aBox.find('a').hover(function (){
that.stop();
var out = that.aBox.find('a').filter('.indicator-active').index();
that.now = $(this).index();
if(out!=that.now) {
that.play(out, that.now)
}
}, function (){
that.start();
});
//点击左右按钮时显示上一张或下一张
$(btnBox).find('a:first').click(function(){that.next()});
$(btnBox).find('a:last').click(function(){that.prev()});
//开始轮播
this.start()
};
//前一张函数
this.prev = function (){
var out = this.now;
this.now = (--this.now + this.len) % this.len;
this.play(out, this.now);
};
//后一张函数
this.next = function (){
var out = this.now;
this.now = ++this.now % this.len;
this.play(out, this.now);
};
/**
* 播放函数
* @param out number 要消失的图片的索引值
* @param now number 接下来要轮播的图的索引值
*/
this.play = function (out, now){
this.liItems.eq(out).stop().animate({opacity:0,'z-index':0},500).end().eq(now).stop().animate({opacity:1,'z-index':1},500);
this.aBox.find('a').removeClass('indicator-active').eq(now).addClass('indicator-active');
};
//开始函数
this.start = function(){
if(!this.hasStarted) {
this.hasStarted = true;
var that = this;
this.interval = setInterval(function(){
that.next();
},2000);
}
};
//停止函数
this.stop = function (){
clearInterval(this.interval);
this.hasStarted = false;
}
};

调用时采用new操作符,如下:

    var banner1 = new Carousel();
var banner2 = new Carousel();
var banner3 = new carousel();
banner1.startPlay('#J_bg_ban1','#J_bg_indicator1','#J_bg_btn1');
banner2.startPlay('#J_bg_ban2','#J_bg_indicator2','#J_bg_btn2');
banner3.startPlay('#J_bg_ban3','#J_bg_indicator3','#J_bg_btn3');

上述方法可实现需求,但是仔细分析发现,这与上一篇文中使用extend复制对象的方法几乎是一样的,这里的new操作符实际上也是将构造函数完全复制了一份出来作为一个新的对象,那就和上文中提到的方法存在共同的缺点,那就是内部函数不能复用,每次执行用new操作符来实例化,都会创建新的内部函数,这也是单独使用构造函数来自定义对象的缺点。

在Carousel对象内的play方法、next方法、prev方法、strat方法、stop方法其实都是可以共用的,多个轮播件共用这些函数是完全没有问题的,而初始化方法需要在每个实例上单独创建。单独使用构造函数创建对象,在使用new操作符创建新实例的时候,初始化方法会被重新在每个实例上创建一遍,这正是我们想要的结果,而play方法、next方法、prev方法、start方法、stop方法这些可共用的方法也会在新实例上被重新创建,而创造多个完成一样任务的方法是完全没有必要的,所以需要将这些共有的方法提出来,让所有Carousel对象的实例都可以公用,这样就可以解决函数复用的问题。

通过将这些共用的方法写在Carousel的原型对象上,在创建Carousel新实例的时候就可以通过原型链来共享这些方法,这样这些公用函数也就得到了复用,代码如下:

   // 构造函数加原型形式

    /**
* 构造函数初始化及开始轮播
* @param bannnerBox string 包含整个轮播图盒子的id或class
* @param aBox string 包含指示器的盒子的id或class
* @param btnBox string 包含前后按钮的盒子的id或class
*/
function Carousel(bannnerBox, aBox, btnBox) {
this.now = 0; //当前显示的图片索引
this.hasStarted = false; //是否开始轮播
this.interval = null; //定时器
this.liItems = null; //要轮播的li元素集合
this.len = 0; //liItems的长度
this.aBox = null; //包含指示器的dom对象
this.bBox = null; //包含前后按钮的dom对象 //初始化函数
this.init = function () {
//初始化对象参数
var that = this;
this.liItems = $(bannnerBox).find('ul').find('li');
this.len = this.liItems.length;
this.aBox = $(bannnerBox).find(aBox);
this.bBox = $(bannnerBox).find(btnBox);
//让第一张图片显示,根据轮播图数量动态创建指示器,并让第一个指示器处于激活状态,隐藏前后按钮
this.liItems.first('li').css({
'opacity': 1,
'z-index': 1
}).siblings('li').css({
'opacity': 0,
'z-index': 0
});
var aDom = '';
for (var i = 0; i < this.len; i++) {
aDom += '<a></a>';
}
$(aDom).appendTo(this.aBox);
this.aBox.find('a:first').addClass("indicator-active");
this.bBox.hide();
//鼠标移入banner图时,停止轮播并显示前后按钮,移出时开始轮播并隐藏前后按钮
$(bannnerBox).hover(function () {
that.stop();
that.bBox.fadeIn(200);
}, function () {
that.start();
that.bBox.fadeOut(200);
});
//鼠标移入指示器时,显示对应图片,移出时继续播放
this.aBox.find('a').hover(function () {
that.stop();
var out = that.aBox.find('a').filter('.indicator-active').index();
that.now = $(this).index();
if (out != that.now) {
that.play(out, that.now)
}
}, function () {
that.start();
});
//点击左右按钮时显示上一张或下一张
$(btnBox).find('a:first').click(function () {
that.next()
});
$(btnBox).find('a:last').click(function () {
that.prev()
});
}
//初始化
this.init();
//开始轮播
this.start();
} /**
* 播放函数
* @param out number 要消失的图片的索引值
* @param now number 接下来要轮播的图的索引值
*/
Carousel.prototype.play = function (out, now) {
this.liItems.eq(out).stop().animate({
opacity: 0,
'z-index': 0
}, 500).end().eq(now).stop().animate({
opacity: 1,
'z-index': 1
}, 500);
this.aBox.find('a').removeClass('indicator-active').eq(now).addClass('indicator-active');
} //前一张函数
Carousel.prototype.prev = function () {
var out = this.now;
this.now = (--this.now + this.len) % this.len;
this.play(out, this.now)
} //后一张函数
Carousel.prototype.next = function () {
var out = this.now;
this.now = ++this.now % this.len;
this.play(out, this.now);
} //开始函数
Carousel.prototype.start = function () {
if (!this.hasStarted) {
this.hasStarted = true;
var that = this;
this.interval = setInterval(function () {
that.next();
}, 2000);
}
}
//停止函数
Carousel.prototype.stop = function () {
clearInterval(this.interval);
this.hasStarted = false;
} $(function () {
var banner1 = new Carousel('#J_bg_ban1', '#J_bg_indicator1', '#J_bg_btn1');
var banner2 = new Carousel('#J_bg_ban2', '#J_bg_indicator2', '#J_bg_btn2');
});

在这里对Carousel对象的原型对象进行了扩展,将play方法、next方法,perv方法,start方法和stop方法写进了Carousel的原型对象中,这样每次实例化的对象就可以共用这些方法。当然,实例化的方法也是使用new操作符。这样我们就可以在同一页面内多次使用这个轮播对象了。

这种组合使用构造函数和原型的模式,是创建自定义类型最常用的方法,至此我们就完成了这个简单轮播对象的封装。

jQuery轮播图(二)利用构造函数和原型创建对象以实现继承的更多相关文章

  1. jQuery轮播图(一)轮播实现并封装

    利用面向对象自己动手写了一个封装好的jquery轮播组件,可满足一般需求,不仅使用简单且复用性高. demo:点此预览 代码地址:https://github.com/zsqosos/componen ...

  2. jQuery轮播图(手动点击轮播)

    下面来看看最终做的手动点击轮播效果: 一.原理说明 (1)首先是轮播图的架构,我采用了一个最外边的大div包住两个小div,一个小div里面放四张图片,另一个小div里面放四个数字按钮 (2)对最外边 ...

  3. Jquery 轮播图简易框架

    =====================基本结构===================== <div class="carousel" style="width: ...

  4. jQuery轮播图--不使用插件

    说明:引入jquery.min.js    将轮播图放入imgs文件夹 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitiona ...

  5. jquery 轮播图实例

    实现效果:1.图片每2秒钟切换1次. 2.当鼠标停留在整个页面上时,图片不进行轮播. 3.当点击右下角的小球时,出现该选项的对应图片,而且切换页选项的背景颜色发生相应的变化. 4.当图片发生轮播切换时 ...

  6. 《第31天:JQuery - 轮播图》

    源码下载地址:链接:https://pan.baidu.com/s/16K9I... 提取码:0ua2 写这篇文章,当做是对自已这一天的一个总结.写轮播图要准备的东西:三张尺寸大小一样的图片.分为三个 ...

  7. jquery 轮播图

    slider.js (function(){ /** parent //父容器 changeTime //每次间隔几秒切换下一条 leaveTime //鼠标从小图上离开过后几秒继续切换 index ...

  8. 超级简单的jquery轮播图demo

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  9. 支持触屏的jQuery轮播图插件

    移动轮播图我看到两类, 一款是无线天猫的m.tmall.com和携程,实现了无缝轮播. 一款是蘑菇街的,没有实现无缝轮播. 我自己重写一个,类似天猫. 1.页面代码 <!DOCTYPE html ...

随机推荐

  1. jpetStore 学习总结(2)

    在写jpetstore时,最难理解的应该是数据库还有每个表之间的关系了,我在这里对数据库简单的介绍. 以下是数据库的所有表:    account表是个人信息表,里面包括用户的名字,邮箱,地址,哪个城 ...

  2. 网络编程-echo服务器

    代码: #coding="utf-8" #name=echo服务器 from socket import * #1.创建套接字 udpSocket = socket(AF_INET ...

  3. springcloud(九)-Feign使用Hystrix

    前言 上一篇我们使用注解@HystrixCommond的fallbackMethod属性实现回退.然而,Feign是以接口形式工作的,它没有方法体,上一篇讲解的方式显然不适用于Feign. 那么Fei ...

  4. Secondary NameNode究竟是做什么的

    Secondary NameNode:它究竟有什么作用? 在hadoop中,有一些命名不好的模块,Secondary NameNode是其中之一.从它的名字上看,它给人的感觉就像是NameNode的备 ...

  5. 2019.4.25 表格表单与HTML5 && CSS3

    目录 表格 标签 属性 表格间距离 表格的内边距 表格的边框 样式 边框合并 行合并 列合并 display 表单 标签 属性 提交的网址 请求方式 input相关 扩大响应范围 字符 密码 单选框 ...

  6. chm 已取消到该网页的导航,打不开!

    方法 11. 双击此 .chm 文件. 2. 在“打开文件安全警告”对话框,单击以清除“打开此文件前始终询问”复选框. 3. 单击“打开”. 方法 21. 右键单击该 CHM 文件,然后单击“属性”. ...

  7. CentOS 7进入救援模式的方法

    CentOS 7版本进入救援模式并修改密码:方法1: runlevel 显示当前的运行级别(进入救援模式需要进入单用户模式) 方法2: ①.开机时随便按下键盘,进入系统选择菜单 ②.选择第一项,按e键 ...

  8. struts2上传单个文件

    项目目录: struts.xml配置: <constant name="struts.enable.DynamicMethodInvocation" value=" ...

  9. java.lang.IllegalStateException: Unknown Priority XXXX 的解决方法

    异常信息: java.lang.IllegalStateException: Unknown Priority SYS_ERR_SMS at org.apache.log4j.Category.pri ...

  10. 删除eclipse无效的工作空间路径

    eclipse会记录我们使用过的工作空间的路径,方便下面使用.也可以根据自己的需要删除无用的工作空间路径.