Last active
January 2, 2016 08:49
-
-
Save joeylin/8278882 to your computer and use it in GitHub Desktop.
a complete jQuery Plugin patterns
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Event | |
1, event trigger flow: init -> ready -> other events(other events shouldn't be triggered before ready event). | |
2, event type format: plugin::eventType. | |
3, always pass a plugin instance to event as a param. | |
Callback | |
1, callback format: onCallback. | |
2, 'this' in callback direct to plugin instance. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// initialied plugin | |
$('.element').pluginName(); | |
$('.element').pluginName({ | |
skin:'your skin', | |
// config | |
..... | |
}); | |
// callback method after initialied | |
$('.element').pluginName('disable'); // call disable method | |
$('.element').pluginName('val', 10); // call val method with 10 as a param | |
$('.element').pluginName('method',para1,para2,para3,...); // pass multi param | |
// another way to call method | |
var instance = $('.element').data('pluginName'); // get plugin instance | |
instance.val(); // excute method on instance directly | |
// what is return | |
$('.element').pluginName(); // always returns jquery element which plugin initialied on it | |
$('.element').data('pluginName'); // always returns plugin instance | |
// ---------------- | |
// class name guide | |
// ---------------- | |
namespace_statusClassName // this for status class name | |
namespace-componentClassName // this for compontent class name | |
namespace-component1-subcomponent |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// here how to extend | |
// extend services / UI components | |
(function($, document, window, undefined) { | |
// Optional, but considered best practice by some | |
"use strict"; | |
var $doc = $(document); | |
// this will be triggered everytime when instance is initialied | |
// Note: if you have multi instances, it will excute corresponding times | |
$doc.on('pluginName::init', function(event, instance) { | |
// do some stuff | |
}); | |
$doc.on('pluginName::ready', function(event, instance) { | |
// do some stuff | |
}); | |
})(jQuery, document, window); | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function($, document, window, undefined) { | |
// Optional, but considered best practice by some | |
"use strict"; | |
var pluginName = 'defaultPluginName', | |
defaults = { | |
namespace: 'yourCustomNamespace', | |
skin: null, | |
// callback | |
onInit: null, // function() {}; | |
onReady: null | |
}; | |
var Plugin = $[pluginName] = function(element,options) { | |
this.element = element; | |
this.$element = $(element); | |
// get setting from element | |
this.options = $.extend( {}, defaults, options, this.$element.data()) ; | |
this._name = pluginName; | |
this.namespace = this.options.namespace; | |
this.classes = { | |
// status | |
skin: this.namespace + '_' + this.options.skin, | |
disabled: this.namespace + '_disabled', | |
// components --for example | |
wrapper: this.namespace + '-wrapper' | |
}; | |
this.$element.addClass(this.namespace); | |
// flag | |
this.disabled = false; | |
this.initialed = false; | |
this.updating = false; | |
this.trigger('init'); | |
this.init(); | |
} | |
Plugin.prototype = function () { | |
constructor: Plugin, | |
init: function() { | |
this.createHtml(); | |
this.bindEvent(); | |
// skin : excuting after all elements are generated | |
if (this.options.skin) { | |
// add skin to wrapper | |
this.$element.addClass(this.classes.skin); | |
} | |
// set initialed value | |
// ... | |
this.initialed = true; | |
// after init end trigger 'ready' | |
this.trigger('ready'); | |
}, | |
bindEvent: function() {}, | |
createHtml: function() {}, | |
// some method | |
// ..... | |
// some method | |
trigger: function(eventType) { | |
// event | |
this.$element.trigger(pluginName + '::' + eventType, this); | |
// callback | |
eventType = eventType.replace(/\b\w+\b/g, function(word){ | |
return word.substring(0,1).toUpperCase() + word.substring(1); | |
}); | |
var onFunction = 'on' + eventType; | |
var method_arguments = arguments.length > 1 ? Array.prototype.slice.call(arguments, 1) : undefined; | |
if (typeof this.options[onFunction] === 'function') { | |
this.options[onFunction].apply(this, method_arguments); | |
} | |
}, | |
update: function(config) { | |
this.updating = true; | |
// do some stuff | |
this.trigger('update'); | |
this.updating = false; | |
}, | |
enable: function() { | |
this.disabled = false; | |
// which element is up to your requirement | |
this.$element.removeClass(this.classes.disabled); | |
// here maybe have some events detached | |
}, | |
disable: function() { | |
this.disabled = true; | |
// whitch element is up to your requirement | |
this.$element.addClass(this.classes.disabled); | |
// here maybe have some events attached | |
}, | |
destory: function() { | |
// detached events first | |
// then remove all js generated html | |
this.$element.data(pluginName, null); | |
this.trigger('destory'); | |
} | |
}; | |
Plugin.defaults = defaults; | |
$.fn[pluginName] = function (options) { | |
if (typeof options === 'string') { | |
var method = options; | |
var method_arguments = arguments.length > 1 ? Array.prototype.slice.call(arguments, 1) : undefined; | |
return this.each(function() { | |
var api = $.data(this, pluginName); | |
if (typeof api[method] === 'function') { | |
api[method].apply(api, method_arguments); | |
} | |
}); | |
} else { | |
return this.each(function() { | |
if (!$.data(this, pluginName)) { | |
$.data(this, pluginName, new Plugin( this, options ));); | |
} | |
}); | |
} | |
}; | |
})(jQuery, document, window); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function($) { | |
/* | |
======== A Handy Little QUnit Reference ======== | |
http://api.qunitjs.com/ | |
Test methods: | |
module(name, {[setup][ ,teardown]}) | |
test(name, callback) | |
expect(numberOfAssertions) | |
stop(increment) | |
start(decrement) | |
Test assertions: | |
ok(value, [message]) | |
equal(actual, expected, [message]) | |
notEqual(actual, expected, [message]) | |
deepEqual(actual, expected, [message]) | |
notDeepEqual(actual, expected, [message]) | |
strictEqual(actual, expected, [message]) | |
notStrictEqual(actual, expected, [message]) | |
throws(block, [expected], [message]) | |
*/ | |
module('plugin#returnValue', { | |
// This will run before each test in this module. | |
setup: function() { | |
this.$elems = $('#qunit-fixture').plugin(); | |
this.instance = this.$elems.data('plugin'); | |
this.instance.test = function(value){ | |
if (value) { | |
return value; | |
} else { | |
return 0; | |
} | |
} | |
} | |
}); | |
test('is chainable', function() { | |
var value = 10; | |
var getValue = this.$elems.plugin('test',value); | |
equal(getValue, 0, 'should return 0'); | |
var setValue = this.$elems.plugin('test',value); | |
equal(setValue, value, 'should be set value'); | |
}); | |
module('plugin#event', { | |
setup: function(){ | |
var self = this; | |
this.$elems = $('#qunit-fixture').plugin({ | |
onChange: function(value) { | |
self.mockValue = value; | |
} | |
}); | |
this.instance = this.$elems.data('plugin'); | |
} | |
}); | |
test('change', function() { | |
this.$elems.on('plugin::change', function(instance) { | |
ok(1,'change event trigger success !'); | |
equal(instance.value,10,'change event value ok'); | |
}); | |
this.instance.set(10); | |
equal(this.mockValue,10,'callback trigger success !'); | |
}); | |
test('update', function() { | |
this.$elems.on('plugin::update', function(instance) { | |
ok(1,'update event trigger success !'); | |
}); | |
this.$elems.on('plugin::change', function(instance) { | |
ok(0,'change event should not be triggered !'); | |
}); | |
this.instance.update(); | |
}); | |
}(jQuery)); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment