描述
本人是从事前端一年的工作的小白,也想拥有自己的博客,便于自己可以记录学习的过程,同时可以把方法和技巧分享给大家,由于本人能力有限,也是一直在前端领域学习中,所以如果有不对的地方还请大家指点,与大家共进步。
最近一直想学习插件编写的方法,(注:不管是js插件编写还是jq的插件编写都需要有一定的js知识面)。从网上找了很多例子学习,但是都不是很理解插件编写的思想是什么。于是,本人意识到是我js知识还不够。于是继续读了javaScript高级程序设计这本书,学习了原型与原型链,this的作用,以及面向对象设计思想。在学习原型与原型链的时候,我从网上找了很多学习资源。本人认为原型与原型链是javaScript这本语言的精髓,同时javaScript也沿用了流行的面向程序设计。强调!!!要好好吃透。这是本人第一次写博客,如果哪里不好还请大家指正,如果大家喜欢对大家的工作或者学习有帮助请大家支持一下我,以后慢慢的也会书写更多的教程与大家一起分享。
阶段
接下来就给大家推荐一下学习Jquery插件编写的方法与过程:
阶段1.学习javaScript的原型与原型链以及面向程序设计思想
百度前端技术学院javaScript教程-------(第四十二天到第四十三天:开一家餐厅吧(一)---- 第五十天到第五十三天:开一家餐厅吧(四))
这是学习原型原型链与面向程序设计的资源,大家要可以好好研究。若大家有更好的资源可以在评论中推荐。这一阶段是给想提高js认知的朋友推荐的,如果有的人已经掌握直接看阶段2
阶段2.学习Jquery插件的编写
在这一阶段,我会一步一步的教大家如何进行插件的编写。本人自己写了一个Out.js 这个插件的效果是页面文字可以像键盘输入文字一样输 出,和按BackSpace键的效果。如下图:
2.1JQuery插件开发模式
在这一节我们先通过一些简单的例子去学习jQuery插件开发的主要三中方式:1.通过.fn向JQuery挂载方法,这种方式后期应用的时候可以直接.widget()应用JQuery UI的部分工厂方式创建
2.1.1.通过$.extend()方式编写
首先我们通过$.extend()方式编写,运行结果我就不截图了可以直接复制代码自己运行一下。
$.extend({
sayBay:function(name){
console.log('Bay,'+(name ? name : 'Dude'))
}
});
$.sayBay();//不传参
$.sayBay('Demo');//传参
以上就是一个最简单的JQuery插件。但这种编写方式无法利用JQuery强有力的选择器带来便利,所以大多情况大家会用第二种来开发自己的插件。
2.1.2.通过$.fn向JQuery挂载方法
最简单的方法如下
$.fn.out = function(options){
//填写自己的代码
}
这里的(元素).out()来实现调用。
注:由于楼主目前只着重学习了第二种插件编写的方法,第三种就不做介绍了。以后有机会学习,在给大家做一个完整的demo,下面就开始自己的插件编写。
2.2 初始化一个Out类
所谓的初始化一个Out类无非就是声明一个函数名字叫Out,注这个函数是声明在$.fn.out方法之外的
可以这样声明
var Out = function(el,opt){};
有可以声明,都是javaScript中对象的声明方式
function Out(el,opt){}
这里先不说两个参数el,opt,后面用到的时候我在给大家解释
2.3 将Out类声明到$.fn.out函数中
在out中声明完之后,插件的整体架构就打好了,就可以在元素上像调用jquery本身有的方法一样去调用out方法,这样配置好之后,我们所要编写的业务逻辑代码都写在Out这个类中就可以了。
$.fn.out = function(el,opt){ new Out(el,opt);//实例化Out类}
2.4 Out类中常见的配置项
像上面图片中那样文字输出与回退。在Out类中都是有配置的
var Out = function(el,opt){
this.$element = el;
this.defaults = {
//输出字符串,默认字符串
outStr:['my name is Post-90s!','the blog is my first project based on line!','I love my blog as I like my life!'] };
};
在Out类中,this值的就是Out,所以在Out中我们可以通过this.detaults在声明一个变量在这个变量中我们给其一个默认的需要输出的字符串数组。这个this.defaults是我们自己声明的,它的作用就是在Out类初始化的时候给这个类进行一个默认值的配置。在这个类中我们可以定义很多属性,像是否无限循环的loop,输出与回退的速度。这都是后期我们可以扩展出来的。
插件既然有默认配置,那么也就可以通过调用out方法的时候给其进行动态的配置,这里通过用.extend({},this.defaults,opt);```
通过三元运算符进行赋值。在其他时候,如果我们需要用到什么属性就可以直接this.属性名 = 属性值;这样运用,如果这个属性可以进行动态配置那么就可以写在defaults这个属性里面然后在进行三元算符的合并。
整理以上代码
var Out = function(el,opt){
this.$element = el;
this.defaults = {
//输出字符串,默认字符串
outStr:['my name is Post-90s!','the blog is my first project based on line!','I love my blog as I like my life!'] };
this.options = $.extend({},this.defaults,opt);
this.contentStr = this.options.outStr?this.options.outStr:this.defaults.outStr;
}
注:这里的el是指在外部调用out()的时候上下文
2.4 将实现的逻辑部分通过函数挂到Out类的原型上
Out.prototype = {
//初始化函数
init:function(){
}
//输出函数
outContent:function(){
}
//回退函数
backContent:function(){
}
}
在初始化的函数init()中我们可以给其进行初始化的操作,将init()方法在Out函数中通过this.init()调用这样在声明实体类的时候就自动调用了这个函数。
在outContent()与backContent()两个方法中就是实现文字回退与输出的效果,在这两个函数中,通过定时器setInterval来实现的。具体的逻辑我就不在一一多说直接上代码,然后将上面所讲的代码整理好如下
代码整理好如下
(function($,window,document,undefined){
var Out = function(el,opt){
this.$element = el;
this.defaults = {
//输出字符串,默认字符串
outStr:['my name is Post-90s!','the blog is my first project based on line!','I love my blog as I like my life!'] };
this.options = $.extend({},this.defaults,opt);
this.contentStr = this.options.outStr?this.options.outStr:this.defaults.outStr;
this.init(this.$element);
//初始化函数
}
Out.prototype = {
//初始化函数
init:function(el){
var self = el;
//把数组的第一组值赋值给span
var textStr = this.defaults.outStr[0];
//调用outContent 输出第一组的文字特效
this.outContent(el,textStr);
}
//输出函数
/*** 输出文字 * @param el 调用的元素 * */
outContent:function(){
var self = el;//初始化文字的时候进行输出//console.log(str.split(''));//将字符安转换为字符数组 var charArr = str.split('');var that = this; clearInterval(self.ouTime);self.ouTime = setInterval(function () { var text = self.text(); if(that.endFlag){ if(that.OutCount < charArr.length){ //后期改为options里面的配置 self.text(text + charArr[that.OutCount]); that.OutCount = that.OutCount + 1; }else{ clearInterval(self.ouTime); that.endFlag = false; that.OutCount = 0; that.backContent(el); } } },this.outSpeed);
}
//回退函数
backContent:function(){
//初始化
span var self = el;
//保存this的指向
var that = this;
clearInterval(self.timeOut);
self.timeOut = setInterval(function(){
//当第一次输出与回退文字执行完后,进行判断 做count+1 将outStr[count+1]的值赋值给outContent
if(self.text().length == 0){ if(that.count < that.defaults.outStr.length - 1){ //console.log(that.count); that.count = that.count+1; clearInterval(self.timeOut); that.endFlag = true; that.outContent(el,that.defaults.outStr[that.count]); } else{ //判断是否进行循环播放 if(that.loop){ that.count = 0; }else{ //如果不进行循环,则终止定时器 clearInterval(self.timeOut); } } }else{ self.text(self.text().substring(0,self.text().length- 1)); } },this.backSpeed);
}
}
//挂载到$的原型中,初始化实体类。
$.fn.out = function(options){ new Out(this,options); }
}(jQuery,window,document)
我们知道JavaScript中无法用花括号方便地创建作用域,但函数却可以形成一个作用域,域内的代码是无法被外界访问的。如果我们将自己的代码放入一个函数中,那么就不会污染全局命名空间,同时不会和别的代码冲突。
如上面我们定义了一个Out全局变量,它会被附到全局的window对象上,为了防止这种事情发生,你或许会说,把所有代码放到jQuery的插件定义代码里面去啊,也就是放到.fn.out里面我们其实应该更专注于插件的调用,以及如何与jQuery互动。
所以保持原来的代码不变,我们将所有代码用自调用匿名函数包裹。另外还有一个好处就是,自调用匿名函数里面的代码会在第一时间执行,页面准备好过后,上面的代码就将插件准备好了,以方便在后面的代码中使用插件。
目前为止似乎接近完美了。如果再考虑到其他一些因素,比如我们将这段代码放到页面后,前面别人写的代码没有用分号结尾,或者前面的代码将window, undefined等这些系统变量或者关键字修改掉了,正好我们又在自己的代码里面进行了使用,那结果也是不可预测的,这不是 我们想要的。。
将系统变量以参数形式传递到插件内部也是个不错的实践。
当我们这样做之后,window等系统变量在插件内部就有了一个局部的引用,可以提高访问速度,会有些许性能的提升
最后我们得到一个非常安全结构良好的代码,这样我们在最后在页面引入Out.js
在你选择的元素上面直接调用