jQuery patterns
Boilerplate
http://jqueryboilerplate.com/
Quel pattern ?
Créer des modules par fonctionnalité et pas par page !
Essayer de concevoir des modules
courts
Jouer sur les options pour configurer les modules et les rendre faciles à paramétrer
;(function ($, window, document) {
"use strict";
// 1) Nom du module dynamique, facile à changer
// 2) Liste de variables par défaut (surchargeable)
// ==> Placer dans cette liste les références aux éléments du DOM à requêter
// ==> De préférence des data-attributes
// ==> Placer les noms des classes d'état (is-visible, ...)
var pluginName = "searching",
defaults = {
container: '.searchBox',
hasResultsState: 'has-results',
resultsContainer: '.js-searchbox-results'
};
// Constructeur (à laisser tel quel)
function Plugin (element, options) {
this.element = element;
this.settings = $.extend({}, defaults, options);
this._defaults = defaults;
this._name = pluginName;
this.init();
}
[...]
$.extend(Plugin.prototype, {
hasFocus: false,
init: function () {
// Définit impérativement ces 2 méthodes
this.setElements();
this.setEvents();
},
// Stocker tous les éléments de DOM utiles dans des variables ($xxx)
// Cela évite de parcourir le DOM trop souvent
setElements: function() {
this.$window = $(window);
this.$element = $(this.element);
this.$results = this.$element.parent().find(this.settings.resultsContainer);
},
// Brancher les événements sur les éléments
setEvents: function() {
this.$element.on('focus', $.proxy(this.onFocus, this));
this.$element.on('blur', $.proxy(this.onBlur, this));
},
// Méthodes propres au module (à définir soit même)
onFocus: function() {
this.hasFocus = true;
this.proxySearch = this.proxySearch || $.proxy(this.doSearch, this);
this.$window.on('keydown', this.proxySearch);
},
onBlur: function() {
this.hasFocus = false;
this.closeSearch();
this.$window.off('keydown', this.proxySearch);
},
doSearch: function() {
this.$results.addClass(this.settings.hasResultsState);
},
closeSearch: function() {
this.$element.val('');
this.$results.removeClass(this.settings.hasResultsState);
}
});
[...]
// Fin du module (à laisser tel quel)
$.fn[ pluginName ] = function (options) {
this.each(function() {
if (!$.data(this, "plugin_" + pluginName)) {
$.data(this, "plugin_" + pluginName, new Plugin(this, options));
}
});
return this;
};
})(jQuery, window, document);
Déclarer les modules
Utiliser un fichier racine de registry.js
// Exemples
$('[data-preview-src]').mediaPreview();
$('[data-scroll-omniture]').scrollOmniture();
// On peut passer des options et les récupérer dans le module !
$('[data-spastic-nav]').spasticNav(options);
Et aussi...
// Ne jamais cibler les scripts avec les classes BEM
// Utiliser des data-attributes, des classes .js-*** ou des ID.
// Ne pas utiliser les classes js-** en CSS, ni les ID.
// ==> Garantir l'indépendance des scripts et des styles
$('.block__element') => NON
$('.js-machin') => OK
$('[data-truc]') => OK
$('#truc') => OK (à condition que l'ID ne soit pas référencé dans le css)
Vu dans le code...
// Ne JAMAIS déclencher des événements sur des éléments du DOM en JS
// http://davidwalsh.name/dont-trigger-real-event-names
$file.click()
Vu dans le code...
// Extrait de code
classicBlock = widget.find(".card-content")[0];
emptyBlock = widget.find(".card-content")[1];
// CORRECTION
// Le JS va parcourir deux fois le DOM
// alors qu'il peut le faire qu'une seule fois (PERF)
var elm = widget.find(".card-content");
classicBlock = elm[0];
emptyBlock = elm[1];
jQuery patterns
By Julien Herpin
jQuery patterns
- 910