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

上一則提到我們試著用 vmodel 做出討論列表,但如果需要讓使用者,針對每一則留言去回覆,那就會更加複雜了。沒關係,我們試試如何透過 vmodel 解決這個複雜的介面設計。vmodel 試圖解決一個明確問題就是:程式碼容易閱讀。解決複雜的介面設計,不代表要用什麼特殊的、另類的、炫麗的技巧來完成,能用最簡單的方式解決困難的問題,是 vmodel() 要做的事情。
比對舊版面與新版面
(舊款)
(新款)
我們可以看到,這次新的版面多多出「回覆列表 + 回覆表單」。回覆列表的每則訊息方塊(黃色姓名的一則一則),都叫做 .comment ,HTML 其實都是直接 copy 原本就有的編碼。只是透過CSS匯了一些樣式。所以我們工程師與設計師溝通,就知道 .comment 的模組勢必可以重複使用。
拿到版面,我們應該會看到靜態HTML編碼長這樣
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
<!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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
<!-- 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> |
我們簡述它的結構表示會長這樣
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
.box .form .list .comment .name .say .current .box_reply // 從這裡開始,是新添加的回覆模組 .list_reply // 放置多筆回覆討論的列表 .comment //這裡是每一則回覆的留言,結構與原本的 .comment 一樣 .name .say .current ~ .form_reply //回覆表單 .text // 使用者輸入的文字 .submit_reply //送出按鈕 ~ |
好的,接著我們要支解這些繼承關係,變成彼此互不關聯的編碼。所以整個架構會變成整樣
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
<!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> |
我們細看這次添加的重點位置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<!-- 以下是新增支解的 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> |
開始修改程式
我們整個修改完的會是這樣
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 |
$(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 渲染彼此的關聯。把每個新模組拼湊起來。
1 2 3 4 |
// 支解後HTML,透過 vmodel 先拼裝起來。 $.vmodel.get("md/box_reply", true); |
先讓 md/box_reply 觸發初始化吧
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
// 回覆框模組 $(".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() 添加送出後的動作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
// 表單模組 $(".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) 後,會把最外層的回覆框模版,整個複製到留言的最後位置。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
//送出時... 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 做放置的部分
1 2 3 4 5 6 7 8 |
// 複製模版,並放到指定的地方 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” 做顯示的動作。
1 2 3 4 5 6 7 8 9 10 |
// 當使用者想要回覆該則留言 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標籤當然也可以,但是我們要盡可能分散。每個根元素盡量分開,並讓不同的概念綁定在上面,才會知道每個根元素,帶有各有不同的意義。再來,性能會比較好。下面是說明
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
.box .form .list <---- 綁在這裡,因為變動次少,不用每次都思考什麼時候還要添加綁定 .comment <-- 這裡常常在添加 .name .say .current .box_reply <-- 綁在這裡,在模版沒問題,但因為上方的 .comment 時常添加,所以連帶這裡也會是新的元素,所以就要重新綁定 .list_reply .comment .name .say .current ~ .form_reply .text .submit_reply ~ |
現在,使用者回覆表單已經顯示出來了,使用者可以在上面打字,打完以後送出的動作,也會在 “md/list” 這邊
1 2 3 4 5 6 7 8 9 |
//當送出回覆表單。要綁定在這裡,而不是綁定在 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” 模組。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
//回覆表單模組 $(".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); } }); |
我們看送出的地方,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
//送出使用者回覆訊息 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()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
//哪個回覆列表,需要重新讀取 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() 負責處理回覆的訊息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
//討論模組 $(".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); } }); |
在這裡我們只需要將數據放入模版、再放到指定地點,這兩件事情而已。
1 2 3 4 5 6 7 |
// 使用者回覆了什麼 this.reply = function (name, say, post_to){ vs.set(name, say) .post_to(post_to); } |
好了,這次擴充回覆留言功能完成了喔!是不是讓你的思維更加清晰了呢?每個模組各司其職,每個方法只做一件小單位的處理,是物件導向的概念。如果本身就使用物件導向開發,一定很快就能將這個概念,透過 vmodel 建構出你的前端介面囉。
Comments