jQuery – vmodel.js 討論列表範例教學(2) 添加回覆功能

上一則提到我們試著用 vmodel 做出討論列表,但如果需要讓使用者,針對每一則留言去回覆,那就會更加複雜了。沒關係,我們試試如何透過 vmodel 解決這個複雜的介面設計。vmodel 試圖解決一個明確問題就是:程式碼容易閱讀。解決複雜的介面設計,不代表要用什麼特殊的、另類的、炫麗的技巧來完成,能用最簡單的方式解決困難的問題,是 vmodel() 要做的事情。

線上看即時範例

比對舊版面與新版面

(舊款)

擷取

(新款)

擷取

 

我們可以看到,這次新的版面多多出「回覆列表 + 回覆表單」。回覆列表的每則訊息方塊(黃色姓名的一則一則),都叫做 .comment ,HTML 其實都是直接 copy 原本就有的編碼。只是透過CSS匯了一些樣式。所以我們工程師與設計師溝通,就知道 .comment 的模組勢必可以重複使用。

拿到版面,我們應該會看到靜態HTML編碼長這樣

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vmodel</title>
    <link rel="stylesheet" href="index2.css"><!-- 範例樣式 -->
</head>
<body>
    <div class="box">
        <!-- form -->
        <div class="form">
            <form class="userdata" action="" data-user-name="小明">
                <input type="text" class="text">
                <button class="submit">送出</button>
            </form>
        </div>

        <!-- list -->
        <div class="list">
            <!-- comment -->
            <div class="comment">
                <span class="name">Jason</span> <span class="say">範例文字</span> - <span class="current">下午3:14:50</span>
                
                <!-- 新增的 reply 開始 -->
                <div class="box_reply">
                    <div class="list_reply">
                        <!-- 這裡的 .comment 與上方的 .comment 一模一樣喔 -->
                        <div class="comment">
                            <span class="name">Jason</span> <span class="say">範例文字</span> - <span class="current">下午3:14:50</span>
                        </div>
                        <div class="comment">
                            <span class="name">Jason</span> <span class="say">範例文字</span> - <span class="current">下午3:14:50</span>
                        </div>
                        <div class="comment">
                            <span class="name">Jason</span> <span class="say">範例文字</span> - <span class="current">下午3:14:50</span>
                        </div>
                    </div>
                    <form class="form_reply" data-user-name="Lee">
                        <textarea class="text" placeholder="回覆訊息..."></textarea>
                        <button class="submit_reply">送出</button>
                    </form>
                </div>
                <!-- 新增的 reply 結束 -->


            </div>
            <div class="comment">
                <span class="name">Maple</span> <span class="say">範例文字範例文字範例文字</span> - <span class="current">下午3:14:50</span>
            </div>
            <div class="comment">
                <span class="name">Ghost</span> <span class="say">範例文字範例文字</span> - <span class="current">下午3:14:50</span>
            </div>
        </div>
    </div>

    <!-- 提示訊息顯示 -->
    <div class="message">
        <div class="title">Message</div>
        <div class="liwrap">
            <div class="comment">
                <span class="name">小華</span> <span class="say">哈囉!</span> - <span class="current">下午3:15:39</span>
            </div>
            <div class="comment">
                <span class="name">小華</span> <span class="say">哈囉!</span> - <span class="current">下午3:15:39</span>
            </div>
            <div class="comment">
                <span class="name">小華</span> <span class="say">哈囉!</span> - <span class="current">下午3:15:39</span>
            </div>
        </div>
    </div>
</body>
</html>

好的,太多不想看沒關係,我們看這次新增的重點。位在原本 .comment 底下的最後面,增加了 .box_reply

<!-- comment -->
<div class="comment">
    <span class="name">Jason</span> <span class="say">範例文字</span> - <span class="current">下午3:14:50</span>
    
    <!-- 新增的 reply 開始 -->
    <div class="box_reply">
        <div class="list_reply">
            <!-- 這裡的 .comment 與上方的 .comment 一模一樣喔 -->
            <div class="comment">
                <span class="name">Jason</span> <span class="say">範例文字</span> - <span class="current">下午3:14:50</span>
            </div>
            <div class="comment">
                <span class="name">Jason</span> <span class="say">範例文字</span> - <span class="current">下午3:14:50</span>
            </div>
            <div class="comment">
                <span class="name">Jason</span> <span class="say">範例文字</span> - <span class="current">下午3:14:50</span>
            </div>
        </div>
        <form class="form_reply" data-user-name="Lee">
            <textarea class="text" placeholder="回覆訊息..."></textarea>
            <button class="submit_reply">送出</button>
        </form>
    </div>
    <!-- 新增的 reply 結束 -->


</div>

我們簡述它的結構表示會長這樣

.box 
    .form
    .list
        .comment
            .name
            .say
            .current
            .box_reply // 從這裡開始,是新添加的回覆模組
                .list_reply // 放置多筆回覆討論的列表
                    .comment //這裡是每一則回覆的留言,結構與原本的 .comment 一樣
                        .name
                        .say
                        .current
                    ~
                .form_reply //回覆表單
                    .text // 使用者輸入的文字
                    .submit_reply //送出按鈕
        ~

好的,接著我們要支解這些繼承關係,變成彼此互不關聯的編碼。所以整個架構會變成整樣

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vmodel</title>
    <style></style>
    <script src="//code.jquery.com/jquery-1.11.3.min.js"></script><!-- jQuery 核心 -->
    <script src="../src/jquery.vmodel.min.js"></script><!-- vmodel 核心 -->
    <script src="index2.js"></script><!-- 範例編碼 -->
    <link rel="stylesheet" href="index2.css"><!-- 範例樣式 -->
</head>
<body>
    <!-- 
    預期的結構長這樣

    .box 
        .form
        .list
            .comment
                .name
                .say
                .current
                .box_reply // 從這裡開始,是新添加的回覆模組
                    .list_reply // 放置多筆回覆討論的列表
                        .comment //這裡是每一則回覆的留言,結構與原本的 .comment 一樣
                            .name
                            .say
                            .current
                        ~
                    .form_reply //回覆表單
                        .text // 使用者輸入的文字
                        .submit_reply //送出按鈕
            ~
    -->


    <!-- 四種模組的編碼 -->

    <!-- box -->
    <div class="box"></div>

    <!-- form -->
    <div class="form">
        <form class="userdata" action="" data-user-name="小明">
            <input type="text" class="text" autofocus>
            <button class="submit">送出</button>
        </form>
    </div>

    <!-- list -->
    <div class="list"></div>

    <!-- comment 預先隱藏起來 -->
    <div class="comment" hidden>
        <span class="name"></span> <span class="say"></span> - <span class="current"></span>
    </div>

    <!-- 提示訊息顯示 -->
    <div class="message">
        <div class="title">Message</div>
        <div class="liwrap"></div>
    </div>

    <!-- 以下是新增支解的 3 個模組, 其中 .comment 我們會使用上面已經有的模組做後續的程式擴充 -->

    <!-- reply -->
    <div class="box_reply" hidden>
    </div>

    <!-- list -->
    <div class="list_reply">
    </div>

    <!-- form -->
    <form class="form_reply" data-user-name="Lee" hidden>
        <textarea class="text" placeholder="回覆訊息..."></textarea>
        <button class="submit_reply">送出</button>
    </form>

</body>
</html>

我們細看這次添加的重點位置

<!-- 以下是新增支解的 3 個模組, 其中 .comment 我們會使用上面已經有的模組做後續的程式擴充 -->

<!-- reply -->
<div class="box_reply" hidden>
</div>

<!-- list -->
<div class="list_reply">
</div>

<!-- form -->
<form class="form_reply" data-user-name="Lee" hidden>
    <textarea class="text" placeholder="回覆訊息..."></textarea>
    <button class="submit_reply">送出</button>
</form>

開始修改程式

我們整個修改完的會是這樣

$(function (){

    // 表單模組
    $(".form").vmodel("md/form", false, function (){

        var vs = this;

        this.autoload = ['init_position', 'submit'];

        // 初始化會被搬移到 .box 底下
        this.init_position = function (){
            vs.root.appendTo(".box");
        }

        // 取得輸入的文字
        this.user_say = function (){
            var val = vs.root.find(".text").val();
            return $.trim(val);
        }

        // 取得使用者是誰
        this.user_name = function (){
            return $.trim(vs.root.find(".userdata").attr("data-user-name"));
        }

        // 負責放到 .comment
        this.put = function (user, say, callback){
            $.vmodel.get("md/comment").say(user, say);
            if (callback) callback();
        }

        //送出時...
        this.submit = function (){
            vs.root.on("submit", ".userdata", function (){
                var user = vs.user_name();
                var say = vs.user_say();
                vs.put(user, say, function (){
                    //發送後可以做一些事情...
                    //將回覆框放進來
                    var where = $(".list .comment").first();
                    $.vmodel.get("md/box_reply").post_to(where)
                });

                return false;
            })
        }

        // 清空
        this.clean = function (){
            vs.root.find(".text").val(null);
        }

    });

    // 列表模組
    $(".list").vmodel("md/list", false, function (){

        var vs = this;

        this.autoload = ['init_position', 'when_reply', 'when_send_reply'];

        // 這裡只負責推送到 .box ,為了範例簡單,我們這裡不推到 message。
        this.init_position = function (){
            vs.root.appendTo(".box");
        }

        // 當使用者想要回覆該則留言
        this.when_reply = function() {
            vs.root.on("click", ".comment .say", function (){
                //顯示該則的回覆表單
                var who = $(this).parents(".comment");
                $.vmodel.get("md/form_reply").show(who);
            });
        }

        //當送出回覆表單。要綁定在這裡,而不是綁定在 md/comment ,是因為 .list 是不會變動的。
        this.when_send_reply = function (){
            vs.root.on("submit", ".form_reply", function (){
                $.vmodel.get("md/form_reply").send(this);
                return false;
            });
        }

    });


    // 整體框的主要模組
    $(".box").vmodel("md/box", false, function (){

        var vs = this;

        this.autoload = ['init'];

        this.init = function (){

            //只放置表單、與列表框到指定的位置。
            //目前 .list 應該不會有任何資料,一直到使用者送出表單。
            vs.create_form()
                .create_list();
        }

        //初始化使用者表單
        this.create_form = function (){
            $.vmodel.get("md/form", true);
            return vs;
        }

        //初始化列表
        this.create_list = function (){
            $.vmodel.get("md/list", true);
        }

    });

    //討論模組
    $(".comment").vmodel("md/comment", false, function (){

        var vs = this;

        // 使用者說了什麼
        this.say = function (name, say){
            
            vs.set(name, say)
                .post_to(".box .list");

            // 記得清空
            $.vmodel.get("md/form").clean();

            // 也可以把模板清空
            vs.clean();

            return vs;
        }

        // 使用者回覆了什麼
        this.reply = function (name, say, post_to){
            vs.set(name, say)
                .post_to(post_to);
        }

        // 將數據放入模板
        this.set = function (name, say){
            vs.root.find(".name").html(name);
            vs.root.find(".say").html(say);

            // 我們加入時間
            var NowDate = new Date();
            vs.root.find(".current").html(NowDate.toLocaleTimeString());
            return vs;
        }

        // 放到列表中
        this.post_to = function(selector){
            //需要先拔除原本的 hidden 屬性才能顯示。
            var obj = vs.root.clone()
            obj.removeAttr('hidden').prependTo(selector);
            return vs;
        }

        // 清空
        this.clean = function (){
            vs.root.find(".name").html(null);
            vs.root.find(".say").html(null);
            vs.root.find(".current").html(null);
        }

    });

    //訊息模組。這個模組是主動式的。也就是當使用者送出資料以後,並不見得會馬上啟用訊息模組。
    $(".message").vmodel("md/message", false, function (){
        
        var vs = this;

        this.autoload = ['interval'];

        // 定時更新
        this.interval = function (){

            //這裡使用 setInterval 作範例,實際上可透過其他效能較好的方式
            setInterval(function (){
                vs.update();
            }, 2000);
        }


        // 更新訊息
        this.update = function (){
            
            // 應該是由 AJAX 向遠端更新訊息。因為遠端的關係,通常會比較慢才取回資料。
            // 我們這邊只假設是本地數據。並延遲觸發來模擬遠端的感覺。

            setTimeout(function (){

                var NowDate = new Date();

                var data = [{
                    name: "小華",
                    say: "哈囉!",
                    current: NowDate.toLocaleTimeString()
                }];

                var comment = $.vmodel.get("md/comment");

                $.each(data, function(index, ele) {
                    comment
                        .set(ele.name, ele.say, ele.current)
                        .post_to(vs.selector + " .liwrap");
                });

            }, 200);
            
        }
    });

    // 全部都定義好了,我們去觸發 box 模組與 message 模組吧
    $.vmodel.get("md/box", true);
    $.vmodel.get("md/message", true);

    /*******/

    // 回覆框模組
    $(".box_reply").vmodel("md/box_reply", false, function (){
        var vs = this;
        this.autoload = ['init'];
        //初始化
        this.init = function (){
            //將回覆列表與表單,放到 .box_reply 裡面
            vs.create_list()
                .create_form();
        }
        //建立表單
        this.create_form = function (){
            //讓 "md/form_reply" 初始化
            $.vmodel.get("md/form_reply", true);
            return this;
        }
        //建立列表
        this.create_list = function (){
            //讓 "md/list_reply" 初始化
            $.vmodel.get("md/list_reply", true);
            return this;
        }
        // 複製模版,並放到指定的地方
        this.post_to = function (selector){
            var newobj = vs.root.clone();
            //這時候先不要移除 .form_reply 的 hidden,因為我們要等到使用者需要回覆時,才會顯示。
            newobj.removeAttr("hidden").appendTo(selector);
        }
    });

    //回覆表單模組
    $(".form_reply").vmodel("md/form_reply", false, function (){
        var vs = this;
        this.autoload = ['init'];
        //初始化
        this.init = function (){
            //放到位置
            vs.root.appendTo('.box_reply');
        }
        //顯示表單
        this.show = function (selector){
            $(selector).find(".form_reply").removeAttr('hidden');
        }
        //送出使用者回覆訊息
        this.send = function (selector){
            var name = $(selector).attr("data-user-name");
            var text = $(selector).find(".text").val();

            // 等候重整的回覆列表是誰
            var who = $(selector).parents(".box_reply").find(".list_reply");   
            
            //通常我們可以使用 AJAX 送出,但我們這裡使用本地的模擬延遲
            setTimeout(function() {

                //重新讀取該則回覆列表
                $.vmodel.get("md/list_reply").reload(who, function (){
                    //也許可以做一些事情....
                });

                // 清空表單
                vs.clean(selector);

            }, 100);
        }
        
        //清空哪個回覆表單
        this.clean = function (selector){
            $(selector).find(".text").val(null);
        }
    });

    //回覆列表模組
    $(".list_reply").vmodel("md/list_reply", false, function (){
        var vs = this;
        this.autoload = ['init'];
        // 初始化
        this.init = function (){
            //放到位置
            vs.root.appendTo('.box_reply');
        }
        //哪個回覆列表,需要重新讀取
        this.reload = function (selector, callback){
            
            //假設我們模擬透過 AJAX 取得遠端的數據
            var data = [{
                name: "新人",
                text: "早安 (其實我是本地產生的數據)"
            }, {
                name: "新人2",
                text: "午安 (其實我也是本地產生的數據)"
            }];

            $.each(data, function(index, info) {
                //我們要呼叫一開始的模組,因為避免重新設計,討論 .comment 都是使用一款模組。
                $.vmodel.get("md/comment").reply(info.name, info.text, selector);
            });

            if (callback) callback();
        }
    });




    
    
    
    
    // 支解後HTML,透過 vmodel 先拼裝起來。
    $.vmodel.get("md/box_reply", true);

    // 送出留言後,添加回覆框。所以在 "md/form" this.submit() 添加送出後的動作

    //使用者想要回覆留言,所以添加了事件,在 "md/list" this.when_reply()
    



})

建立關係

要添加新的模組,我們一樣,要先透過 vmodel 渲染彼此的關聯。把每個新模組拼湊起來。

// 支解後HTML,透過 vmodel 先拼裝起來。
$.vmodel.get("md/box_reply", true);

先讓 md/box_reply 觸發初始化吧

// 回覆框模組
$(".box_reply").vmodel("md/box_reply", false, function (){
    var vs = this;
    this.autoload = ['init'];
    //初始化
    this.init = function (){
        //將回覆列表與表單,放到 .box_reply 裡面
        vs.create_list()
            .create_form();
    }
    //建立表單
    this.create_form = function (){
        //讓 "md/form_reply" 初始化
        $.vmodel.get("md/form_reply", true);
        return this;
    }
    //建立列表
    this.create_list = function (){
        //讓 "md/list_reply" 初始化
        $.vmodel.get("md/list_reply", true);
        return this;
    }
    // 複製模版,並放到指定的地方
    this.post_to = function (selector){
        var newobj = vs.root.clone();
        //這時候先不要移除 .form_reply 的 hidden,因為我們要等到使用者需要回覆時,才會顯示。
        newobj.removeAttr("hidden").appendTo(selector);
    }
});

目前我們只是去呼叫  “md/form_reply” 與 “md/list_reply” 讓它們將HTML擺放到我們希望的位置,也就是 .box_reply 底下。

添加隱藏的回覆框

.box_reply 目前還是在最外層喔,沒有歸屬在誰底下。一直到「使用者點選某人的留言文字,才會出現」。所以我們修改 “md/form” 並添加了 this.submit() 添加送出後的動作

// 表單模組
$(".form").vmodel("md/form", false, function (){

    var vs = this;

    this.autoload = ['init_position', 'submit'];

    // 初始化會被搬移到 .box 底下
    this.init_position = function (){
        vs.root.appendTo(".box");
    }

    // 取得輸入的文字
    this.user_say = function (){
        var val = vs.root.find(".text").val();
        return $.trim(val);
    }

    // 取得使用者是誰
    this.user_name = function (){
        return $.trim(vs.root.find(".userdata").attr("data-user-name"));
    }

    // 負責放到 .comment
    this.put = function (user, say, callback){
        $.vmodel.get("md/comment").say(user, say);
        if (callback) callback();
    }

    //送出時...
    this.submit = function (){
        vs.root.on("submit", ".userdata", function (){
            var user = vs.user_name();
            var say = vs.user_say();
            vs.put(user, say, function (){
                //發送後可以做一些事情...
                //將回覆框放進來
                var where = $(".list .comment").first();
                $.vmodel.get("md/box_reply").post_to(where)
            });

            return false;
        })
    }

    // 清空
    this.clean = function (){
        vs.root.find(".text").val(null);
    }

});

沒錯,我們是透過自訂的回呼含式,讓使用者送出討論表單 (.form) 後,會把最外層的回覆框模版,整個複製到留言的最後位置。

//送出時...
this.submit = function (){
    vs.root.on("submit", ".userdata", function (){
        var user = vs.user_name();
        var say = vs.user_say();
        vs.put(user, say, function (){
            //發送後可以做一些事情...
            //將回覆框放進來
            var where = $(".list .comment").first();
            $.vmodel.get("md/box_reply").post_to(where)
        });

        return false;
    })
}

我們看看呼叫 md/box_reply 做放置的部分

// 複製模版,並放到指定的地方
this.post_to = function (selector){
    var newobj = vs.root.clone();
    //這時候先不要移除 .form_reply 的 hidden,因為我們要等到使用者需要回覆時,才會顯示。
    newobj.removeAttr("hidden").appendTo(selector);
}

這樣就完成了。我們在最上方打上文字、按下送出,會把文字更新到下方的列表。這時候下方列表,「會加入被隱藏的回覆框」。

當使用者想要針對某則留言做回覆

使用者點了留言文字,這件事情我們要修改在 “md/list” 並添加新的 this.when_reply() ,我們會去呼叫模組 “md/form_reply” 做顯示的動作。

// 當使用者想要回覆該則留言
this.when_reply = function() {
    vs.root.on("click", ".comment .say", function (){
        //顯示該則的回覆表單
        var who = $(this).parents(".comment");
        $.vmodel.get("md/form_reply").show(who);
    });
}

注意!為什麼事件要綁定在 “md/list” 模組,而不是在 “md/form_reply” 呢?這是一個經驗上的複雜問題,但歸類到的經驗結果很簡單,因為比較好做。將事件綁定在 “最少動態添加的位置” 是比較適合的,這樣可以大幅降低手寫動態綁定的事情。當然,要把所有事件都綁在同一個HTML標籤當然也可以,但是我們要盡可能分散。每個根元素盡量分開,並讓不同的概念綁定在上面,才會知道每個根元素,帶有各有不同的意義。再來,性能會比較好。下面是說明

.box 
    .form
    .list <---- 綁在這裡,因為變動次少,不用每次都思考什麼時候還要添加綁定
        .comment <-- 這裡常常在添加
            .name
            .say
            .current
            .box_reply <-- 綁在這裡,在模版沒問題,但因為上方的 .comment 時常添加,所以連帶這裡也會是新的元素,所以就要重新綁定
                .list_reply 
                    .comment 
                        .name
                        .say
                        .current
                    ~
                .form_reply 
                    .text 
                    .submit_reply 
        ~

現在,使用者回覆表單已經顯示出來了,使用者可以在上面打字,打完以後送出的動作,也會在 “md/list” 這邊

//當送出回覆表單。要綁定在這裡,而不是綁定在 md/comment ,是因為 .list 是不會變動的。
this.when_send_reply = function (){
    vs.root.on("submit", ".form_reply", function (){
        $.vmodel.get("md/form_reply").send(this);
        return false;
    });
}

送出的實際動作我們交給 “md/form_reply” .send() 去執行。並傳入,現在哪張回覆表單要送出。這很重要喔。我們看一下整體的 “md/form_reply” 模組。

//回覆表單模組
$(".form_reply").vmodel("md/form_reply", false, function (){
    var vs = this;
    this.autoload = ['init'];
    //初始化
    this.init = function (){
        //放到位置
        vs.root.appendTo('.box_reply');
    }
    //顯示表單
    this.show = function (selector){
        $(selector).find(".form_reply").removeAttr('hidden');
    }
    //送出使用者回覆訊息
    this.send = function (selector){
        var name = $(selector).attr("data-user-name");
        var text = $(selector).find(".text").val();

        // 等候重整的回覆列表是誰
        var who = $(selector).parents(".box_reply").find(".list_reply");   
        
        //通常我們可以使用 AJAX 送出,但我們這裡使用本地的模擬延遲
        setTimeout(function() {

            //重新讀取該則回覆列表
            $.vmodel.get("md/list_reply").reload(who, function (){

            });

            // 清空表單
            vs.clean(selector);

        }, 100);
    }
    
    //清空哪個回覆表單
    this.clean = function (selector){
        $(selector).find(".text").val(null);
    }
});

我們看送出的地方,

//送出使用者回覆訊息
this.send = function (selector){
    var name = $(selector).attr("data-user-name");
    var text = $(selector).find(".text").val();

    // 等候重整的回覆列表是誰
    var who = $(selector).parents(".box_reply").find(".list_reply");   
    
    //通常我們可以使用 AJAX 送出,但我們這裡使用本地的模擬延遲
    setTimeout(function() {

        //重新讀取該則回覆列表
        $.vmodel.get("md/list_reply").reload(who, function (){
                //也許可以做一些事情....
        });

        // 清空表單
        vs.clean(selector);

    }, 100);

我們送出回覆文字,會需要馬上更新該則訊息的「回覆列表」,所以我們要知道等下是「哪篇訊息的回覆列表」需要被更新。所以更新回覆列表,我們看 “md/list_reply” 的 reload()

//哪個回覆列表,需要重新讀取
this.reload = function (selector, callback){
    
    //假設我們模擬透過 AJAX 取得遠端的數據
    var data = [{
        name: "新人",
        text: "早安 (其實我是本地產生的數據)"
    }, {
        name: "新人2",
        text: "午安 (其實我也是本地產生的數據)"
    }];

    $.each(data, function(index, info) {
        //我們要呼叫一開始的模組,因為避免重新設計,討論 .comment 都是使用一款模組。
        $.vmodel.get("md/comment").reply(info.name, info.text, selector);
    });

    if (callback) callback();
}

因為該篇留言,可能有很多人回覆了,所以我們透過AJAX取得資料,批次將它顯示,也就是透過 “md/comment” .reply() 將訊息放入。

“md/comment” 在上篇例子已經存在,他是負責處理每則討論訊息的模組。我們這裡擴充了 .reply() 負責處理回覆的訊息。

//討論模組
$(".comment").vmodel("md/comment", false, function (){

    var vs = this;

    // 使用者說了什麼
    this.say = function (name, say){
        
        vs.set(name, say)
            .post_to(".box .list");

        // 記得清空
        $.vmodel.get("md/form").clean();

        // 也可以把模板清空
        vs.clean();

        return vs;
    }

    // 使用者回覆了什麼
    this.reply = function (name, say, post_to){
        vs.set(name, say)
            .post_to(post_to);
    }

    // 將數據放入模板
    this.set = function (name, say){
        vs.root.find(".name").html(name);
        vs.root.find(".say").html(say);

        // 我們加入時間
        var NowDate = new Date();
        vs.root.find(".current").html(NowDate.toLocaleTimeString());
        return vs;
    }

    // 放到列表中
    this.post_to = function(selector){
        //需要先拔除原本的 hidden 屬性才能顯示。
        var obj = vs.root.clone()
        obj.removeAttr('hidden').prependTo(selector);
        return vs;
    }

    // 清空
    this.clean = function (){
        vs.root.find(".name").html(null);
        vs.root.find(".say").html(null);
        vs.root.find(".current").html(null);
    }

});

在這裡我們只需要將數據放入模版、再放到指定地點,這兩件事情而已。

// 使用者回覆了什麼
this.reply = function (name, say, post_to){
    vs.set(name, say)
        .post_to(post_to);
}

好了,這次擴充回覆留言功能完成了喔!是不是讓你的思維更加清晰了呢?每個模組各司其職,每個方法只做一件小單位的處理,是物件導向的概念。如果本身就使用物件導向開發,一定很快就能將這個概念,透過 vmodel 建構出你的前端介面囉。

 

完整教學範例

Comments

發表迴響