Rails 3 Client Side Validations 工作机制备忘
最近看了一下 Client Side Validations 这个插件 JavaScript 部分的源码,记录一下对它的理解(版本为 Rails 3 Client Side Validations - v3.1.0 )。
一、客户端校验的设置信息
首先,来看一下它是通过什么方式在客户端得到校验规则的。在页面渲染的时候,client_side_validations 会在 FormBuilder 输出的表单 HTML 后边附加一段 JavaScript,内容看起来像是这样:
window['new_article'] = { "type": "SimpleForm::FormBuilder", "error_class": ["error"], "error_tag": "span", "wrapper_error_class": "field_with_errors", "wrapper_tag": "div", "validators": { "article[title]": { "presence": { "message": "不能为空" }, "length": { "messages": { "minimum": "过短", "maximum": "过长" }, "minimum": 2, "maximum": 100 } } }};var clientSideValidations = { validators: { all: function() { return jQuery.extend({}, clientSideValidations.validators.local, clientSideValidations.validators.remote) }, local: { presence: function(element, options) { /* ... */ }, acceptance: function(element, options) { /* ... */ }, format: function(element, options) { /* ... */ }, numericality: function(element, options) { /* ... */ }, length: function(element, options) { /* ... */ }, exclusion: function(element, options) { /* ... */ }, inclusion: function(element, options) { /* ... */ }, confirmation: function(element, options) { /* ... */ } }, remote: { uniqueness: function(element, options) { /* ... */ } } }, /* formBuilders、callbacks 部分代码 */}var clientSideValidations = {/* validators 部分代码 */, formBuilders: { 'ActionView::Helpers::FormBuilder': { add: function(element, settings, message) { /* ... */ }, remove: function(element, settings) { /* ... */ } }, 'SimpleForm::FormBuilder': { add: function(element, settings, message) { /* ... */ }, remove: function(element, settings) { /* ... */ } }, 'Formtastic::FormBuilder': { add: function(element, settings, message) { /* ... */ }, remove: function(element, settings) { /* ... */ } }, 'NestedForm::Builder': { add: function(element, settings, message) { /* ... */ }, remove: function(element, settings, message) { /* ... */ } } }, /* callbacks 部分代码 */}var clientSideValidations = {/* validators 和 formBuilders 部分代码 */, callbacks: { element: { after: function(element, eventData) { }, before: function(element, eventData) { }, fail: function(element, message, addError, eventData) { addError() }, pass: function(element, removeError, eventData) { removeError() } }, form: { after: function(form, eventData) { }, before: function(form, eventData) { }, fail: function(form, eventData) { }, pass: function(form, eventData) { } } }}jQuery(function () { clientSideValidations.callbacks.element.before = function(element, eventData) { /* your code */ };});(function($) { $.fn.validate = function() { return this.filter('form[data-validate]').each(function() { var form = $(this); var settings = window[form.attr('id')]; // $.fn.validate() 的作用是为表单和表单项的一些事件绑定 callback // 包括前边说到的那8个 callbacks // 其中 element:validate:fail 事件触发时会调用前边提到的 formBuilders 中的 add() 函数 // 而 element:validate:pass 事件则对应调用 formBuilders 中的 remove() 函数 // 当表单的 submit 和 ajax:beforeSend 事件触发时,对此表单调用isValid(settings.validators) // 当需要校验的表单项(除radio)触发 focusout 时,对此表单项调用 isValid(参数同上) // 当需要校验的 checkbox 触发 click 时,对此表单项调用 isValid(参数同上) // 当 _confirmation 这种匹配项,触发 focusout、keyup 事件时,对此表单项调用isValid(参数同上) }); } $.fn.isValid = function(validators) { if ($(this[0]).is('form')) { return validateForm($(this[0]), validators); } else { return validateElement($(this[0]), validators[this[0].name]); } } var validateForm = function(form, validators) { // 触发 form:validate:before 事件 // 对表单中每一个需要校验的表单项调用 isValid(validators) // 触发 form:validate:pass 或 form:validate:fail 事件 // 触发 form:validate:after 事件 // 返回 true 或 false } var validateElement = function(element, validators) { // 触发 element:validate:before 事件 // 根据 validators 中的函数名字,到 clientSideValidations.validators 中找到对应的函数并调用 // 触发 element:validate:pass 或 element:validate:fail 事件 // 触发 element:validate:after 事件 // 返回 true 或 false } // Main hook // If new forms are dynamically introduced into the DOM the .validate() method // must be invoked on that form $(function() { $('form[data-validate]').validate(); })})(jQuery);