MVC && MVVM
前端框架前端 MV*框架的意义
被误解的MVC和被神化的MVVM
Vue.js新手入门指南
单页应用SPA的路由
单页面应用的路由问题html
本文是在本身总结时,看了许多篇文章有了些体会,而后把我认为有意义的摘抄下来,文中很大部分摘录以上参考的文章,再结合一点点本身的观点,总的来讲这篇文章是一个汇总文。前端
在前端搞 MV有什么意义?也有人提出这样的疑问:以 AngularJS,Knockout,BackBone 为表明的 MV*框架,它跟 jQuery 这样的框架有什么区别?我 jQuery 用得好好的,有什么必要再引入这种框架?vue
库和框架是有一些区别的:库是一种工具,我提供了,你能够不用,即便你用了,也没影响你自 己的代码结构。框架则是面向一个领域,提供一套解决方案,若是你用我,就得按照个人方式办事。html5
jQuery 的思惟方式是:以 DOM 操做为中心
MV*框架的思惟方式是:以模型为中心,DOM 操做只是附加git
因为前端功能的加强、代码的膨胀,致使不得不作“前端的架构”这个事情了。github
因此回到那个问题上,jQuery 知足了你的业务须要,你还有什么必要引入 MV*框架?
这个是要看产品类型的,若是是页面型产品,多数确实不太须要它,由于页面中的 JavaScript 代码,处理交互的绝对远远超过处理模型的,可是若是是应用软件类产品,这就太须要了。 ajax
MV框架的理念是把前端按照职责分层,每一层都相对比较独立,有本身的价值,也有各自发挥的余地。vuex
这种逻辑的好处在于,业务逻辑与用户界面分离以后,后期对于界面的改版以及对于用户交互的处理变化,仅仅须要改动View层便可,不在须要对业务逻辑层进行多大的改动。后期的维护成本会减小不少。segmentfault
将开发重心从DOM操做,转移到数据操做,将DOM操做与程序逻辑解耦。
指望提高开发效率、单位时间产出、后期代码扩展性,下降维护成本设计模式
MVC
Model 数据模型
View 用户界面
Controller 业务逻辑
不一样的框架对Model、View的数据同步有不一样的处理
MVC开发模式的原则:咱们来看看 MVC 这种架构的特色。其实设计模式不少时候是为了 Don't repeat yourself 原则来作的,该原则要求可以复用的代码要尽可能复用,来保证重用。在 MVC 这种设计模式中,咱们发现 View 和 Model 都是符合这种原则的。在Controller层尽可能写不可以复用的。
开发人员只要考虑和处理Model(数据模型)的变化便可,不用考虑Model和View之间的数据绑定同步,更不用花精力用大量的代码获取DOM元素改变DOM元素的值来完成界面数据的变化。全部工做交给VM(View-Model)来处理。
MVVM并无业务逻辑的控制器,它经过数据双向绑定,实时更新View和Model层,当数据模型发生变化的时候,用户界面(DOM)的内容会即时更新。反之若是用户操做致使某些DOM内容变化(如input),ViewModel也会即时的将Model数据模型更新。
数据双向绑定,开发人员不用再把精力放在DOM的修改和更新,只要经过模板引擎将数据模型和用户界面绑定,框架会实时同步双方数据的变化。减轻了开发人员的负担,也减小了DOM操做逻辑致使业务逻辑混乱的可能性。
调用 Backbone.history.start() 开始监控 hashchange 事件并分配路由
View:视图
Model:数据
Router:路由,因为Controller层主要负责了路由,而业务逻辑都在View中写了。
backbone事件:订阅发布者模式
Vue.js(读音 /vjuː/, 相似于 view) 是一套构建用户界面的 渐进式框架。与其余重量级框架不一样的是,Vue 采用自底向上增量开发的设计。Vue 的核心库只关注视图层,而且很是容易学习,很是容易与其它库或已有项目整合。另外一方面,Vue 彻底有能力驱动采用单文件组件和 Vue 生态系统支持的库开发的复杂单页应用。
Vue.js 的目标是经过尽量简单的 API 实现响应的数据绑定和组合的视图组件。
Vue.js就是一个用于搭建相似于网页版知乎这种表单项繁多,且内容须要根据用户的操做进行修改的网页版应用。
vue 不支持IE8如下浏览器的缘由?由于 Vue.js 使用了 IE8 不能模拟的 ECMAScript 5 特性
经过js对象。。。。。。。。。
beforeCreate
observe Data / init Events
组件实例被建立,组件属性计算以前
应用:beforeCreate 给个loading加载界面
created
1.组件实例建立完成,属性已经绑定,但DOM还未生成,$el属性还不存在
2.在实例建立以后同步调用。此时实例已经结束解析选项,这意味着已创建:数据绑定,计算属性,方法,watcher/事件回调。
3.可是尚未开始 DOM 编译,$el 还不存在,可是实例存在,即this.a存在,可打印出来 。
应用:created阶段作一些初始化,实现函数自执行,例如:created撤销loading
el / template
beforeMounted
模板编译、挂载以前
replace el
mounted
1.模板编译、挂载以后不保证组件已在document中
2.在编译结束后调用。此时全部的指令已生效,于是数据的变化将触发 DOM 更新。可是不担保 $el 已插入文档。
应用:mounted阶段作ajax,或者配合路由钩子作一些事情;此时DOM已经获取到,能够对DOM进行操做
data changed
beforeUpdated
1.数据更新时调用,发生在虚拟 DOM 从新渲染和打补丁以前。
2.你能够在这个钩子中进一步地更改状态,这不会触发附加的重渲染过程。
3.该钩子在服务器端渲染期间不被调用。
virtual dom re-render / patch
updated
因为数据更改致使的虚拟 DOM 从新渲染和打补丁,在这以后会调用该钩子。当这个钩子被调用时,组件 DOM 已经更新,因此你如今能够执行依赖于 DOM 的操做。
然而在大多数状况下,你应该避免在此期间更改状态,由于这可能会致使更新无限循环。
vm.$destroyed
beforeDestroy
dsetroyed
还好发布检查了一次,发现本身把本身乱七八糟说的都写进来了。
这篇文章我觉还不错,跟着本身写一遍,就会比较了解了。全部才有个人乱七八糟之说。本身理解最重要。
1.实例MVVM对象时,会生成观察者observe去观察实例中的data的每个属性。
2.observe对象会遍历每个key、value。若是value也是对象,也会经过observe来观察其中的key、value。
3.在每一个observe对象中会建立一个订阅者,而后再设置属性的内置get、set函数。
4.经过内置get函数:在里面会给data的属性添加订阅者。
5.经过内置set函数:会将value值更改,而且若是新的value值是object,那么则建立一个observe观察者观察它。最后会通知订阅者。
6.compile主要作的事情是解析模板指令,将模板中的变量替换成数据,而后初始化渲染页面视图,并将每一个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变更,收到通知,更新视图。
7.观察者Watcher是observe与compile的桥梁,在解析vue的自定义指令时,会为每个指令建立一个Watcher观察者对象。watcher会将每一个指令的当前状态设定,并添加到每一个data的订阅者数组中,当data的数值发生改变时,会通知其绑定的订阅者,触发每个订阅者更新函数。
第一点:数据绑定使得 Bug 很难被调试。你看到界面异常了,有多是你 View 的代码有 Bug,也多是 Model 的代码有问题。数据绑定使得一个位置的 Bug 被快速传递到别的位置,要定位原始出问题的地方就变得不那么容易了。
第二点:对于过大的项目,数据绑定须要花费更多的内存。
咱们能够将同一函数定义为一个 method 而不是一个计算属性。对于最终的结果,两种方式确实是相同的。然而,不一样的是计算属性是基于它们的依赖进行缓存的。计算属性只有在它的相关依赖发生改变时才会从新求值。这就意味着只要 message 尚未发生改变,屡次访问 reversedMessage 计算属性会当即返回以前的计算结果,而没必要再次执行函数。
仅是观察变量的变化能够不用watch,直接用计算属性
可是,当在数据发生变化时,你但愿执行开销较大的操做时,用watch比较有用。
watch能够限制咱们执行的频率,在最终结果前,能够设置中间状态。计算属性没法作到。
state:驱动应用的数据源
view:以声明方式将state映射到视图
action:响应在view上的用户输入致使的状态变化。
当咱们的应用遇到多个组件共享状态时,单向数据流的简洁性很容易被破坏:
多个视图依赖于同一状态。
来自不一样视图的行为须要变动同一状态。
对于问题一,传参的方法对于多层嵌套的组件将会很是繁琐,而且对于兄弟组件间的状态传递无能为力。对于问题二,咱们常常会采用父子组件直接引用或者经过事件来变动和同步状态的多份拷贝。以上的这些模式很是脆弱,一般会致使没法维护的代码。
把组件的共享状态抽取出来,以一个全局单例模式管理。
Vuex 是一个专为Vue.js应用程序开发的状态管理模式。它采用集中式存储管理应用的全部组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
因为 Vuex 的状态存储是响应式的,从 store 实例中读取状态最简单的方法就是在计算属性中返回某个状态
State:状态
Getters:从State中派生出来的一些状态
Mutations:更改 Vuex 的 store 中的状态的惟一方法是提交 mutation,不能直接调用,须要触发store.commit(type,[payload])。mutation必须时同步函数。异步函数不能捕捉到改变的状态
Actions:
Action 提交的是 mutation,而不是直接变动状态
Action 能够包含任意异步操做。
Action 函数接受一个与 store 实例具备相同方法和属性的 context 对象。
Action 经过 store.dispatch 方法触发:store.dispatch('increment')
store.dispatch 能够处理被触发的action的回调函数返回的Promise,而且store.dispatch仍旧返回Promise
Modules
因为使用单一状态树,应用的全部状态会集中到一个比较大的对象。当应用变得很是复杂时,store 对象就有可能变得至关臃肿。
为了解决以上问题,Vuex 容许咱们将 store 分割成模块(module)。每一个模块拥有本身的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行一样方式的分割
单页面应用(Single Page Application)简称SPA,使用SPA构建的应用优势有用户体验好、速度快,内容的改变不须要从新加载整个页面,避免了没必要要的跳转和重复渲染,从而相对减轻了服务器压力,SPA在WEB移动端应用很是普遍。
单页应用路由
HTML5在History里增长了pushState方法,这个方法会将当前的url添加到历史记录中,而后修改当前url为新url。固然这个方法只会修改地址栏的Url显示,但并不会发出任何请求。所以咱们能够利用这个方法结合ajax实现单页面应用SPA,就是PushState+Ajax,人称Pjax。
location.hash更改了,页面也不会变化 hashchange hash值的改变也会加入历史记录中
总的来讲,基于Hash的路由,兼容性更好;基于History API的路由,更加直观和正式。可是,有一点很大的区别是,基于Hash的路由不须要对服务器作改动,基于History API的路由须要对服务器作一些改造。
pushstate的使用方法:
history.pushState(state, title, url)
state: 能够听任意你想放的数据,它将附加到新url上,做为该页面信息的一个补充。 该对象可在onpopstate事件中获取,也可在history对象中获取。
title: 顾名思义,就是document.title。
url: 新url,也就是你要显示在地址栏上的url。
history.replaceState(state, title, url)
replaceState方法与pushState大同小异,区别只在于pushState会将当前url添加到历史记录,以后再修改url,而replaceState只是修改url,不添加历史记录。
window.onpopstate
通常来讲,每当url变更时,popstate事件都会被触发。所以,咱们能够把它用做浏览器的前进后退事件。该事件有一个参数,就是上文pushState方法的第一个参数state。
Pjax能作什么
Pjax是一个优秀的解决方案,它能够作:
能够在页面切换间平滑过渡,增长Loading动画。
能够在各个页面间传递数据,不依赖URL。
能够选择性的保留状态,如音乐网站,切换页面时不会中止播放歌曲。
全部的标签均可以用来跳转,不只仅是a标签。
避免了公共JS的反复执行,减小了请求体积,节省流量,加快页面响应速度。
对SEO也不会有影响,对于不支持HTML5的浏览器以及搜索引擎爬虫,则能够跳转真实的页面。
支持浏览器前进和后退按钮。
Pjax ajax请求,经过html5pushState来修改历史记录,若是不支持html5则重写url 每次修改location的属性(hash除外),页面都会以新URL从新加载