1. 程式人生 > >自定義jQuery外掛Step by Step

自定義jQuery外掛Step by Step

隨著前端和後端技術的分離,各大網際網路公司對於Mobile First理念都是趨之若鶩的,為了解決網頁在不同移動裝置上的顯示效果,其中一個解決方案就是Responsive Design;但我們今天不是介紹它,正由於前端開發已經十分重要了,所以我們將介紹如何使用jQuery自定義外掛。

相信大家都使用過jQuery庫,甚至自定義過一些常用的jQuery外掛,如果沒有學習過也無需擔心,接下來我們將從一些簡單的例子開始。

本文目錄

1.1.2 正文

現在,jQuery庫的功能已經很豐富了(The Write Less, Do More, JavaScript Library),但它也沒有辦法滿足使用者的所有需求,所以,它提供了一種機制:讓使用者給核心模組增加自定義的方法和額外的功能;通過這種機制,jQuery允許我們建立自定義的外掛封裝常用的方法,從而提高我們的開發效率。

控制元件模式

jQuery外掛定義方式很簡單,如果我們需要定義一個外掛,只需給jQuery的$.fn物件新增一個新的函式屬性就可以了,示例程式碼如下:

$.fn.myPluginName = function() {

    // Your plugin logic. 

};

現在,我們定義了一個函式myPluginName(),這樣就建立了一個自定義外掛了,但有一個問題我們要注意的是:由於美元符號(“$”)不僅僅只有jQuery庫會使用到,其他Javascript庫也可能使用到,假如其他庫中“$”也有特別的含義,那麼就會引起不必要衝突了。

其實,我們可以通過定義自執行的函式IIFE),然後把jQuery

物件作為引數傳遞給該自執行函式,通過建立“$”和jQuery的對應關係,這樣“$”就不會在其執行範圍中被其他庫覆蓋了。

(function($) {
    $.fn.myPluginName = function() {
        // your plugin logic
    };
})(jQuery);

大家看到這裡,我們的外掛通過閉包的方式封裝起來了,這是為了確保我們使用“$”符號和其他JavaScript庫之間不會衝突。

上面我們通過匿名函式的方式給myPluginName()方法賦值,我們也可以通過另外一種方法來建立自定義方法,那就是使用jQuery的extend()方法,它允許我們定義多個方法,而且語意更加簡潔,示例程式碼如下:

(function($) {
    $.extend($.fn, {
        myplugin: function() {
            // your plugin logic
        }
    });
})(jQuery);

SignUp表單

現在,我們對jQuery自定義外掛有了初步的瞭解,接下來,我們將通過具體的例子介紹自定義的jQuery外掛的實現。

假設,我們需要定義一個表單校驗的外掛,也許有人會說:“jQuery已經提供了表單校驗外掛,我們真的有必要重做輪子嗎?”,的確是這樣,但這些外掛功能十分豐富不利於剛開始的學習jQuery使用,我們更希望通過一個簡單的例子介紹jQuery外掛的定義。

我們有一個註冊表單,它包含Name,Email,Password和Weibo等輸入資訊,現在,需要定義一個表單驗證控制元件,驗證使用者的輸入資訊是否符合規則,表單HTML程式碼如下:

<div class="validation-demo">
    <!-- Start Sign Up Form -->
    <form action="#signup-form" id="Form1">
        <h2>Sign Up</h2>
        <fieldset>
            <div class="fieldgroup">
                <label for="name">
                    Name</label>
                <input type="text" name="name" validation="required"/>
            </div>
            <div class="fieldgroup">
                <label for="email">
                    Email</label>
                <input type="text" name="email" validation="email"/>
            </div>
            <div class="fieldgroup">
                <label for="password">
                    Password</label>
                <input type="text" name="password" validation="password"/>
            </div>
            <div class="fieldgroup">
                <label for="weibo">
                    Weibo</label>
                <input type="text" name="weibo" validation="url"/>
            </div>

            <div class="fieldgroup">
                <input type="submit" class="submit" value="Sign up">
            </div>
        </fieldset>

        <div class="fieldgroup">
            <p>Already registered? <a href="http://www.cnblogs.com/rush">Sign in</a>.</p>
        </div>
    </form>
    <!-- End Sign Up Form -->
</div>

現在,我們需要驗證Password長度,Email地址和Weibo地址的合法性,首先我們在input標籤中新增validation屬性標記該輸入是否需要驗證,接著我們設定validation的值:required,email,password和url。

validation0

圖1登錄檔單

Validation物件

接下來,我們要建立一個Validation型別(類)用於驗證使用者輸入資訊,它包含4個方法分別用於驗證Name、Email、Password和Url地址資訊。

(function($) {

    // The validation function.
    // We adds validation rules for email, required field, password and url.
    var Validation = function() {

        var rules = {

            email: {
                check: function(value) {

                    if (value)
                        return isValidatedPattern(value, /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/);
                    return true;
                },
                msg: "Please enter a valid e-mail address."
            },
            url: {
                check: function(value) {

                    if (value)
                        return isValidatedPattern(value, /^https?:\/\/(.+\.)+.{2,4}(\/.*)?$/);
                    return true;
                },
                msg: "Please enter a valid URL."
            },
            password: {
                check: function(value) {
                    if (value.length < 8 || value.length > 20) {
                        return false;
                    }
                    else {
                        // Check the password strength enough.
                        return isValidatedPattern(value, /(?=[A-Za-z0-9]{8,20})(?=.*[A-Za-z])(?=.*[0-9])[A-Za-z0-9]+/);
                    }
                },
                msg: "Your password must be at least 8 characters long."
            },
            required: {
                check: function(value) {

                    if (value)
                        return true;
                    else
                        return false;
                },
                msg: "This field is required."
            }
        }
        var isValidatedPattern = function(value, pattern) {
            var regex = pattern;
            var match = regex.exec(value);
            return match;
        }

        // Returns a publish method, then the user can custom validation rule.
        return {

            addRule: function(name, rule) {

                rules[name] = rule;
            },
            getRule: function(name) {

                return rules[name];
            }
        }
    }

    //Creates instance of our object in the jQuery namespace.
    $.Validation = new Validation();
})(jQuery);
// We're passing jQuery into the function
// so we can use $ without potential conflicts.

上面,我們定義了一個Validation型別,通過一個私有的陣列rules儲存了驗證Name、Email、Password和Url物件;每個驗證物件中都包含一個check()方法,如:email物件的check()方法,通過呼叫方法isValidatedPattern(),判斷使用者輸入是否符合驗證規則。

接著,我們返回公開的方法addRule()和getRule(),讓使用者可以通過addRule()方法增加自定義的驗證方法。

我們在Validation型別中定義了公開的方法addRule(),通過該方法我們可以新增自定義的驗證方法,而無需修改我們的外掛程式碼。

接下來,讓我們新增自定義的驗證方法,具體程式碼如下:

// Adds custom rule.
$.validation.addRule("CustomRule", {
    check: function(value) {
        if (value != "JK_Rush") {
            return false;
        }
        return true;
    },
    msg: "Must equal to the word JK_Rush."
});

上面,我們通過addRule()方法添加了自定義的驗證規則,由於addRule()方法是公開的,所以我們可以通過該方法往私有的rules陣列新增自定義的驗證規則。

表單物件

接下來,我們定義一個Form型別,它表示DOM中的表單例項。

// The Form type.
var Form = function(form) {

    var fields = [];

    // Find the field has the validation attribute.
    form.find("[validation]").each(function() {
        var field = $(this);
        if (field.attr('validation') !== undefined) {
            fields.push(new Field(field));
        }
    });
    this.fields = fields;
}

// The Field type.
var Field = function(field) {

    this.field = field;
    this.valid = false;
    //this.attach("change");
}

由於表單中有多個輸入框,我們使用jQuery的each()方法來遍歷表單中所有的輸入框,查詢到輸入框中包含valiation屬性的輸入框,然後把field物件儲存到fields陣列中。

Javascript原型物件

ECMAScript中描述了原型鏈的概念,並將原型鏈作為實現繼承的主要方法。其基本思想是利用原型讓一個引用型別繼承另一個引用型別的屬性和方法。

前面,我們建立一個型別Field用來表示表單中需要驗證的輸入框,那麼Field例項物件必須有一個validate()方法,我們直接給Field物件新增validate()方法,具體實現如下:

var Field = function(field) {

    this.field = field;
    this.valid = false;
    //this.attach("change");
}

Field.validate = function() {
    // Your cdoe here.
}

我們注意到每當建立一個Field物件時,都會分配給該物件一個獨立的validate()方法,如果我們建立30個Field物件,那麼就要給這30物件分配30次validate()方法,其實,validate()方法應該是共享的,也就是說每個Field物件都應該呼叫用一個validate()方法;這時我們可以使用原型鏈方式共享validate()方法。

接下來,讓我們將在Field的原型屬性(prototype)中新增validate()方法,具體實現如下:

// The prototype of Field type.
Field.prototype = {

    // Public method.
    attach: function(event) {

        // The object refers to Field object.
        var obj = this;

        // When the field changed, then invoked the validate method.
        if (event == "change") {
            obj.field.bind("change", function() {
                return obj.validate();
            });
        }

        // When Key up, then invoked the validate method.
        if (event == "keyup") {
            obj.field.bind("keyup", function() {
                return obj.validate();
            });
        }
    },

    // Public method.
    validate: function() {

        var obj = this,
                field = obj.field,
                errorClass = "errorlist",
                errorlist = $(document.createElement("ul")).addClass(errorClass),

        // We can splits the validation attribute with space.
        // Gets all validation types.
                types = field.attr("validation").split(" "),

        // Gets the fieldgroud object.
                container = field.parent(),
                errors = [];

        // If there is an errorlist already present
        // remove it before performing additional validation
        field.next(".errorlist").remove();

        for (var type in types) {

            var rule = $.Validation.getRule(types[type]);

            // If invalid displays the error msg.
            if (!rule.check(field.val())) {

                container.addClass("error");
                errors.push(rule.msg);
            }
        }
        if (errors.length) {

            // Unbinds the keyup event added before.
            obj.field.unbind("keyup")

            // Attaches the keyup event.
            obj.attach("keyup");
            field.after(errorlist.empty());

            // Displays the error msg.
            for (error in errors) {

                errorlist.append("<li>" + errors[error] + "</li>");
            }
            obj.valid = false;
        }
        else {
            errorlist.remove();
            container.removeClass("error");
            obj.valid = true;
        }
    }
}
validation2

我們在Field的原型中添加了兩個方法,attach()方法用來繫結驗證輸入框的keyup和change事件,而validate()方法封裝了呼叫具體校驗方法。

現在,每個Field物件都可以呼叫繼承於原型的attach()和validate()方法,假設表單中包含30個需要校驗的輸入,那麼我們該如何遍歷每個Field物件並且呼叫其validate()方法呢?

其實,Field物件都包含在Form物件中,由於我們在Form型別中定義了fields屬性,它儲存了包含validation屬性field物件,所以我們可以通過訪問Form的fields屬性遍歷每個field物件。

這裡我們給Form的原型新增兩個方法,validate()用來校驗表單物件中的field,isValid()方法判斷field物件是否符合驗證規則,如果不符合規則就把焦點定在該輸入框中。

// The prototype of Form.
Form.prototype = {

    // Validates all the fields in the form object.
    validate: function() {

        for (field in this.fields) {

            this.fields[field].validate();
        }
    },

    // If the field invaild, focus on it.
    isValid: function() {

        for (field in this.fields) {

            if (!this.fields[field].valid) {

                this.fields[field].field.focus();
                return false;
            }
        }
        return true;
    }
}  

validation3

圖3 Form原型物件

外掛使用

現在我們給Form物件添加了validate()和isValid()方法,接下來,我們將使用jQuery的擴充套件方法($.extend),使所有的jQuery物件都可以訪問我們自定義的外掛方法。

// Extends jQuery prototype with validation and validate methods.
$.extend($.fn, {

    validation: function() {

        // Creates a Form instance.
        var validator = new Form($(this));

        // Stores the Form instance in Key/Value collection.
        $.data($(this)[0], 'validator', validator);

        // Binds the submit event.
        $(this).bind("submit", function(e) {
            validator.validate();
            if (!validator.isValid()) {
                e.preventDefault();
            }
        });
    },

    // Checks the field is validated or not.
    validate: function() {

        var validator = $.data($(this)[0], 'validator');
        validator.validate();
        return validator.isValid();

    }
});

我們在jQuery的擴充套件方法($.extend)中添加了兩個方法,它們分別是validation()和 validate();validation()建立了一個Form物件,接著綁定了頁面的submit事件,當頁面方式提交時,驗證表單輸入是否正確。

現在,我們已經完成了自定義的jQuery外掛了,那麼接下來我們將使用該外掛驗證signupform。

我們在表單的HTML中引入jQuery庫和自定義外掛,具體程式碼如下:

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script type="text/javascript" src="js/jquery.formvalidation.js"></script>

當然我們也把jQuery庫下載到本地,然後引入到我們專案中。

接下來,我們在HTML頁面中新增以下程式碼:

$(function() { // jQuery DOM ready function.

    // Get the form object.
    var signUpForm = $("#signup-form");

    // Invokes the validation method.
    signUpForm.validation();
});

當DOM載入完畢後,就呼叫validation驗證外掛,當用戶對頁面進行提交或輸入框的修改都會觸發validate()方法。

1.1.3 總結

本文介紹瞭如何自定義jQuery外掛,首先介紹了jQuery外掛的定義方式,通過給jQuery的$.fn方法新增自定義方法來實現我們的外掛。

接著,我們引入了表單驗證控制元件例子來介紹jQuery外掛的實現;我們在外掛中定義了Form和Field型別,然後通過原型鏈方式共享Form和Field的方法,使得每個Form或Field物件例項可以呼叫其共享的方法。

希望大家在閱讀本博文後,對jQuery外掛的實現有進一步的瞭解。


源引:http://www.cnblogs.com/rush/archive/2012/10/28/2743957.html