前端MVC 豆瓣说

12,423 views
12,323 views

Published on

Published in: Technology
4 Comments
47 Likes
Statistics
Notes
No Downloads
Views
Total views
12,423
On SlideShare
0
From Embeds
0
Number of Embeds
2,812
Actions
Shares
0
Downloads
362
Comments
4
Likes
47
Embeds 0
No embeds

No notes for slide

前端MVC 豆瓣说

  1. 1. •••
  2. 2. var Comment = Backbone.Model.extend();
  3. 3. var Comment = Backbone.Model.extend();var comment = new Comment({ id: 83562107 text: " “ ” " created_at: "2011-07-03 09:04:34" user: { uid: "keso" id: "1000185" screen_name: "keso" }});
  4. 4. •••
  5. 5. – extend- constructor / initialize– get– set– escape– has– unset– clear– id– cid– attributes– defaults- toJSON
  6. 6. comment.get(text); // “ ” comment.set( {text:<script>alert(xss)</script>}, {silent:true} );– extend comment.escape(text);- constructor / initialize // &lt;script&gt;alert(&#x27xss&#x27)– get &lt;/script&gt;– set– escape comment.has(city); // false– has– unset comment.unset(text); // trigger change event– clear– id– cid– attributes– defaults- toJSON
  7. 7. comment.get(text); // “ ” comment.set( {text:<script>alert(xss)</script>}, {silent:true} );– extend comment.escape(text);- constructor / initialize // &lt;script&gt;alert(&#x27xss&#x27)– get &lt;/script&gt;– set– escape comment.has(city); // false– has– unset comment.unset(text); // trigger change event– clear– id– cid– attributes var Comment = new Backbone.Model.extend({– defaults // hash or function()- toJSON defaults: { source: douban.com }, initialize: function() { ... } }); var comment = new Comment(); comment.get(source); // douban.com
  8. 8. var Comment = new Backbone.Model.extend({ urlRoot: /comments initialize: function(attrs) { ... } }); var comment = new Comment({id:123456});– fetch comment.url(); // /comments/123456 comment.fetch();– save– destroy– validate– url– urlRoot var Comment = new Backbone.Model.extend({– parse initialize: function(attrs) { ... },– clone validate: function(attrs) {– isNew if ( attrs.text.length < 3 ) {– change return 3 – hasChanged }– changedAttributes– previous }– previousAttributes }); var comment = new Comment(); comment.set({text:ok},{ error: function(model,error) { alert(error); } });
  9. 9. •••
  10. 10. •••
  11. 11. var Comments = new Backbone.Collection.extend({ model: Comment, initialize: function(models,options) { }});
  12. 12. [ { text: " “ ” " created_at: "2011-07-03 09:04:34" source: "douban.com" user: { city: " " statuses_count: 172 uid: "keso" following_count: 1688 created_at: "2005-04-07 18:01:26" followers_count: 6178 small_avatar: "http://img3.douban.com/icon/u1000185-2.jpg" id: "1000185" screen_name: "keso" ... } id: 83562107 }, {...} {...}]
  13. 13. App.Collections.Comments = Backbone.Collection.extend({– model– constructor / initialize model: Comment,– models initialize: function(models,options) {– toJSON– Underscore Methods (25) this.url = /api/statuses/ + options.id + /comments– get + (options.count ? ?count= + options.count : )– getByCid + (options.page ? &page= + options.page : ); this.page = 1;– at– length },– comparator comparator: function(model) {– sort return -model.get(id);– pluck }– url– parse });
  14. 14. •••
  15. 15. •••
  16. 16. collection.create(attributes, [options])
  17. 17. collection.create(attributes, [options])var Comments = new Comments([{...}]);
  18. 18. collection.create(attributes, [options])var Comments = new Comments([{...}]);Comments.create({text: "Its no big deal!"});
  19. 19. collection.create(attributes, [options])var Comments = new Comments([{...}]);Comments.create({text: "Its no big deal!"});
  20. 20. collection.create(attributes, [options])var Comments = new Comments([{...}]);Comments.create({text: "Its no big deal!"});var comment = new Comment({ text: "Its no big deal!",});comment.save();Comments.add(comment);
  21. 21. •••
  22. 22. App.Views.Comment = Backbone.View.extend({ className: comment-item, template: $(#comment-item-template).html(), events: { "mouseenter" : "showActions", "mouseleave" : "hideActions" }, initialize: function() { _.bindAll(this, render); this.model.bind(change, this.render); }, render: function() { $(this.el).html(Mustache.to_html(this.template, this.model.toJSON())); $(this.el).attr({ data-item-id: this.model.id, data-comment-id: this.model.id }); return this; }, showActions: function(e) { this.$(.icon-delete).show(); }, hideActions: function(e) { this.$(.icon-delete).hide(); }});
  23. 23. App.Views.Comment = Backbone.View.extend({ className: comment-item, template: $(#comment-item-template).html(), events: { "mouseenter" : "showActions", "mouseleave" : "hideActions" }, initialize: function() { _.bindAll(this, render); this.model.bind(change, this.render); }, render: function() { $(this.el).html(Mustache.to_html(this.template, this.model.toJSON())); $(this.el).attr({ data-item-id: this.model.id, data-comment-id: this.model.id }); return this; }, showActions: function(e) { this.$(.icon-delete).show(); }, var view = new App.Views.Comment({ hideActions: function(e) { model: model this.$(.icon-delete).hide(); }); }}); $(body).append(view.render().el);
  24. 24. App.Router.Shuo = Backbone.Router.extend({ routes: { "" : "home", ":uid" : "profile", ":uid/following" : "following", ":uid/status/:id" : "permalink", "search/:query" : "search" }, initialize: function() { Backbone.history.start({pushState: true, root:/}); }, home: function() { App.Pages.Home = new App.Views.Home(); oBody.append(App.Pages.Home.render().el); this.navigate(); }, profile: function(uid) { App.Pages.Profile[uid] = new App.Views.Profile({uid: uid}); oBody.append(App.Pages.Profile[uid].render().el); this.navigate(uid,true); }, following: function(uid) { ... permalink: function(uid,id) { ... search: function(query) { ...});
  25. 25. router.route(route, name, callback) initialize: function(options) { // Matches #page/10, passing "10" this.route("page/:number", "page", function(number){ ... }); // Matches /117-a/b/c/open, passing "117-a/b/c" this.route(/^(.*?)/open$/, "open", function(id){ ... }); }
  26. 26. ••
  27. 27. Backbone.history.start([options]) App.Router.Shuo = Backbone.Router.extend({ routes: { "" : "home", ":uid" : "profile", ":uid/following" : "following", ":uid/status/:id" : "permalink", "search/:query" : "search" }, initialize: function() { Backbone.history.start({pushState: true, root:/}); }, ...
  28. 28. Backbone.Events◦ "add" (model, collection) — when a model is added to a collection.◦ "remove" (model, collection) — when a model is removed from a collection.◦ "reset" (collection) — when the collections entire contents have been replaced.◦ "change" (model, collection) — when a models attributes have changed.◦ "change:[attribute]" (model, collection) — when a specific attribute has been updated.◦ "destroy" (model, collection) — when a model is destroyed.◦ "error" (model, collection) — when a models validation fails, or a save call fails on the server.◦ "route:[name]" (router) — when one of a routers routes has matched.◦ "all" — this special event fires for any triggered event, passing the event name as the first argument.
  29. 29. object.bind(event, callback) App.Views.Comment = Backbone.View.extend({ className: comment-item, template: $(#comment-item-template).html(), initialize: function() { _.bindAll(this, render); this.model.bind(change, this.render); }, render: function() { $(this.el).html(Mustache.to_html(this.template, this.model.toJSON())); $(this.el).attr({ data-item-id: this.model.id, data-comment-id: this.model.id }); return this; } });
  30. 30. Backbone.sync is the function that Backbone calls every time itattempts to read or save a model to the server. By default, it uses(jQuery/Zepto).ajax to make a RESTful JSON request. You canoverride it in order to use a different persistence strategy, such asWebSockets, XML transport, or Local Storage.
  31. 31. ModelsInteractive Data Domain- specific methods
  32. 32. Models CollectionsInteractive Data Domain- Ordered Sets of Models specific methods
  33. 33. Models CollectionsInteractive Data Domain- Ordered Sets of Models specific methods Views Render HTML/CSS With Javascript templating
  34. 34. Models CollectionsInteractive Data Domain- Ordered Sets of Models specific methods Views Router Render HTML/CSS With Methods For Routing URL Javascript templating Fragments
  35. 35. Models CollectionsInteractive Data Domain- Ordered Sets of Models specific methods Views Router Render HTML/CSS With Methods For Routing URL Javascript templating Fragments
  36. 36. Models CollectionsInteractive Data Domain- Ordered Sets of Models specific methods Views Router Render HTML/CSS With Methods For Routing URL Javascript templating Fragments
  37. 37. public/js
  38. 38. public/js
  39. 39. public/js-- /libs/ |- jquery.js |- backbone.js |- underscore.js |- json2.js |- mustache.js |- cacheprovider.js-- /applications.js-- /models/-- /collections/-- /views/-- /controllers/
  40. 40. ../application.js
  41. 41. var App = { Views: {}, Router: {}, Collections: {}, Cache: new CacheProvider(), initialize: function(){ new App.Router.Shuo(); Backbone.history.start({pushState: true}); } };public/js/application.js
  42. 42. App.Routers.Shuo = Backbone.Router.extend({ routes: { "" : "home", "comments" : "comments", "mentions" : "mentions", ":uid" : "profile", ":uid/following" : "following", ":uid/followers" : "followers", ":uid/status/:id" : "permalink", "search/users/:query" : "user_search", "search/:query" : "search" }, initialize: function() { ... }, home: function() { ... }, comments: function() { ... }, mentions: function() { ... }, profile: function(uid) { ... }, following: function(uid) { ... }, followers: function(uid) { ... }, permalink: function(uid,id) { ... }, user_search: function(query) { ... }, search: function(query) { ... } });public/js/controllers/shuo.js
  43. 43. public/js/models
  44. 44. public/js/models
  45. 45. public/js/models|- comment.js|- comment_notification.js|- mention.js|- stat.js|- status.js|- user.js
  46. 46. public/js/collections
  47. 47. public/js/collections
  48. 48. public/js/collections|- comments.js|- follow_in_common.js|- followers.js|- home_timeline.js|- likers.js|- mentions.js|- resharers.js|- results.js|- suggestions.js|- user_recommendations.js|- user_results.js|- user_timeline.js|- users.js
  49. 49. public/js/views
  50. 50. Home
  51. 51. Main
  52. 52. Main Dashboard
  53. 53. HomeHeader Stream
  54. 54. HomeHeader Navigation Following Followers Suggestion Stream ADs Footer
  55. 55. StatusResharersComments
  56. 56. StatusResharersComments
  57. 57. new App.Views.StreamItem(); model: Status Status model.fetch() this.render()ResharersComments
  58. 58. new App.Views.StreamItem(); model: Status Status model.fetch() this.render()Resharers new App.Views.Resharers()...Comments
  59. 59. new App.Views.StreamItem(); model: Status Status model.fetch() this.render()Resharers new App.Views.Resharers()... new App.Views.Comments() this.collection = new Comments([],{ id: status.idComments }); this.collection.fetch() this.collection.create() this.collection.remove()
  60. 60. ... <div id="page-outer"> </div> ... <script id="status-item-template" type="text/template">...</script> <script id="comment-item-template" type="text/template">...</script> ...template/app.html
  61. 61. App.Views.Permalink = Backbone.View.extend({ el: oDoc, initialize: function(options) { _.bindAll(this, render, loadStatus, loadResharers, loadLikers, loadComments); var self = this; $.ajax(/api/statuses/ + options.id + ?pack=1&comment_count=50&reshare_count=14&like_count=14) .success(function(resp) { self.status = new Status(resp.status, {id: options.id}); self.comments = new App.Collections.Comments(resp.comments, {id: options.id}); self.resharers = new App.Collections.Resharers(resp.reshare_users, {id: options.id}); self.loadStatus(); }) .error(function(resp){ // 404 } }); }, render: function() { return this; }, loadStatus: function() { var view = new App.Views.StreamItem({ model: this.status }); this.loadComments(); this.loadResharers(); oPageContainer.prepend(view.render().el); }, loadResharers: function() { ... }, loadComments: function() { ... } });public/js/views/permalink.js
  62. 62. App.Views.Permalink = Backbone.View.extend({ ... loadComments: function() { var view = new App.Views.Comments({ model: this.status, collection: this.comments }); oPageContainer.prepend(view.render().el); } });public/js/views/permalink.js
  63. 63. App.Views.Comments = Backbone.View.extend({ className: comments-manager, template: $(#comments-components-template).html(), title_template: {{#comments_count}}<h3>{{comments_count}} </h3>{{/comments_count}}, events: { "click .submit" : "submitComment", }, initialize: function(options) { _.bindAll(this,render, loadTitle, loadOne, loadAll); this.status = options.status; this.collection.bind(add, this.loadOne); this.collection.bind(remove, this.loadAll); this.collection.bind(reset, this.loadAll); }, render: function() { $(this.el).html(Mustache.to_html(this.template,{ logged_out: !shuo.loggedIn })); this.title = this.$(.comments-title); this.oBnSubmit = this.$(.submit-area input); this.comments = this.$(.comments-items); this.loadTitle(this.status.toJSON()); this.loadAll(); return this; }, loadOne: function(model) { if ( model.isNew() ) { var view = new App.Views.Comment({ model: model }); this.comments.append(view.render().el); } }, loadTitle: function(data) { this.title.html(Mustache.to_html(this.title_template,data)); }, loadAll: function() {public/js/views/comments.js }, this.collection.each(this.loadOne); create: function(e) {
  64. 64. App.initialize();
  65. 65. BackboneJSMustacheJSUnderscoreJS
  66. 66. BackboneJSMustacheJSUnderscoreJS
  67. 67. MustacheJS
  68. 68. { entities: { user_mentions: [], urls: [] } text: " “ ” " created_at: "2011-07-03 09:04:34" source: "douban.com" user: { city: " " icon_avatar: "http://img3.douban.com/icon/ui1000185-2.jpg" statuses_count: 172 uid: "keso" following_count: 1688 url: "" created_at: "2005-04-07 18:01:26" description: "keso http://blog.donews.com/keso" followers_count: 6178 location: " " small_avatar: "http://img3.douban.com/icon/u1000185-2.jpg" following: false verified: false large_avatar: "http://img3.douban.com/icon/ul1000185-2.jpg" id: "1000185" screen_name: "keso" } id: 83562107}
  69. 69. <script id="comment-item-template" type="text/template"> <div class="comment-item-content" data-user-id="{{#user}}{{uid}}{{/user}}" data-item-id="{{id}}" data-comment-id="{{id}}"> {{#user}} <div class="icon"> <a href="/#{{uid}}"><img src="{{small_avatar}}" alt="{{screen_name}}"/></a> </div> {{/user}} <div class="content"> <p> {{#user}} <a href="/#!/{{uid}}" class="to" title="{{uid}}">{{screen_name}}</a> {{/user}} <span class="comment-time">{{timestamp}}</span> </p> <p> <span class="comment-text">{{{text}}}</span> <a href="" class="icon-comment" title=" "><img src="http://img3.douban.com/anduin/pics/blank.gif"/></a> </p> </div> </div></script>
  70. 70. Mustache.to_html(template,data);
  71. 71. MustacheJS
  72. 72. BackboneJSMustacheJSUnderscoreJS
  73. 73. UnderscoreJS
  74. 74. http://shuo.douban.com/imdonkey

×