亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

jQuery彈簧插件編寫基礎(chǔ)之“又見彈窗”

 更新時(shí)間:2015年12月11日 11:08:33   投稿:mrr  
本文通過具體實(shí)例給大家介紹jquery彈窗插件編寫基礎(chǔ)之又見彈簧的相關(guān)資料,對(duì)jquery彈簧插件編寫相關(guān)知識(shí)感興趣的朋友一起學(xué)習(xí)吧

本文將通過一個(gè)實(shí)例來引出jQuery插件開發(fā)中的一些細(xì)節(jié),首先介紹下jQuery插件開發(fā)的一些基礎(chǔ)知識(shí)。

jQuery的插件開發(fā)主要分為兩類:

1. 類級(jí)別,即在jQuery類本身上擴(kuò)展方法,類似與 $.ajax,$.get 等。

2. 對(duì)象級(jí)別,這里所謂的對(duì)象是指通過jQuery選擇器選中的jQuery對(duì)象,在該對(duì)象上添加方法。例如:$('div').css(), $('div').show() 等。

在實(shí)際開發(fā)中,我們通常選用對(duì)象級(jí)別的方法來開發(fā)插件,jQuery強(qiáng)大的選擇器及對(duì)象操作是我們選擇這種方式很大的一個(gè)原因。

接下來我們看看兩種方式的具體寫法是什么:

類級(jí)別的插件開發(fā)

$.extend({
  foo: function() {
    //...
  },
  bar: function() {
    //...
  }
})
//調(diào)用
$.foo();

在這里,對(duì)擴(kuò)展方法的命名需要考究一些,以免與jQuery類中的原有方法重名。即便如此,當(dāng)我們需要在類上擴(kuò)展多個(gè)方法時(shí)仍有可能會(huì)出現(xiàn)命名沖突的情況,為此我們可以創(chuàng)建自定義的命名空間:

$.myPlugin = {
  foo: function() {
    //...
  },
  bar: function() {
    //...
  }
}
 //調(diào)用
$.myPulgin.foo();

對(duì)象級(jí)別的插件開發(fā)

$.fn.foo = function() {
  //doSomething...
}
//調(diào)用(假設(shè)擁有一個(gè)id為obj的元素)
$('#obj').foo();
有個(gè)會(huì)問 fn 是什么東東?粘一段別人截取的jQuery源碼就明白了:
jQuery.fn = jQuery.prototype = {
  init: function(selector, context) {
    //....
  }
}

原來是原型鏈啊。。。

接收配置參數(shù)

在編寫一個(gè)插件時(shí),我們可以讓使用插件的人能按自己的意愿設(shè)置插件的一些屬性,這就需要插件有接收參數(shù)的功能,同時(shí)當(dāng)使用插件的人不傳入?yún)?shù)時(shí),插件內(nèi)部也有一套自己默認(rèn)的配置參數(shù)。

$.fn.foo = function(options) {
  var defaults = {
    color: '#000',
    backgroundColor: 'red'
  };
  var opts = $.extend({}, defaults, options); 
  alert(opts.backgroundColor); //yellow
}
$('#obj').foo({
  backgroundColor: 'yellow'  
})

這里的關(guān)鍵就是 $.extend 方法,它能夠?qū)?duì)象進(jìn)行合并。對(duì)于相同的屬性,后面的對(duì)象會(huì)覆蓋前面的對(duì)象。為什么extend方法第一個(gè)參數(shù)是一個(gè)空對(duì)象呢?因?yàn)樵摲椒〞?huì)將后者合并到前者上,為了不讓 defaults 被改變所以第一個(gè)參數(shù)設(shè)為空對(duì)象。

如果我們?cè)试S使用插件的人能夠設(shè)置默認(rèn)參數(shù),就需要將其暴露出來:

$.fn.foo = function(options) {
  var opts = $.extend({}, $.fn.foo.defaults, options); 
  alert(opts.backgroundColor);
}
$.fn.foo.defaults = {
  color: '#000',
  backgroundColor: 'red'
}

這樣就可以在外部對(duì)插件的默認(rèn)參數(shù)進(jìn)行修改了。

適當(dāng)?shù)谋┞兑恍┓椒?/strong>

$.fn.foo = function(options) {
  var opts = $.extend({}, $.fn.foo.defaults, options); 
  $.fn.foo.sayColor(opts.backgroundColor);
}
$.fn.foo.sayColor = function(bgColor) {
  alert(bgColor);
}
$.fn.foo.defaults = {
  color: '#000',
  backgroundColor: 'red'
}

改寫:

$.fn.foo.sayColor = function(bgColor) {
  alert('background color is ' + bgColor);
}

暴露插件中的一部分方法是很牛逼的,它使得別人可以對(duì)你的方法進(jìn)行擴(kuò)展、覆蓋。但是當(dāng)別人對(duì)你的參數(shù)或方法進(jìn)行修改時(shí),很可能會(huì)影響其他很多東西。所以在考慮要不要暴露方法時(shí)候要頭腦清楚,不確定的就不要暴露了。

保持函數(shù)的私有性

說到保持私有性,首先想到什么?沒錯(cuò),就是閉包:

;(function($) {
  $.fn.foo = function(options) {
    var opts = $.extend({}, $.fn.foo.defaults, options); 
    debug(opts.backgroundColor);
  }
  function debug(bgColors) {
    console.log(bgColors);
  }
  $.fn.foo.defaults = {
    color: '#000',
    backgroundColor: 'red'
  }
})(jQuery)

這是jQuery官方給出的插件開發(fā)方式,好處包括:1.沒有全局依賴 2.避免其他人破壞 3.兼容 '$' 與 'jQuery' 操作符。

如上,debug 方法就成了插件內(nèi)部的私有方法,外部無法對(duì)其進(jìn)行修改。在閉包前面加 ; 是防止進(jìn)行代碼合并時(shí),如果閉包前的代碼缺少分號(hào)從而導(dǎo)致后面報(bào)錯(cuò)的情況。

合并

;(function($) {
  //定義插件
  $.fn.foo = function(options) {
    //doSomething...
  }
  //私有函數(shù)
  function debug() {
    //doSomething...
  }
  //定義暴露函數(shù)
  $.fn.foo.sayColor = function() {
    //doSomething...
  }
  //插件默認(rèn)參數(shù)
  $.fn.foo.default = {
    color: '#000',
    backgroundColor: 'red'
  }
})(jQuery);

以上的代碼就創(chuàng)建了一個(gè)完整且規(guī)范的插件骨架,看起來雖然很簡單但在實(shí)際開發(fā)中還是有很多技巧與注意事項(xiàng),接下來我們通過一個(gè)實(shí)例來看看。

想了半天,覺得將彈窗做成插件當(dāng)作示例是比較合適的。在開發(fā)之前我們先構(gòu)想一下這個(gè)彈窗插件的結(jié)構(gòu)與功能等:

從上圖我們看出包括三個(gè)部分,標(biāo)題、內(nèi)容、以及按鈕組。這里需要申明一點(diǎn),我們不想只做成瀏覽器里默認(rèn)的只包含一個(gè)按鈕的alert框,而是使用者可以自定義按鈕數(shù)量,這樣該彈出框也能完成類似confirm框的功能。

搭建插件骨架

function SubType($ele, options) {
  this.$ele = $ele;
  this.opts = $.extend({}, $.fn.popWin.defaults, options);
}
SubType.prototype = {
  createPopWin: function() {
  }
};
$.fn.popWin = function(options) {
  //this指向被jQuery選擇器選中的對(duì)象
  var superType = new SubType(this, options);
  superType.createPopWin();
};
$.fn.popWin.defaults = {};

1. 我們創(chuàng)建了基于對(duì)象且名為 popWin 方法,并將 defaults 默認(rèn)配置參數(shù)暴露出去以便使用的人進(jìn)行修改;

2. 這里使用面向?qū)ο蟮姆椒▉砉芾砦覀兊乃接泻瘮?shù),createPopWin 方法就是我們私有的用來創(chuàng)建彈窗的函數(shù)。

3. 在插件被調(diào)用時(shí)將jq對(duì)象與自定義的參數(shù)傳入構(gòu)造函數(shù)中并實(shí)例化。

調(diào)用

設(shè)想一下我們?cè)撛趺凑{(diào)用這個(gè)插件呢?我們可以在自己的文檔樹中合適的位置插入一個(gè) div 元素,選中該 div 并調(diào)用我們定義在jQuery對(duì)象上的 popWin 方法。

$('#content').popWin({
  a: 1,
  b: 2,
  callback: function() {}
});

調(diào)用 popWin 的同時(shí)傳入自定義的配置參數(shù),之后被選中的 div 元素就被神奇的轉(zhuǎn)化成一個(gè)彈窗了!當(dāng)然,這只是我們的設(shè)想,下面開始碼代碼。

確定默認(rèn)配置

$.fn.popWin.defaults = {
  width: '600', //彈窗寬
  height: '250', //彈窗高
  title: '標(biāo)題', //標(biāo)題
  desc: '描述', //描述
  winCssName: 'pop-win', //彈窗的CSS類名
  titleCssName: 'pop-title', //標(biāo)題區(qū)域的CSS類名
  descCssName: 'pop-desc', //描述區(qū)域的CSS類名
  btnAreaCssName: 'pop-btn-box', //按鈕區(qū)域的CSS類名
  btnCssName: 'pop-btn', //單個(gè)按鈕的CSS類名
  btnArr: ['確定'], //按鈕組
  callback: function(){} //點(diǎn)擊按鈕之后的回調(diào)函數(shù)
}

我們定義了如上的參數(shù),為什么有要傳入這么多的CSS類名呢?1. 為了保證JS與CSS盡可能的解耦。 2. 你的樣式有很大可能別人并不適用。所以你需要配置一份樣式表文件來對(duì)應(yīng)你的默認(rèn)類名,當(dāng)別人需要更改樣式時(shí)可以傳入自己編寫的樣式。

按鈕組為一個(gè)數(shù)組,我們的彈窗需要根據(jù)其傳入的數(shù)組長度來動(dòng)態(tài)的生成若干個(gè)按鈕。回調(diào)函數(shù)的作用是在用戶點(diǎn)擊了某個(gè)按鈕時(shí)返回他所點(diǎn)擊按鈕的索引值,方便他進(jìn)行后續(xù)的操作。

彈窗DOM創(chuàng)建

var popWinDom,titleAreaDom,descAreaDom,btnAreaDom;
SubType.prototype = {
  createPopWin: function() {
    var _this = this;
    //首次創(chuàng)建彈窗
    //背景填充整個(gè)窗口
    this.$ele.css({
      position: 'fixed',
      top: 0,
      left: 0,
      right: 0,
      bottom: 0,
      backgroundColor: 'rgba(0,0,0,0.4)',
      overflow: 'hidden'
    });
    
    //窗口區(qū)域
    popWinDom = $('<div><div></div><div></div><div></div></div>').css({
      width: this.opts.width,
      height: this.opts.height,
      position: 'absolute',
      top: '30%',
      left: '50%',
      marginLeft: '-' + (this.opts.width.split('px')[0] / 2) + 'px'
    }).attr('class',this.opts.winCssName);
    
    //標(biāo)題區(qū)域
    titleAreaDom = popWinDom.find('div:eq(0)')
              .text(this.opts.title)
              .attr('class',this.opts.titleCssName);
    
    //描述區(qū)域
    descAreaDom = popWinDom.find('div:eq(1)')
            .text(this.opts.desc)
            .attr('class',this.opts.descCssName);
    //按鈕區(qū)域   
    btnAreaDom = popWinDom.find('div:eq(2)')
            .attr('class',this.opts.btnAreaCssName);
    
    //插入按鈕
    this.opts.btnArr.map(function(item, index) {
      btnAreaDom.append($('<button></button>')
        .text(item)
        .attr({'data-index':index, 'class':_this.opts.btnCssName})
        .on('click', function() {
          _this.opts.callback($(this).attr('data-index'));
        }));
      });
    
    this.$ele.append(popWinDom);
  }
}

1. 首先命名了四個(gè)變量用來緩存我們將要?jiǎng)?chuàng)建的四個(gè)DOM,將傳入的jQuery對(duì)象變形成覆蓋整個(gè)窗口半透明元素;

2. 創(chuàng)建窗口DOM,根據(jù)傳入的高、寬來設(shè)置尺寸并居中,之后另上傳入的窗口CSS類名;

3. 創(chuàng)建標(biāo)題、描述、按鈕組區(qū)域,并將傳入的標(biāo)題、描述內(nèi)容配置上去;

4. 動(dòng)態(tài)加入按鈕,并為按鈕加上data-index的索引值。注冊(cè)點(diǎn)擊事件,點(diǎn)擊后調(diào)用傳入的回調(diào)函數(shù),將索引值傳回。

好了,我們先看下效果。調(diào)用如下:

$('#content').popWin({
  width: '500',
  height: '200',
  title: '系統(tǒng)提示',
  desc: '注冊(cè)成功',
  btnArr: ['關(guān)閉'],
  callback: function(clickIndex) {
    console.log(clickIndex);
  }
});

可以看到一個(gè)彈窗的DOM已被渲染到頁面中了,當(dāng)點(diǎn)擊關(guān)閉按鈕時(shí)控制臺(tái)會(huì)打印出 "0",因?yàn)榘粹o組只有一個(gè)值嘛,當(dāng)然是第0個(gè)了。

如果我們需要多次調(diào)用這個(gè)彈窗,每次都要傳入高、寬我會(huì)覺得很麻煩。這時(shí)我們可以直接在一開始修改插件內(nèi)部的默認(rèn)配置,這也是我們將默認(rèn)配置暴露的好處:

$.fn.popWin.defaults.width = '500';
$.fn.popWin.defaults.height = '200';

要注意的當(dāng)然是不能直接改變defaults的引用,以免露掉必須的參數(shù)。 這樣以后的調(diào)用都無需傳入尺寸了。

我們加一個(gè)按鈕并且傳入一個(gè)自定義的樣式看看好使不呢?

$('#content').popWin({
  title: '系統(tǒng)提示',
  desc: '是否刪除當(dāng)前內(nèi)容',
  btnArr: ['確定','取消'],
  winCssName: 'pop-win-red',
  callback: function(clickIndex) {
    console.log(clickIndex);
  }
});

可以看到都是生效了的,當(dāng)點(diǎn)擊“確定”按鈕時(shí)回調(diào)函數(shù)返回 0,點(diǎn)擊“取消”按鈕時(shí)回調(diào)函數(shù)返回 1。這樣使用插件的人就知道自己點(diǎn)擊的是哪一個(gè)按鈕,以完成接下來的操作。

顯示&隱藏

接下來要進(jìn)行打開、關(guān)閉彈窗功能的開發(fā)?;叵肷厦娼榻B的概念,我們想讓使用該插件的人能夠?qū)@兩個(gè)方法進(jìn)行擴(kuò)展或者重寫,所以將這兩個(gè)方法暴露出去:

$.fn.popWin.show = function($ele) {
  $ele.show();
}
$.fn.popWin.hide = function($ele) {
  $ele.hide();
}

之后在createPopWin方法中需要的地方調(diào)用這兩個(gè)方法。

這里多強(qiáng)調(diào)一點(diǎn),也是做彈窗控件不可避免的一點(diǎn):只有當(dāng)我們點(diǎn)擊按鈕以及灰色背景區(qū)域時(shí)允許彈窗關(guān)閉,點(diǎn)擊彈窗其他地方不允許關(guān)閉。由于彈窗屬于整個(gè)灰色區(qū)域的子節(jié)點(diǎn),必然牽扯到的就是事件冒泡的問題。

所以在給最外層加上點(diǎn)擊關(guān)閉的事件時(shí),要在彈窗區(qū)域阻止事件冒泡。

popWinDom = $('<div><div></div><div></div><div></div></div>').css({
  width: this.opts.width,
  height: this.opts.height,
  position: 'absolute',
  top: '30%',
  left: '50%',
  marginLeft: '-' + (this.opts.width.split('px')[0] / 2) + 'px'
}).attr('class',this.opts.winCssName).on('click', function(event) {
  event.stopPropagation();
});

二次打開

我們只需要在第一次調(diào)用插件時(shí)創(chuàng)建所有創(chuàng)建DOM,第二次調(diào)用時(shí)只更改其參數(shù)即可,所以在createPopWin方法最前面加入如下方法:

if (popWinDom) { //彈窗已創(chuàng)建
  popWinDom.css({
    width: this.opts.width,
    height: this.opts.height
  }).attr('class',this.opts.winCssName);
  titleAreaDom.text(this.opts.title).attr('class',this.opts.titleCssName);
  descAreaDom.text(this.opts.desc).attr('class',this.opts.descCssName);
  btnAreaDom.html('').attr('class',this.opts.btnAreaCssName);
  this.opts.btnArr.map(function(item, index) {
    btnAreaDom.append($('<button></button>')
      .text(item)
      .attr('data-index',index)
      .attr('class',_this.opts.btnCssName)
      .on('click', function() {
        _this.opts.callback($(this).attr('data-index'));
        $.fn.popWin.hide(_this.$ele);
      }));
    });
  $.fn.popWin.show(this.$ele);
  return;
}

合并整個(gè)插件代碼

;(function($) {
  function SubType(ele, options) {
    this.$ele = ele;
    this.opts = $.extend({}, $.fn.popWin.defaults, options);
  }
  var popWinDom,titleAreaDom,descAreaDom,btnAreaDom;
  SubType.prototype = {
    createPopWin: function() {
      var _this = this;
      if (popWinDom) { //彈窗已創(chuàng)建
        popWinDom.css({
          width: this.opts.width,
          height: this.opts.height
        }).attr('class',this.opts.winCssName);
        titleAreaDom.text(this.opts.title).attr('class',this.opts.titleCssName);
        descAreaDom.text(this.opts.desc).attr('class',this.opts.descCssName);
        btnAreaDom.html('').attr('class',this.opts.btnAreaCssName);
        this.opts.btnArr.map(function(item, index) {
          btnAreaDom.append($('<button></button>')
            .text(item)
            .attr('data-index',index)
            .attr('class',_this.opts.btnCssName)
            .on('click', function() {
              _this.opts.callback($(this).attr('data-index'));
              $.fn.popWin.hide(_this.$ele);
            }));
        });
        $.fn.popWin.show(this.$ele);
        return;
      }
      //首次創(chuàng)建彈窗
      this.$ele.css({
        position: 'fixed',
        top: 0,
        left: 0,
        right: 0,
        bottom: 0,
        backgroundColor: 'rgba(0,0,0,0.4)',
        overflow: 'hidden',
        display: 'none'
      }).on('click', function() {
        $.fn.popWin.hide(_this.$ele);
      });
      popWinDom = $('<div><div></div><div></div><div></div></div>').css({
        width: this.opts.width,
        height: this.opts.height,
        position: 'absolute',
        top: '30%',
        left: '50%',
        marginLeft: '-' + (this.opts.width.split('px')[0] / 2) + 'px'
      }).attr('class',this.opts.winCssName).on('click', function(event) {
        event.stopPropagation();
      });
      titleAreaDom = popWinDom.find('div:eq(0)')
              .text(this.opts.title)
              .attr('class',this.opts.titleCssName);
      descAreaDom = popWinDom.find('div:eq(1)')
              .text(this.opts.desc)
              .attr('class',this.opts.descCssName);
      btnAreaDom = popWinDom.find('div:eq(2)')
              .attr('class',this.opts.btnAreaCssName);
      this.opts.btnArr.map(function(item, index) {
        btnAreaDom.append($('<button></button>')
          .text(item)
          .attr({'data-index':index, 'class':_this.opts.btnCssName})
          .on('click', function() {
            _this.opts.callback($(this).attr('data-index'));
            $.fn.popWin.hide(_this.$ele);
          }));
      });
      this.$ele.append(popWinDom);
      $.fn.popWin.show(this.$ele);
    }
  }
  $.fn.popWin = function(options) {
    var superType = new SubType(this, options);
    superType.createPopWin();
    return this;
  }
  $.fn.popWin.show = function($ele) {
    $ele.show();
  }
  $.fn.popWin.hide = function($ele) {
    $ele.hide();
  }
  $.fn.popWin.defaults = {
    width: '600',
    height: '250',
    title: 'title',
    desc: 'description',
    winCssName: 'pop-win',
    titleCssName: 'pop-title',
    descCssName: 'pop-desc',
    btnAreaCssName: 'pop-btn-box',
    btnCssName: 'pop-btn',
    btnArr: ['確定'],
    callback: function(){}
  }
})(jQuery);

如上,一個(gè)完整的彈窗插件就在這里了。

說下這個(gè)標(biāo)紅的 return this 是干什么用的,前面已說過 this 在這里是被選中的jQuery對(duì)象。將其return就可以在調(diào)用完我們的插件方法后可以繼續(xù)調(diào)用jQ對(duì)象上的其他方法,也就是jQuery的鏈?zhǔn)讲僮?,說玄乎點(diǎn)就叫級(jí)聯(lián)函數(shù)。

OK!趁熱打鐵,我們來看看暴露出去的兩個(gè)方法重寫之后效果怎么樣,畢竟對(duì)插件暴露部分的擴(kuò)展和重寫是很牛逼的一塊東西。

想象個(gè)情景,你用了這個(gè)插件后覺得簡單的show和hide效果簡直是low爆了,決定重寫這個(gè)彈出和隱藏的效果:

$.fn.popWin.show = function($ele) {
  $ele.children().first().css('top','-30%').animate({top:'30%'},500);
  $ele.show();
}
$.fn.popWin.hide = function($ele) {
  $ele.children().first().animate({top:'-30%'},500,function() {
    $ele.hide();
  });
}

你在自己的代碼里加上上面兩段,然后發(fā)現(xiàn)彈窗有了一個(gè)簡單的上下滑動(dòng)進(jìn)入屏幕的效果,同時(shí)又不會(huì)影響我們彈窗的創(chuàng)建,證明我們的暴露方法還算合理。

當(dāng)然你也可以讓它豎著進(jìn)、橫著進(jìn)、翻著跟頭進(jìn),這就看你自己了。

最后貼上默認(rèn)的樣式表,為了急著想粘回去試試的同學(xué)們。

.pop-win {
  border: 1px solid #fff;
  padding: 10px;
  background-color: #fff;
  -wekbit-border-radius: 6px;
  border-radius: 6px;
  -webkit-box-shadow: 0 3px 9px rgba(0,0,0,0.3);
  box-shadow: 0 3px 9px rgba(0,0,0,0.3);
}
.pop-win-red {
  padding: 10px;
  background-color: red;
  -wekbit-border-radius: 6px;
  border-radius: 6px;
  -webkit-box-shadow: 0 3px 9px rgba(0,0,0,0.3);
  box-shadow: 0 3px 9px rgba(0,0,0,0.3);
}
.pop-title {
  width: 100%;
  height: 20%;
  line-height: 40px;
  padding-left: 10px;
  box-sizing: border-box;
  border-bottom: 1px solid #eee;
  font-size: 17px;
  font-weight: bold;
}
.pop-desc {
  width: 100%;
  height: 60%;
  box-sizing: border-box;
  padding: 10px 0 0 10px;
  border-bottom: 1px solid #eee;
}
.pop-btn-box {
  width: 100%;
  height: 20%;
  text-align: right;
}
.pop-btn {
  margin: 10px 10px 0 0;
  width: 60px;
  height: 30px;
}

當(dāng)然這只是個(gè)編寫插件的例子,如果要拿出去使用還需要仔細(xì)打磨。例子雖然簡單,旨在拋磚引玉。

相關(guān)文章

最新評(píng)論