本文是在我开始学习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. 无比迅速敏捷地开发iOS超精美控件

    目录 前言 设计 编码 PaintCode 前言 自从人生第一篇博客<iOS中的预编译指令的初步探究>问世以来 浏览量竟然达到了360多,(路过的大神勿笑!)这些浏览量使我兴奋异常但又令我 ...

  2. flask _bootstrap中使用flash

    在模板中获取flash闪现的那段代码要和内容块放在同一级别上.不然网页上是看不到闪现的内容的. 比如在基模板里定义一个content block ,里面一个是get_flashed_messages代 ...

  3. 一个好用的ssh终端:MobaXterm

    WSL由于没有图形界面,所有操作都是在命令行里执行,平时用来编译和跑CFD代码其实还是挺方便.不过有时候要查看WSL里的文件就比较麻烦,这时可以用SFTP这类工具,连接过去后直接操作文件.试过几个这类 ...

  4. request.getSession(true/false)的区别

    javax.servlet.http.HttpServletRequest接口有两个方法:getSession(boolean)和getSession(). 具体什么区别,跟踪源码分析下,先摆出结论: ...

  5. vsftpd文件虚拟用户搭建

    关于vsftpd的原理这里就不多说了,下面红色部分有单独标出,突出显示,意思是这里的东西有额外的配置,全文的配置一定要跟着第二步的配置来,不要过程中随便改变参数,除非你看得懂,好了直接上配置过程 1. ...

  6. springboot(十三)-分库分表-手动配置

    sharding-jdbc简介 Sharding-JDBC直接封装JDBC API,可以理解为增强版的JDBC驱动,旧代码迁移成本几乎为零: 可适用于任何基于java的ORM框架,如:JPA, Hib ...

  7. [转] 两个静态html页面传值方法的总结

    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/csdn_ds/article/details/78393564 问题 因最近尝试实现客户端与服务端分 ...

  8. C# 数组基础

    一.数组的基础知识 1.数组有什么用? 如果需要同一个类型的多个对象,就可以使用数组.数组是一种数组结构,它可以包含同一个类型的多个元素. 2.数组的初始化方式 第一种:先声明后赋值 ]; array ...

  9. java动态加载机制

    假设有一个class,ClassLoader首先把它load到内存里的code segment(内存里存放代码段的),站在ClassLoader的角度,内存里的一个一个的class就是一个一个的对象, ...

  10. PHP 判断字符串 是否 包含另一个字符串

    1.stristr 忽略大小写 $string = 'Hello World!'; if(stristr($string, 'earth') === FALSE) { echo '"eart ...