【四十八】JQ-擴(kuò)展

當(dāng)我們使用jquery對象的方法時脱惰,由于jQuery對象可以操作一組DOM,而且支持鏈?zhǔn)讲僮髦瘢杂闷饋矸浅7奖恪?br> 但是jQuery內(nèi)置的方法永遠(yuǎn)不可能滿足所有的需求螃概。比如矫夯,我們想要高亮顯示某些DOM元素,用jQuery可以這么實現(xiàn):

$('span.hl').css('backgroundColor', '#fffceb').css('color', '#d85030');
$('p a.hl').css('backgroundColor', '#fffceb').css('color', '#d85030');

總是寫重復(fù)代碼可不好吊洼,萬一以后還要修改字體就更麻煩了训貌,能不能統(tǒng)一起來,寫個highlight()方法冒窍?

$('span.hl').hightlight();
$('p a.hl').hightlight();

答案是肯定的递沪。我們可以擴(kuò)展jQuery來實現(xiàn)自定義方法。將來如果要修改高亮的邏輯综液,只需要需要一處擴(kuò)展代碼款慨。這種方式也稱為編寫jQuery插件。

<p>
</br>

編寫jQuery插件

給jQuery對象綁定一個新方法是通過擴(kuò)展$.fn對象實現(xiàn)的谬莹。讓我們來編寫第一個擴(kuò)展-------hightlight1():

$.fn.highlight1 = function() {
      // this已經(jīng)綁定為當(dāng)前的jQuery對象:
      this.css('backgroundColor', '#fffceb').css('color', '#d85030');
      return this;
}

注意到函數(shù)內(nèi)部的this在調(diào)用時被綁定為jQuery對象檩奠,所以函數(shù)內(nèi)部代碼可以正常調(diào)用所有jQuery對象的方法。
對于如下的HTML結(jié)構(gòu):

<!-- HTML結(jié)構(gòu) -->
<div id="test-hightlight1">
    <p>什么是<span>jQuery</span></p>
    <p><span>jQuery</span>是目前最流行的<span>JavaScript</span>庫附帽。</p>
</div>

來測試一下highlight1()的效果:

$('#test-highlight1 span').highlight1();
原本顯示的文本

執(zhí)行jQuery代碼之后:

執(zhí)行代碼之后

細(xì)心的童鞋可能發(fā)現(xiàn)了埠戳,為什么最后要return this;?因為jQuery對象支持鏈?zhǔn)讲僮鹘栋纾覀冏约簩懙臄U(kuò)展方法也要能繼續(xù)鏈?zhǔn)较氯ィ?/p>

$('pan.hl').highlight1().slideDown();

不然整胃,用于調(diào)查的時候,就不得不把上面的代碼拆成兩行喳钟。
但是這個版本并不完美屁使。有的用戶希望高亮的顏色能自己來指定,怎么辦奔则?
我們可以給方法加個參數(shù)蛮寂,讓用戶自己把參數(shù)用對象傳進(jìn)去。于是我們有了第二個版本的highlight2():

$.fn.highlight2 = function (options) {
      // 要考慮到各種情況:
      // options為undefined
      // options只有部分Key
      var bgcolor = options && options.backgroundColor || '#fffceb';
      var color = options && options.color || '#d85030';
      this.css('backgroundColor', bgcolor).css('color', color);
      return this; 
}

對于如下HTML結(jié)構(gòu):

<!-- HTML結(jié)構(gòu) -->
<div id="test-highlight2">
    <p>什么是<span>jQuery</span> <span>Plugin</span></p>
    <p>編寫<span>jQuery</span> <span>Plugin</span>可以用來擴(kuò)展<span>jQuery</span>的功能应狱。</p>
</div>

來實測一下帶參數(shù)的highlight2():

$('#test-highlight2 span').highlight2({
    backgroundColor: '#00a8e6',
    color: '#ffffff'
});
原本顯示的文本

執(zhí)行highlight2()之后:

執(zhí)行highlight2();

對于默認(rèn)值的處理共郭,我們用了一個簡單的&&||短路操作符,總能得到一個有效的值疾呻。

另一種方法是使用jQuery提供的輔助方法$.extend(target, obj1, obj2, ...)除嘹,它把多個object對象的屬性合并到第一個target對象中,遇到同名屬性岸蜗,總是使用靠后的對象的值尉咕,也就是越往后優(yōu)先級越高:

// 把默認(rèn)值和用戶傳入的options合并到對象{}中并返回:
var opts = $.extend({}, {
    backgroundColor: '#00a8e6',
    color: 'ffffff'
}, options);

緊接著用戶對highlight2()提出了意見:每次調(diào)用都需要傳入自定義的設(shè)置,能不能讓我自己設(shè)定一個缺省值璃岳,以后的調(diào)用統(tǒng)一使用無參數(shù)的highlight2()?
也就是說年缎,我們設(shè)定的默認(rèn)值應(yīng)該能允許用戶修改悔捶。
那默認(rèn)值放哪比較合適?放全局變量肯定不合適单芜,最佳地點是$.fn.highlight2這個函數(shù)對象本身蜕该。
于是最終版的highlight()終于誕生了:

$.fn.highlight = function (options) {
    // 合并默認(rèn)值和用戶設(shè)定值:
    var opts = $.extend({}, $.fn.highlight.defaults, options);
    this.css('backgroundColor', opts.backgroundColor).css('color', opts.color);
    retunr this;
}

// 設(shè)定默認(rèn)值:
$.fn.highlight.defaults = {
    color: '#d85030',
    bakcgroundColor: '#fff8de'
}

這次用戶終于滿意了。用戶使用時洲鸠,只需一次性設(shè)定默認(rèn)值:

$.fn.highlight.defaults.color = '#fff';
$.fn.highlight.defaults.backgroundColor = '#000';

然后就可以非常簡單地調(diào)用highlight()了堂淡。

對如下的HTML結(jié)構(gòu):

<!-- HTML結(jié)構(gòu) -->
<div id="test-highlight">
    <p>如何編寫<span>jQuery</span> <span>Plugin</span></p>
    <p>編寫<span>jQuery</span> <span>Plugin</span>,要設(shè)置<span>默認(rèn)值</span>扒腕,并允許用戶修改<span>默認(rèn)值</span>绢淀,或者運行時傳入<span>其他值</span>。</p>
</div>

實測一下修改默認(rèn)值的效果:

$.fn.highlight.defaults.color = '#659f13';
$.fn.highlight.defaults.backgroundColor = '#f2fae3';

$('#test-highlight p:first-child span').highlight();

$('#test-highlight p:last-child span').highlight({
    color: '#dd1144'
});

調(diào)用前:

調(diào)用前的文本

調(diào)用后:

調(diào)用后的文本

最終瘾腰,我們得出編寫一個jQuery插件的原則:

  1. $.fn綁定函數(shù)皆的,實現(xiàn)插件的代碼邏輯;
  2. 插件函數(shù)最后要return this;以支持鏈?zhǔn)秸{(diào)用蹋盆;
  3. 插件函數(shù)要有默認(rèn)值费薄,綁定在$.fn.<pluginName>.defaults上;
  4. 用戶在調(diào)用時可傳入設(shè)定值以便覆蓋默認(rèn)值怪嫌。

<p>
</br>

針對特定元素的擴(kuò)展

我們知道jQuery對象有些方法只能作用在特定DOM元素上义锥,比如submit()方法只能針對form。如果我們編寫的擴(kuò)展只能針對某些類型的DOM元素岩灭,應(yīng)該怎么寫拌倍?

還記得jQuery的選擇器支持filter()方法來過濾嗎?我們可以借助這個方法來實現(xiàn)針對特定元素的擴(kuò)展噪径。

舉個例子柱恤,現(xiàn)在我們要給所有指向外鏈的超鏈接加上跳轉(zhuǎn)提示,怎么做找爱?

先寫出用戶調(diào)用的代碼:

$('#main a').external();

然后按照上面的方法編寫一個external擴(kuò)展:

$.fn.external = function () {
    // return返回的each()返回結(jié)果梗顺,支持鏈?zhǔn)秸{(diào)用:
    return this.filter('a').each(function () {
        //注意,each()內(nèi)部的回調(diào)函數(shù)的this綁定為DOM本身车摄!
        var a = $(this);
        var url = a.attr('href');
        if (url && (url.indexOf('http://')===0 || url.indexOf('https://')===0)) {
            a.attr('href', '#0')
              .removeAttr('target')
              .append(' <i class="uk-icon-external-link"></i>')
              .click(function () {
                  if(confirm('你確定要前往' + url + '?')) {
                      window.open(url);
                  }
              });
        }
    });
}

對如下的HTML結(jié)構(gòu):

<!-- HTML結(jié)構(gòu) -->
<div id="test-external">
    <p>如何學(xué)習(xí)<a >jQuery</a>寺谤?</p>
    <p>首先,你要學(xué)習(xí)<a href="/wiki/001434446689867b27157e896e74d51a89c25cc8b43bdb3000">JavaScript</a>吮播,并了解基本的<a >HTML</a>变屁。</p>
</div>

實測外鏈效果:

$('#test-external a').external();

調(diào)用前:

調(diào)用前

調(diào)用后:

調(diào)用后

點擊時:

彈窗提示

<p>
</br>

小結(jié)

擴(kuò)展jQuery對象的功能十分簡單,但是我們要遵循jQuery的原則意狠,編寫的擴(kuò)展方法能支持鏈?zhǔn)秸{(diào)用粟关、具備默認(rèn)值和過濾特定元素,使得擴(kuò)展方法看上去和jQuery本身的方法沒有什么區(qū)別环戈。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末闷板,一起剝皮案震驚了整個濱河市澎灸,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌遮晚,老刑警劉巖性昭,帶你破解...
    沈念sama閱讀 212,599評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異鹏漆,居然都是意外死亡巩梢,警方通過查閱死者的電腦和手機(jī)创泄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,629評論 3 385
  • 文/潘曉璐 我一進(jìn)店門艺玲,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人鞠抑,你說我怎么就攤上這事饭聚。” “怎么了搁拙?”我有些...
    開封第一講書人閱讀 158,084評論 0 348
  • 文/不壞的土叔 我叫張陵秒梳,是天一觀的道長。 經(jīng)常有香客問我箕速,道長酪碘,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,708評論 1 284
  • 正文 為了忘掉前任盐茎,我火速辦了婚禮兴垦,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘字柠。我一直安慰自己探越,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,813評論 6 386
  • 文/花漫 我一把揭開白布窑业。 她就那樣靜靜地躺著钦幔,像睡著了一般。 火紅的嫁衣襯著肌膚如雪常柄。 梳的紋絲不亂的頭發(fā)上鲤氢,一...
    開封第一講書人閱讀 50,021評論 1 291
  • 那天,我揣著相機(jī)與錄音西潘,去河邊找鬼卷玉。 笑死,一個胖子當(dāng)著我的面吹牛秸架,可吹牛的內(nèi)容都是我干的揍庄。 我是一名探鬼主播,決...
    沈念sama閱讀 39,120評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼东抹,長吁一口氣:“原來是場噩夢啊……” “哼蚂子!你這毒婦竟也來了沃测?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,866評論 0 268
  • 序言:老撾萬榮一對情侶失蹤食茎,失蹤者是張志新(化名)和其女友劉穎蒂破,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體别渔,經(jīng)...
    沈念sama閱讀 44,308評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡附迷,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,633評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了哎媚。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片喇伯。...
    茶點故事閱讀 38,768評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖拨与,靈堂內(nèi)的尸體忽然破棺而出稻据,到底是詐尸還是另有隱情,我是刑警寧澤买喧,帶...
    沈念sama閱讀 34,461評論 4 333
  • 正文 年R本政府宣布捻悯,位于F島的核電站,受9級特大地震影響淤毛,放射性物質(zhì)發(fā)生泄漏今缚。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,094評論 3 317
  • 文/蒙蒙 一低淡、第九天 我趴在偏房一處隱蔽的房頂上張望姓言。 院中可真熱鬧,春花似錦查牌、人聲如沸事期。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,850評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽兽泣。三九已至,卻和暖如春胁孙,著一層夾襖步出監(jiān)牢的瞬間唠倦,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,082評論 1 267
  • 我被黑心中介騙來泰國打工涮较, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留稠鼻,地道東北人。 一個月前我還...
    沈念sama閱讀 46,571評論 2 362
  • 正文 我出身青樓狂票,卻偏偏與公主長得像候齿,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,666評論 2 350

推薦閱讀更多精彩內(nèi)容