首页 > 网站 > WEB开发 > 正文

【单页应用】理解MVC

2024-04-27 14:23:40
字体:
来源:转载
供稿:网友

【单页应用】理解MVC

前言

之前我们为view引入了wrapperSet的概念,想以此解决view局部刷新问题,后来发现这个方案不太合理view里面插入了业务相关的代码,事实上这个是应该剥离出去,业务的需求千奇百怪,我们不应该去处理view现在只提供最基础的功能:① 定义各个状态的模板② 渲染模板整个view的逻辑便该结束了,有一个比较特殊的情况是,当状态值不变的情况就应该是更新,这个可能会有不一样的逻辑也应该划出去Adapter的意义在于存储view渲染过程中需要的data数据,从组成上分为① datamodel② viewmodeldatamodel用于具体操作,viewmodel被干掉了,提供一个getViewModel的方法替换,并且对外提供一个format方法用于用户继承format的参数便是datamodel,这里通过处理返回的数据便是我们所谓的viewModel,他将会用于view生成对应html然后datamodel的改变会引起对应view的变化,这个变化发起端与控制端皆在viewController,最后viewController会通知到view重新渲染Controller依旧是交互的核心,他是连接Adapter以及view的桥梁view与Adapter本身并没有关联,Controller将之联系到了一起:① 在实例化时候便会关联一个Adapter以及view的实例,这里Adapter不是必须的② viewController会保留一个view的根节点,view的根节点只会存在一个③ viewController会在Adapter实例上监听自身,在adpter datamodel发生变化时候通知到自己,便会触发update事件④ 传入初始状态的status以及Adapter的datamodel,调用view的render方法,会生成当前状态的view的html⑤ 将之装入view的根节点,并且为viewController的this.$el赋值,create的逻辑结束⑥ 触发viewController show事件,将events绑定到根节点,将$el append到container容器中并显示,初步逻辑结束⑦ viewController有几个事件点用于用户注册,本身也具有很多一系列dom事件,可能导致datamodel的变化⑧ 若是Adapter的datamodel发生变化便会触发dataAdpter改变的notify事件,这个时候viewController便会有所反应⑨ datamodel的改变会触发viewController的update事件,默认会再次触发render事件重新新渲染结构由于render会放给view自定义,所以其中需要执行的逻辑便不需要我们的关注了

实例

这个便是一个标准的MVC模型,借IOS MVC的模型来说核心操控点在于Controller,Controller会组织model以及view由于Controller上注册的各系列事件,会引起model的变化,每次model产生变化后会重新通知,Controller 通知view update操作这个时候view会获取viewController的状态值以及model的数据渲染出新的viewview只负责html渲染model只负责操作数据,并且通知观察者改变事件Controller将view以及model联系起来,所有的事件全部注册至ControllerPS:传统的View会包含事件交互,这里放到了Controller上模型会把datamodel的改变通知到控制器,控制器会更新视图信息,控制器根据view组成dom结构,并且注册各种UI事件,又会触发datamodel的各种改变这就达到了理想情况的view与model的分离,一个model(adpter可用于多个viewController),一个dataAdpter的改变会影响两个视图的改变这个MVC可以完全解耦view以及model,view的变化相当频繁,若是model控制view渲染便会降低model的重用这里首先举一个例子做简单说明:
  1 <!doctype html>  2 <html lang="en">  3 <head>  4   <meta charset="UTF-8">  5   <title>ToDoList</title>  6   <meta name="viewport" content="width=device-width, initial-scale=1.0">  7   <link rel="stylesheet" type="text/CSS" href="http://designmodo.github.io/Flat-UI/bootstrap/css/bootstrap.css">  8   <link rel="stylesheet" type="text/css" href="http://designmodo.github.io/Flat-UI/css/flat-ui.css">  9   <link href="../style/main.css" rel="stylesheet" type="text/css" /> 10   <style type="text/css"> 11     .cui-alert { width: auto; position: static; } 12     .txt { border: #cfcfcf 1px solid; margin: 10px 0; width: 80%; } 13     ul, li { padding: 0; margin: 0; } 14     .cui_calendar, .cui_week { list-style: none; } 15     .cui_calendar li, .cui_week li { float: left; width: 14%; overflow: hidden; padding: 4px 0; text-align: center; } 16   </style> 17 </head> 18 <body> 19   <article id="container"> 20   </article> 21   <script type="text/underscore-template" id="template-Ajax-init"> 22       <div class="cui-alert" > 23         <div class="cui-pop-box"> 24           <div class="cui-hd"> 25             <%=title%> 26           </div> 27           <div class="cui-bd"> 28             <div class="cui-error-tips"> 29             </div> 30             <div class="cui-roller-btns" style="padding: 4px; "><input type="text" placeholder="设置最低价 {day: '', PRice: ''}" style="margin: 2px; width: 100%; " id="ajax_data" class="txt" value="{day: , price: }"></div> 31             <div class="cui-roller-btns"> 32               <div class="cui-flexbd cui-btns-sure"><%=confirm%></div> 33             </div> 34           </div> 35         </div> 36       </div> 37   </script> 38   <script type="text/underscore-template" id="template-ajax-suc"> 39     <ul> 40       <li>最低价:本月<%=ajaxData.day %>号,价格:<%=ajaxData.price %> 元</li> 41   </ul> 42   </script> 43  44   <script type="text/underscore-template" id="template-ajax-loading"> 45     <span>loading....</span> 46   </script> 47  48   <script src="../../vendor/underscore-min.js" type="text/javascript"></script> 49   <script src="../../vendor/zepto.min.js" type="text/Javascript"></script> 50   <script src="../../src/underscore-extend.js" type="text/javascript"></script> 51   <script src="../../src/util.js" type="text/javascript"></script> 52   <script src="../../src/mvc.js" type="text/javascript"></script> 53   <script type="text/javascript"> 54  55 //模拟Ajax请求 56 function getAjaxData(callback, data) { 57   setTimeout(function () { 58     if (!data) { 59       data = {day: 3, price: 20}; 60     } 61     callback(data); 62   }, 1000); 63 } 64  65 var AjaxView = _.inherit(Dalmatian.View, { 66   _initialize: function ($super) { 67     //设置默认属性 68     $super(); 69  70     this.templateSet = { 71       init: $('#template-ajax-init').html(), 72       loading: $('#template-ajax-loading').html(), 73       ajaxSuc: $('#template-ajax-suc').html() 74     }; 75  76   } 77 }); 78  79 var AjaxAdapter = _.inherit(Dalmatian.Adapter, { 80   _initialize: function ($super) { 81     $super(); 82     this.datamodel = { 83       title: '标题', 84       confirm: '刷新数据' 85     }; 86     this.datamodel.ajaxData = {}; 87   }, 88  89   format: function (datamodel) { 90     //处理datamodel生成viewModel的逻辑 91     return datamodel; 92   }, 93  94   ajaxLoading: function () { 95     this.notifyDataChanged(); 96   }, 97  98   ajaxSuc: function (data) { 99     this.datamodel.ajaxData = data;100     this.notifyDataChanged();101   }102 });103 104 var AjaxViewController = _.inherit(Dalmatian.ViewController, {105   _initialize: function ($super) {106     $super();107     //设置基本的属性108     this.view = new AjaxView();109     this.adapter = new AjaxAdapter();110     this.viewstatus = 'init';111     this.container = '#container';112   },113 114   //处理datamodel变化引起的dom改变115   render: function (data) {116     //这里用户明确知道自己有没有viewdata117     var viewdata = this.adapter.getViewModel();118     var wrapperSet = {119       loading: '.cui-error-tips',120       ajaxSuc: '.cui-error-tips'121     };122     //view具有唯一包裹器123     var root = this.view.root;124     var selector = wrapperSet[this.viewstatus];125 126     if (selector) {127       root = root.find(selector);128     }129 130     this.view.render(this.viewstatus, this.adapter && this.adapter.getViewModel());131 132     root.html(this.view.html);133 134   },135 136   //显示后Ajax请求数据137   onViewAfterShow: function () {138     this._handleAjax();139   },140 141   _handleAjax: function (data) {142     this.setViewStatus('loading');143     this.adapter.ajaxLoading();144     getAjaxData($.proxy(function (data) {145       this.setViewStatus('ajaxSuc');146       this.adapter.ajaxSuc(data);147     }, this), data);148   },149 150   events: {151     'click .cui-btns-sure': function () {152       var data = this.$el.find('#ajax_data').val();153       data = eval('(' + data + ')');154       this._handleAjax(data);155     }156   }157 });158 159 var a = new AjaxViewController();160 a.show();161 162   </script>163 </body>164 </html>
完成HTML
  1 (function () {  2   var _ = window._;  3   if (ty
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表