https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93viewmodelcss
Model–view–view-model (MVVM) is a software architectural pattern.html
MVVM facilitates a separation of development of the graphical user interface – be it via a markup language or GUI code – from development of the business logic or back-end logic (the data model). The view model of MVVM is a value converter;[1] meaning the view model is responsible for exposing (converting) the data objects from the model in such a way that objects are easily managed and presented. In this respect, the view model is more model than view, and handles most if not all of the view's display logic.[1] The view model may implement a mediator pattern, organizing access to the back-end logic around the set of use cases supported by the view.jquery
- View model
- The view model is an abstraction of the view exposing public properties and commands. Instead of the controller of the MVC pattern, or the presenter of the MVP pattern, MVVM has a binder. In the view model, the binder mediates communication between the view and the data binder. [clarification needed] The view model has been described as a state of the data in the model. [7]
- Binder
- Declarative data- and command-binding are implicit in the MVVM pattern. In the Microsoft solution stack, the binder is a markup language called XAML. [8] The binder frees the developer from being obliged to write boiler-plate logic to synchronize the view model and view. When implemented outside of the Microsoft stack the presence of a declarative databinding technology is a key enabler of the pattern. [4] [9] [clarification needed]
https://linux.cn/article-6481-1.html?utm_medium=weibolinux
MVVM表明的是Model-View-ViewModel,这里须要解释一下什么是ViewModel。ViewModel的含义就是 "Model of View",视图的模型。它的含义包含了领域模型(Domain Model)和视图的状态(State)。 在图形界面应用程序当中,界面所提供的信息可能不只仅包含应用程序的领域模型。还可能包含一些领域模型不包含的视图状态,例如电子表格程序上须要显示当前排序的状态是顺序的仍是逆序的,而这是Domain Model所不包含的,但也是须要显示的信息。git
能够简单把ViewModel理解为页面上所显示内容的数据抽象,和Domain Model不同,ViewModel更适合用来描述View。程序员
MVVM的调用关系和MVP同样。可是,在ViewModel当中会有一个叫Binder,或者是Data-binding engine的东西。之前所有由Presenter负责的View和Model之间数据同步操做交由给Binder处理。你只须要在View的模版语法当中,指令式地声明View上的显示的内容是和Model的哪一块数据绑定的。当ViewModel对进行Model更新的时候,Binder会自动把数据更新到View上去,当用户对View进行操做(例如表单输入),Binder也会自动把数据更新到Model上去。这种方式称为:Two-way data-binding,双向数据绑定。能够简单而不恰当地理解为一个模版引擎,可是会根据数据变动实时渲染。github
https://linux.cn/article-6481-1.html?utm_medium=weiboweb
用户的对View操做之后,View捕获到这个操做,会把处理的权利交移给Controller(Pass calls);Controller会对来自View数据进行预处理、决定调用哪一个Model的接口;而后由Model执行相关的业务逻辑;当Model变动了之后,会经过观察者模式(Observer Pattern)通知View;View经过观察者模式收到Model变动的消息之后,会向Model请求最新的数据,而后从新更新界面。以下图:docker
MVC模式同样,用户对View的操做都会从View交移给Presenter。Presenter会执行相应的应用程序逻辑,而且对Model进行相应的操做;而这时候Model执行完业务逻辑之后,也是经过观察者模式把本身变动的消息传递出去,可是是传给Presenter而不是View。Presenter获取到Model变动的消息之后,经过View提供的接口更新界面。数据库
关键点:
- View再也不负责同步的逻辑,而是由Presenter负责。Presenter中既有应用程序逻辑也有同步逻辑。
- View须要提供操做界面的接口给Presenter进行调用。(关键)
https://segmentfault.com/q/1010000000534091
而MVVM派的见解是,我给view里面的各类控件也定义一个对应的数据对象,这样,只要修改这个数据对象,view里面显示的内容就自动跟着刷新,而在view 里作了任何操做,这个数据对象也跟着自动更新,这样多美。因此:
ViewModel:就是与界面(view)对应的Model。由于,数据库结构每每是不能直接跟界面控件一一对应上的,因此,须要再定义一个数据对象专门对应view上的控件。而ViewModel的职责就是把model对象封装成能够显示和接受输入的界面数据对象。
至于viewmodel的数据随着view自动刷新,而且同步到model里去,这部分代码能够写成公用的框架,不用程序员本身操心了。
想好说清楚,最好就是使用用例来解释MVVM是如何工做的,下图以AngularJS为例。
如图所示,
App.html
是与app.js
中的ViewModel
绑定的View
。若是有人想要修改app.js
中的$scope.user
的name
属性,那么它会自动更新app.html
中对应的name
属性。反之也成立,若是有人想要修改app.html
中的name
属性值,那么也会自动更新$scope.user
对象。App.html
同时也能够对app.js
发出命令,如调用$scope.save
函数从而让app.js
执行一些逻辑操做,如保存$scope.user
至users.js
模型中并与后端同步,那么它就能够与整个应用程序共享。
MVVM
模式对于RIA
应用来讲是很是必要的,由于View
被绑定至ViewModel
的,而且当ViewModel
的状态变化时,View
会自动更新,它有效的隔离了View
和它背后的业务逻辑。这也是为何AngularJS须要双向绑定的缘由。
https://www.zhihu.com/question/28893576
去年暑假实习一直在作MVVM的开发。就我所知全部的后端和业务逻辑都应该是在M端的,写界面XAML是V端,先后端之间能够互不干扰完成设计/开发,最后再加一个VM,而VM作的事就是衔接V和M。 Wiki上这一段很清楚地解释了view model的做用,也就是把model中的数据对象转换成view能够直接使用的形式(好比string或者collection等等)。
视图层 V,展示数据,绑定事件,
视图模型层 VM, 从数据模型层变换而来, 除了数据或状态flag,还有许多事件回调,$watch回调(当某个数据变更时会执行的函数), widget的配置对象
模型层 M, 这是经过AJAX请求获得,或者经过后端输出时就打印在页面某个script标签内, 都是数据(JSON),没有函数
业务逻辑层 BS,这不归为MVVM以内,但它们应该使用类进行组织,在VM中的某个函数里面被调用。
http://backbonejs.org/#Getting-started
Backbone.js gives structure to web applications by providing models with key-value binding and custom events, collections with a rich API of enumerable functions, views with declarative event handling, and connects it all to your existing API over a RESTful JSON interface.
When working on a web application that involves a lot of JavaScript, one of the first things you learn is to stop tying your data to the DOM. It's all too easy to create JavaScript applications that end up as tangled piles of jQuery selectors and callbacks, all trying frantically to keep data in sync between the HTML UI, your JavaScript logic, and the database on your server. For rich client-side applications, a more structured approach is often helpful.
With Backbone, you represent your data as Models, which can be created, validated, destroyed, and saved to the server. Whenever a UI action causes an attribute of a model to change, the model triggers a "change" event; all the Views that display the model's state can be notified of the change, so that they are able to respond accordingly, re-rendering themselves with the new information. In a finished Backbone app, you don't have to write the glue code that looks into the DOM to find an element with a specific id, and update the HTML manually — when the model changes, the views simply update themselves.
Philosophically, Backbone is an attempt to discover the minimal set of data-structuring (models and collections) and user interface (views and URLs) primitives that are generally useful when building web applications with JavaScript. In an ecosystem where overarching, decides-everything-for-you frameworks are commonplace, and many libraries require your site to be reorganized to suit their look, feel, and default behavior — Backbone should continue to be a tool that gives you the freedom to design the full experience of your web application.
todolist
http://backbonejs.org/examples/todos/index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Backbone.js Todos</title> <link rel="stylesheet" href="todos.css"/> </head> <body> <div id="todoapp"> <header> <h1>Todos</h1> <input id="new-todo" type="text" placeholder="What needs to be done?"> </header> <section id="main"> <input id="toggle-all" type="checkbox"> <label for="toggle-all">Mark all as complete</label> <ul id="todo-list"></ul> </section> <footer> <a id="clear-completed">Clear completed</a> <div id="todo-count"></div> </footer> </div> <div id="instructions"> Double-click to edit a todo. </div> <div id="credits"> Created by <br /> <a href="http://jgn.me/">Jérôme Gravel-Niquet</a>. <br />Rewritten by: <a href="https://github.com/tastejs/todomvc">TodoMVC</a>. </div> <script src="../../test/vendor/json2.js"></script> <script src="../../test/vendor/jquery.js"></script> <script src="../../test/vendor/underscore.js"></script> <script src="../../backbone.js"></script> <script src="../backbone.localStorage.js"></script> <script src="todos.js"></script> <!-- Templates --> <script type="text/template" id="item-template"> <div class="view"> <input class="toggle" type="checkbox" <%= done ? 'checked="checked"' : '' %> /> <label><%- title %></label> <a class="destroy"></a> </div> <input class="edit" type="text" value="<%- title %>" /> </script> <script type="text/template" id="stats-template"> <% if (done) { %> <a id="clear-completed">Clear <%= done %> completed <%= done == 1 ? 'item' : 'items' %></a> <% } %> <div class="todo-count"><b><%= remaining %></b> <%= remaining == 1 ? 'item' : 'items' %> left</div> </script> </body> </html>
// An example Backbone application contributed by // [Jérôme Gravel-Niquet](http://jgn.me/). This demo uses a simple // [LocalStorage adapter](backbone.localStorage.html) // to persist Backbone models within your browser. // Load the application once the DOM is ready, using `jQuery.ready`: $(function(){ // Todo Model // ---------- // Our basic **Todo** model has `title`, `order`, and `done` attributes. var Todo = Backbone.Model.extend({ // Default attributes for the todo item. defaults: function() { return { title: "empty todo...", order: Todos.nextOrder(), done: false }; }, // Toggle the `done` state of this todo item. toggle: function() { this.save({done: !this.get("done")}); } }); // Todo Collection // --------------- // The collection of todos is backed by *localStorage* instead of a remote // server. var TodoList = Backbone.Collection.extend({ // Reference to this collection's model. model: Todo, // Save all of the todo items under the `"todos-backbone"` namespace. localStorage: new Backbone.LocalStorage("todos-backbone"), // Filter down the list of all todo items that are finished. done: function() { return this.where({done: true}); }, // Filter down the list to only todo items that are still not finished. remaining: function() { return this.where({done: false}); }, // We keep the Todos in sequential order, despite being saved by unordered // GUID in the database. This generates the next order number for new items. nextOrder: function() { if (!this.length) return 1; return this.last().get('order') + 1; }, // Todos are sorted by their original insertion order. comparator: 'order' }); // Create our global collection of **Todos**. var Todos = new TodoList; // Todo Item View // -------------- // The DOM element for a todo item... var TodoView = Backbone.View.extend({ //... is a list tag. tagName: "li", // Cache the template function for a single item. template: _.template($('#item-template').html()), // The DOM events specific to an item. events: { "click .toggle" : "toggleDone", "dblclick .view" : "edit", "click a.destroy" : "clear", "keypress .edit" : "updateOnEnter", "blur .edit" : "close" }, // The TodoView listens for changes to its model, re-rendering. Since there's // a one-to-one correspondence between a **Todo** and a **TodoView** in this // app, we set a direct reference on the model for convenience. initialize: function() { this.listenTo(this.model, 'change', this.render); this.listenTo(this.model, 'destroy', this.remove); }, // Re-render the titles of the todo item. render: function() { this.$el.html(this.template(this.model.toJSON())); this.$el.toggleClass('done', this.model.get('done')); this.input = this.$('.edit'); return this; }, // Toggle the `"done"` state of the model. toggleDone: function() { this.model.toggle(); }, // Switch this view into `"editing"` mode, displaying the input field. edit: function() { this.$el.addClass("editing"); this.input.focus(); }, // Close the `"editing"` mode, saving changes to the todo. close: function() { var value = this.input.val(); if (!value) { this.clear(); } else { this.model.save({title: value}); this.$el.removeClass("editing"); } }, // If you hit `enter`, we're through editing the item. updateOnEnter: function(e) { if (e.keyCode == 13) this.close(); }, // Remove the item, destroy the model. clear: function() { this.model.destroy(); } }); // The Application // --------------- // Our overall **AppView** is the top-level piece of UI. var AppView = Backbone.View.extend({ // Instead of generating a new element, bind to the existing skeleton of // the App already present in the HTML. el: $("#todoapp"), // Our template for the line of statistics at the bottom of the app. statsTemplate: _.template($('#stats-template').html()), // Delegated events for creating new items, and clearing completed ones. events: { "keypress #new-todo": "createOnEnter", "click #clear-completed": "clearCompleted", "click #toggle-all": "toggleAllComplete" }, // At initialization we bind to the relevant events on the `Todos` // collection, when items are added or changed. Kick things off by // loading any preexisting todos that might be saved in *localStorage*. initialize: function() { this.input = this.$("#new-todo"); this.allCheckbox = this.$("#toggle-all")[0]; this.listenTo(Todos, 'add', this.addOne); this.listenTo(Todos, 'reset', this.addAll); this.listenTo(Todos, 'all', this.render); this.footer = this.$('footer'); this.main = $('#main'); Todos.fetch(); }, // Re-rendering the App just means refreshing the statistics -- the rest // of the app doesn't change. render: function() { var done = Todos.done().length; var remaining = Todos.remaining().length; if (Todos.length) { this.main.show(); this.footer.show(); this.footer.html(this.statsTemplate({done: done, remaining: remaining})); } else { this.main.hide(); this.footer.hide(); } this.allCheckbox.checked = !remaining; }, // Add a single todo item to the list by creating a view for it, and // appending its element to the `<ul>`. addOne: function(todo) { var view = new TodoView({model: todo}); this.$("#todo-list").append(view.render().el); }, // Add all items in the **Todos** collection at once. addAll: function() { Todos.each(this.addOne, this); }, // If you hit return in the main input field, create new **Todo** model, // persisting it to *localStorage*. createOnEnter: function(e) { if (e.keyCode != 13) return; if (!this.input.val()) return; Todos.create({title: this.input.val()}); this.input.val(''); }, // Clear all done todo items, destroying their models. clearCompleted: function() { _.invoke(Todos.done(), 'destroy'); return false; }, toggleAllComplete: function () { var done = this.allCheckbox.checked; Todos.each(function (todo) { todo.save({'done': done}); }); } }); // Finally, we kick things off by creating the **App**. var App = new AppView; });
http://codedocker.com/backbone-events-introduce/
model to view
var View = Backbone.View.extend({ initialize:function(){ this.listenTo(this.model,'change:name',this.onNameChange); }, onNameChange:function(){ this.$('.name').text(this.model.get('name')); } template: '<span class="name"></span>' }); var m = new Backbone.Model({name:'Jack'}); var v = new View({model:m}); m.set('name','John');
view to model
var View = Backbone.View.extend({ initialize:function(){ this.listenTo(this.model,'change:name',this.onNameChange); }, onNameChange:function(){ this.$('.name').text(this.model.get('name')); } template: '<input type="text" class="name-input"><span class="name"></span>', events: {'input .name-input': '_changeName'}, _changeName: function(e){ var value = e.currentTarget.value; this.model.set('name', value); return false; } }); var m = new Backbone.Model({name:'Jack'}); var v = new View({model:m}); m.set('name','John');