7. jQuery plugins & the stateManager / jQuery插件基類與StateManager的完美配合

7.1 Introduction / 簡介

當用戶試圖只用Javascript處理響應式網頁的時候无埃,會發(fā)現該過程異常痛苦徙瓶,因為用戶必須根據屏幕大小調整代碼。
==> 因此嫉称,Shopware推出了一個組件 StateManager侦镇,能夠定義新狀態(tài),并觸發(fā)callback函數(callback function)织阅。
另外一方面壳繁,可愛的jQuery插件并不喜歡干這些事。為了簡化這個過程荔棉,Shopware導入了一個插件基類闹炉,它具有jQuery插件開發(fā)的最佳實踐,并能與StateManager完美集成江耀。

7.2 Plugin base class / 插件基類(插件的編寫)

就像上面所提到的那樣剩胁,jQuery插件基類具有jQuery插件開發(fā)的最佳實踐。插件功能一覽:

  • 默認配置 + 可通過自定義配置重寫默認配置
  • 可通過HTML5的 data 屬性配置插件
  • 支持jQuery方法鏈接(jQuery's method chaining)
  • 支持事件命名空間(Namespace of events)
  • 有內置函數支持刪除事件監(jiān)聽器
  • 防止同一元素上的多重實例化
  • 檢查元素是否使用某個插件的自定義表達式
  • 使用jQuery的 data -方法自動將插件綁定到元素
    由此可見祥国,該jQuery基類為用戶編寫jQuery插件提供了許多有效的方法昵观。

7.2.1 Getting started / 基礎
以下代碼展示了,如何使用插件基類編寫jQuery插件的過程:

/**
 * $.plugin(): 自動連接全局jQuery對象舌稀。
 * 該方法的兩個參數:
 * para1: 插件名
 * para2: 一個對象啊犬,包含了默認配置和插件的實際實現
 */
$.plugin('example', {
    
    /**
     * 插件的默認配置對象
     * 用戶可以自定義設置。自定義后的設置會被自動整合到新對象里壁查。該對象可通過"this.opts"在這個插件的任意方法中被訪問到
     */
    defaults: {
        activeCls: 'js--is-active'
    },
    
    /**
     * "init" 方法的作用就像是插件的構造函數(constructor)
     * 可在這里對必要的元素進行緩存觉至,并為插件注冊事件監(jiān)聽器(Event Listener)
     * 另外,還可以現有配置的基礎上修改插件的function
     */
    init: function() {
        var me = this;
        
        /**
         * 調用"applyDataAttributes" 會自動讀出所有的 "data-" 屬性并重寫配置睡腿。
         * 如果你想要用HTML來配置你的插件语御,而不是通過提供一個配置對象的話,這個屬性很有用席怪。
         *
         * 比如应闯,我們要在下面這個div元素中調用插件:
         *    <div data-activeCls="some-other-class">...</div>
         *  "data"屬性會用值"some-other-class"重寫 "activeCls"
         */
        me.applyDataAttributes();
        
        /**
         * 接下來,用內置函數"_on"為插件設置一個新的事件監(jiān)聽器(這個"_on"方法其實是在jQuery的"on"方法上添加了一些其他的特性)
         * 事件和事件監(jiān)聽器都會在插件特殊事件集中進行注冊挂捻。該集合將自動迭代碉纺,并從元素中刪除已注冊的事件監(jiān)聽器。
         * Additionally the event name will be namespaced on the fly which
         * provides us with a safe way to remove a specific event listener from
         * an element and doesn't affect other plugins which are listening on
         * the same event.
         * (這段翻譯無能刻撒。骨田。。求助)
         */
        me._on(me.$el, 'click', function(event) {
            event.preventDefault();
            
            /**
             * 在接下來的條件語句中声怔,拍段元素是否在使用該插件态贤,若在被使用,則終止
             * 此外捧搞,這里使用 "this.$el"來初始化插件
             */
            if(me.$el.is('plugin-example')) {
                
                /**
                 * 現在用變量 "this.opts" 來訪問插件的配置
                 */
                me.$el.toggleClass(me.opts.activeCls);
            }
        });
    },
    
    /**
     * "destroy" 方法可從插件外部被調用抵卫,或者在被定義的狀態(tài)(state)改變時自動使用StateManager
     * 通常你需要刪除那些由插件添加到元素的類狮荔,并將事件監(jiān)聽器也從元素上刪除。
     */
    destroy: function() {
        var me = this;
    
        me.$el.removeClass(me.opts.activeCls);
        
        /**
         * 調用"_destroy"方法:移除所有用"_on"方法在基類插件上注冊的事件監(jiān)聽器介粘。
         * 如果想要自行迭代事件監(jiān)聽器殖氏,你可以使用 "this._events" 在插件中訪問事件集
         */
        me._destroy();
    }
});

注意:強烈推薦jQuery插件使用基類!

接下來姻采,我們刪去注解雅采,看著代碼解釋一遍給自己聽:

$.plugin('example', {
    
    defaults: {
        activeCls: 'js--is-active'
    },
    
    init: function() {
        var me = this;
        me.applyDataAttributes();
        me._on(me.$el, 'click', function(event) {
            event.preventDefault();
            if(me.$el.is('plugin-example')) {
                me.$el.toggleClass(me.opts.activeCls);
            }
        });
    },
    
    destroy: function() {
        var me = this;
        me.$el.removeClass(me.opts.activeCls);      
        me._destroy();
    }
});

7.2.2 Class properties / 類的屬性

  • _name: String類型, 插件的名字
  • $el : jQuery類型慨亲, 將插件實例化成jQuery對象的HTML元素
  • opts : Object類型婚瓜, 默認配置和用戶配置的結果。==> 通過調用this.applyDataAttributes()能重寫對象的屬性值
  • _events : Array類型刑棵, 一個包含所有用 _on 方法注冊了的事件監(jiān)聽器的集合

7.2.3 Class methods / 類的方法

  • init() 模板中的方法巴刻,作用類似于插件的構造方法(the constructor of the plugin),可以用于緩存所需的HTML元素蛉签,設置事件監(jiān)聽等等胡陪。

  • destroy() 模板中的方法,用于刪除插件碍舍。通常你會用它刪除你加到某個元素上的類或者事件監(jiān)聽器柠座。當你想要專門對某個特定的狀態(tài)使用插件的時候,該方法很有用片橡。

  • update() 模板中的方法妈经,用于當狀態(tài)發(fā)生改變(進入或離開一個狀態(tài))時更新插件的行為。這個方法只有在你使用了StateManager來初始化插件的時候有用捧书。

  • _destroy() 私人方法吹泡,在插件的_events 屬性中迭代已注冊的事件監(jiān)聽器。此外经瓷,該方法可使用jQuery的removeData()方法移除插件的內存綁定(inmemory binding)荞胡。并且觸發(fā)一個全局可用的觀察者(observer)。

  • _on(element , event , fn) :
    element : jQuery或HTMLElement類型了嚎,特殊事件監(jiān)聽器的事件目標(jQuery元素 / DOM節(jié)點)
    event : String類型, 代表要監(jiān)聽的事件
    fn : Function類型廊营, 當特殊類型的事件發(fā)生時歪泳,對象會收到提示(notification)
    該方法為jQuery中on()方法的代理方法,用于連接事件監(jiān)聽器到提供的元素露筒, 并且在_events事件集中進行注冊呐伞。

  • _off(element, event) :
    element : jQuery或HTMLElement類型,擁有事件監(jiān)聽器的事件目標
    event : String類型慎式, 一個或者多個空間分離時間類型(space-separated event types)伶氢,可添加可選的命名空間趟径。或者就只是命名空間癣防,比如 "click" 或者 "keydown.myPlugin"

  • getName() getter插件名

  • getEventName(event)
    event : String 或 Array類型蜗巧,一個或多個空間分離事件類型
    將事件命名空間應用到事件類型上

  • getElement() 獲取實例化插件的元素

  • getOptions() 獲整合后的配置對象

  • getOption(key)
    key : String類型,配置屬性的key
    自定義配置屬性的getter方法

  • setOption(key, value)
    key : String類型蕾盯, 配置屬性的key
    value : Mixed類型幕屹, 所提供的key值
    用value值重寫屬性key

  • applyDataAttributes()
    獲取提供的配置key,并根據元素的data屬性覆蓋值它

7.3 Global jQuery event observer / 全局jQuery事件監(jiān)聽

在Shopware5中添加了一個全局事件服務器(global event server)级遭,它使得用戶能夠在jQuery對象上定義全局事件望拖,因此每個插件都能監(jiān)聽以下這些事件:

// 注冊事件
$.publish('plugin/some-plugin/onInit', me);

// 監(jiān)聽事件
$.subscribe('plugin/some-plugin/onInit', function() {
    console.log('onInit');
})

// 移除事件監(jiān)聽器
$.unsubscribe('plugin/some-plugin/onInit');```
建議在注冊事件監(jiān)聽器時,一直使用命名空間(namespace)挫鸽,能增加精確度说敏,避免誤刪等情況。舉例:

$.subscribe('plugin/some-plugin/onInit.my-plugin', function() {});

// 移除事件監(jiān)聽器
$.unsubscribe('plugin/some-plugin/onInit.my-plugin');```

7.4 The state manager / 狀態(tài)管理器

狀態(tài)管理器(state manager)幫助管理不同屏幕大小時丢郊,不同的行為盔沫。實現了通過斷點(breakpoint)設置不同的狀態(tài)。
斷點即預定義的視窗寬度蚂夕。通過輸入斷點范圍迅诬,被注冊的事件監(jiān)聽器的enter()函數會被調用。當到達預定義寬度之后婿牍,調用exit()函數侈贷。
即,已注冊的回調函數 在進入 / 結束預定義狀態(tài)時會被調用等脂。
狀態(tài)管理器提供了許多協(xié)助函數和填充工具俏蛮,對于管理響應式設計(responsive design)十分有效。

7.5 Use the state manager / 使用狀態(tài)管理器

在Shopware的前段javascript代碼中 狀態(tài)管理器是是自包含(self-containing)的全局變量上遥。
狀態(tài)管理器的初始化:

== 狀態(tài) XS ==
范圍:0 - 479px
適用于:智能手機豎屏

== 狀態(tài) S ==
范圍:480 - 767px
適用于:智能手機橫屏

== 狀態(tài) M ==
范圍:768 - 1023px
適用于:平板電腦豎屏

== 狀態(tài) L ==
范圍:1024 - 1259px
適用于:平板電腦橫屏搏屑,筆記本電腦,臺式電腦

== 狀態(tài) XL ==
范圍:1260 - 5160px
適用于:臺式電腦粉楚,高分辨率的顯示屏

具體代碼舉例:

window.StateManager.init([
        {
            state: 'xs',
            enter: 0,
            exit: 29.9375   // 479px
        },
        {
            state: 's',
            enter: 30,      // 480px
            exit: 47.9375   // 767px
        },
        {
            state: 'm',
            enter: 48,      // 768px
            exit: 63.9375   // 1023px
        },
        {
            state: 'l',
            enter: 64,      // 1024px
            exit: 78.6875   // 1259px
        },
        {
            state: 'xl',
            enter: 78.75,   // 1260px
            exit: 322.5     // 5160px
        }
    ]);

注意:若默認斷點與用戶所要求的有出入辣恋,可以在window.StateManager.init([ ]);方法中直接修改enterexit的值

7.5.1 Adding an event listner / 添加事件監(jiān)聽器
用狀態(tài)管理器注冊或者移除一個事件監(jiān)聽器,我們通常用javascript來寫模软。
注冊事件監(jiān)聽舉例:

StateManager.registerListener([{
    state: 'xs',
    enter: function() { console.log('onEnter'); },
    exit: function() { console.log('onExit'); }
}]);

事件監(jiān)聽器的注冊支持通配符伟骨,所以enter()exit()這兩個方法也可以在每個斷點都被調用,具體如下:

StateManager.registerListener([{
    state: '*',
    enter: function() { console.log('onEnter'); },
    exit: function() { console.log('onExit'); }
}]);

7.5.2 Register additional breakpoints / 注冊額外的斷點
默認的斷定可以通過StateManager的registerBreakpoint()方法被繼承燃异。

注意:額外的斷點不能和已存在的完全重疊

StateManager.registerBreakpoint({
    state: 'xxl',
    enter: 78.75  // = 1260px
    exit: 90      // = 1440px
});```

**7.5.3 Class methods / 類的方法**
`init(breakpoints)`
`breakpoints`:Array或Object類型携狭,最初的狀態(tài)(state)
實例化StateManager,注冊預定義的斷點回俐,給html元素添加瀏覽器特定的類(browser specific class)逛腿,設置特定設備的cookie

`registerBreakpoint(breakpoints)`
`breakpoints`:Array或Object類型稀并,最初的狀態(tài)(state)
給State Manager注冊額外斷點

`removeBreakpoint(state)`
`state`:String類型,

`registerListener(listener)`
`listener`:


`addPlugin(selector, pluginName, config, viewport)`
`selector`:
`pluginName`:
`config`:
`viewport`:

`removePlugin(selector, pluginName, viewport)`
`selector`:
`pluginName`:
`viewport`:

`updatePlugin(selector, pluginName)`
`selector`:
`pluginName`:

`destroyPlugin(selector, pluginName)`
`selector`:
`pluginName`:

`getViewportWidth()`

`getViewportHeight()`

`getPreviousState()`

`isPreviousState(state)`
`state`:

`getCurrentState()`

`isCurrentState(state)`
`state`:

`isPortraitMode()`

`isLandscapeMode()`

`getDevicePixelRatio()`

`isBrowser(browser)`
`browser`:

`getScrollBarHeight()`

`matchMedia()`

`requestAnimationFrame()`

`cancelAnimationFrame()`

`getVendorProperty(property, softError)`
`property`:
`softError`:

##7.6 Working with stateful jQuery plugins / jQuery插件的使用
StateManager和jQuery插件基類的合作单默,簡化了特定狀態(tài)下(state)注冊jQuery插件的過程碘举。使組件(component)的行為根據當前state而改變。比如Offcanvas menu插件只在移動端設備(state為xs或s)上顯示雕凹,在tablet和PC端被隱藏殴俱。
state manager的作用域為前端的所有javascript代碼。想要注冊一個插件枚抵,只要調用state manager的`addPlugin()`方法即可线欲。
下面的例子中,我們將自定義的jQuery插件在狀態(tài)為xs和s下進行注冊汽摹。

StateManager.addPlugin('.my-selector', 'myPlugin', [ 'xs', 's' ]);```

注意:有些自定義主題的代碼中沒有初始化StateManager導致上面代碼無效李丰,此時需要在addPlugin之前先用init()初始化狀態(tài)管理器(見7.5 Use the state manager)

7.6.1 Passing a user configuration to the jQuery plugin / 為jQuery插件傳遞一個用戶自定義的配置
用戶也可以將自定義的配置傳遞給plugin,被傳遞的自定義配置將與插件的默認配置進行融合(該重寫的重寫逼泣,沒被重寫的保留blablabla...)趴泌。被融合(merge)之后的配置可以通過插件中的this.opts對象取得。

// 自定義插件配置
$.plugin('myPlugin', {
    defaults: {
        'speed': 300
    }
});

// 注冊插件
StateManager.addPlugin('.my-selector', 'myPlugin', {
    'speed': 2000
}, [ 'xs', 's' ]);```
如果用戶需要給插件傳遞一個修改過的配置拉庶,可以參照下面的模式:

StateManager.addPlugin('.my-selector', 'myPlugin', {
'speed': 300
}).addPlugin('.my-selector', 'myPlugin', {
'speed': 2000
}, 's');```

7.7 Adding javascript files to your theme / 在用戶主題中添加js文件

將js文件放在/frontend/_public目錄下嗜憔,然后將該路徑寫在Theme.php中,舉例:

/** @var array Defines the files which should be compiled by the javascript compressor */
protected $javascript = array(
    'src/js/jquery.my-plugin.js'
);```
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末氏仗,一起剝皮案震驚了整個濱河市吉捶,隨后出現的幾起案子,更是在濱河造成了極大的恐慌皆尔,老刑警劉巖呐舔,帶你破解...
    沈念sama閱讀 217,406評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異慷蠕,居然都是意外死亡珊拼,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 92,732評論 3 393
  • 文/潘曉璐 我一進店門流炕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來澎现,“玉大人,你說我怎么就攤上這事每辟∥敉罚” “怎么了?”我有些...
    開封第一講書人閱讀 163,711評論 0 353
  • 文/不壞的土叔 我叫張陵影兽,是天一觀的道長。 經常有香客問我莱革,道長峻堰,這世上最難降的妖魔是什么讹开? 我笑而不...
    開封第一講書人閱讀 58,380評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮捐名,結果婚禮上旦万,老公的妹妹穿的比我還像新娘。我一直安慰自己镶蹋,他們只是感情好成艘,可當我...
    茶點故事閱讀 67,432評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著贺归,像睡著了一般淆两。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上拂酣,一...
    開封第一講書人閱讀 51,301評論 1 301
  • 那天秋冰,我揣著相機與錄音,去河邊找鬼婶熬。 笑死剑勾,一個胖子當著我的面吹牛,可吹牛的內容都是我干的赵颅。 我是一名探鬼主播虽另,決...
    沈念sama閱讀 40,145評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼饺谬!你這毒婦竟也來了捂刺?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,008評論 0 276
  • 序言:老撾萬榮一對情侶失蹤商蕴,失蹤者是張志新(化名)和其女友劉穎叠萍,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體绪商,經...
    沈念sama閱讀 45,443評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡苛谷,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,649評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了格郁。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片腹殿。...
    茶點故事閱讀 39,795評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖例书,靈堂內的尸體忽然破棺而出锣尉,到底是詐尸還是另有隱情,我是刑警寧澤决采,帶...
    沈念sama閱讀 35,501評論 5 345
  • 正文 年R本政府宣布自沧,位于F島的核電站,受9級特大地震影響拇厢,放射性物質發(fā)生泄漏爱谁。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,119評論 3 328
  • 文/蒙蒙 一孝偎、第九天 我趴在偏房一處隱蔽的房頂上張望访敌。 院中可真熱鬧,春花似錦衣盾、人聲如沸寺旺。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽阻塑。三九已至,卻和暖如春徽龟,著一層夾襖步出監(jiān)牢的瞬間叮姑,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評論 1 269
  • 我被黑心中介騙來泰國打工据悔, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留传透,地道東北人。 一個月前我還...
    沈念sama閱讀 47,899評論 2 370
  • 正文 我出身青樓极颓,卻偏偏與公主長得像朱盐,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子菠隆,可洞房花燭夜當晚...
    茶點故事閱讀 44,724評論 2 354

推薦閱讀更多精彩內容

  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理兵琳,服務發(fā)現,斷路器骇径,智...
    卡卡羅2017閱讀 134,654評論 18 139
  • 原文鏈接 http://blog.poetries.top/2016/10/20/review-jQuery 關注...
    程序員poetry閱讀 16,643評論 18 503
  • (續(xù)jQuery基礎(1)) 第5章 DOM節(jié)點的復制與替換 (1)DOM拷貝clone() 克隆節(jié)點是DOM的常...
    凜0_0閱讀 1,338評論 0 8
  • Spring Boot 參考指南 介紹 轉載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,810評論 6 342
  • 該文章內容摘自謝宇衡在微信社群中的分享 何為高效學習躯肌?1.更加有效的學習;2.學習完后有結果破衔。 原則1:做自己真正...
    仞月psy閱讀 600評論 0 3