`

仅用100行代码实现的JavaScript MVC样式框架

mvc 
阅读更多
 http://developer.51cto.com/art/201502/465396_1.htm

使用过 JavaScript框架(如 AngularJS, Backbone 或者Ember)的人都很熟悉在UI(用户界面,前端)中mvc的工作机理。这些框架实现了MVC,使得在一个单页面中实现根据需要变化视图时更加轻松,而模型-视图-控制器(mvc)的核心概念就是:处理传入请求的控制器、显示信息的视图、表示业务规则和数据访问的模型。

AD:

 

Download JavaScript-Mvc.zip - 4.6 KB

介绍

使用过 JavaScript框架(如 AngularJS, Backbone 或者Ember)的人都很熟悉在UI(用户界面,前端)中mvc的工作机理。这些框架实现了MVC,使得在一个单页面中实现根据需要变化视图时更加轻松,而模型-视图-控制器(mvc)的核心概念就是:处理传入请求的控制器、显示信息的视图、表示业务规则和数据访问的模型。

因此,当需要创建这样一个需要在单个页面中实现切换出不同内容的应用时,我们通常选择使用上述框架之一。但是,如果我们仅仅需要一个在一个url中实现视图切换的框架,而不需要额外捆绑的功能的话,就不必使用象Angular和Ember等复杂的框架。本文就是尝试使用简单、有效方法来解决同样的问题。

 

概念

应用中的代码利用urls中的“#”实现MVC模式的导航。应用以一个缺省的url开始,基于哈希值的代码加载应用视图并且将对象-模型应用于视图模板。

url格式像下面这样:

http://Domain Name/index.html#/Route Name

视图内容必须以{{Property-Name}}的方式绑定对象模型的值和属性。代码会查找这个专门的模板格式并且代替对象模型中的属性值。

以ajax的方式异步加载的视图会被放置于页面的占位符中。视图占位符可以是任何的元素(理想的情况是div),但是它必须有一个专门的属性,代码根据这个专门的属性来定位它,这样同样有助于代码的实现。当url改变时,会重复这个场景,另外一个视图被加载。听起来很简单吧!下面的流程图解释了在这个特定的实现中的消息跳转。

写代码

我们以基本的模块设计模式开始,并且最终用门面设计模式的方式将我们的libs曝光于全局范围内。

 
  1. ; (function (w, d, undefined) { //rest of the code })(window, document); 

 

我们需要将视图元素存储到一个变量中,这样就可以多次使用。

 
  1. var _viewElement = null//element that will be used to render the view 

 

我们需要一个缺省的路由来应对url中没有路由信息的情况,这样就缺省的视图就可以被加载而不是展示空白页面。

 
  1. var _defaultRoute = null

 

现在我们来创建我们的主要MVC对象的构造方法。我们会把路由信息存储在“_routeMap”

 
  1. var jsMvc = function () {  
  2.     //mapping object for the routes  
  3.     this._routeMap = {};  

 

是时候创建路由对象了,我们会将路由、模板、控制器的信息存储在这个对象中。

 
  1. var routeObj = function (c, r, t) {  
  2.     this.controller = c;  
  3.     this.route = r;  
  4.     this.template = t;  

 

每一个url会有一个专门的路由对象routeObj.所有的这些对象都会被添加到_routeMap对象中,这样我们后续就可以通过key-value的方式获取它们。

为了添加路由信息到MVC libs中,我们需要曝光libs中的一个方法。所以让我们创建一个方法,这个方法可以被各自的控制器用来添加新路由。

 
  1. jsMvc.prototype.AddRoute = function (controller, route, template) {  
  2.     this._routeMap[route] = new routeObj(controller, route, template);  

 

方法AddRoute接收3个参数:控制器,路由和模板( contoller, route and template)。他们分别是:

controller:控制器的作用就是访问特定的路线。

route:路由的路线。这个就是url中#后面的部分。

template:这是外部的html文件,它作为这个路由的视图被加载。现在我们的libs需要一个切入点来解析url,并且为相关联的html模板页面提供服务。为了完成这个,我们需要一个方法。

Initialize方法做如下的事情:

1)获取视图相关的元素的初始化。代码需要一个具有view属性的元素,这样可以被用来在HTML页面中查找:

2)设置缺省的路由

3)验证视图元素是否合理

4)绑定窗口哈希变更事件,当url不同哈希值发生变更时视图可以被及时更新

5)最后,启动mvc

 
  1. //Initialize the Mvc manager object to start functioning  
  2. jsMvc.prototype.Initialize = function () {  
  3.     var startMvcDelegate = startMvc.bind(this);  
  4.    
  5.     //get the html element that will be used to render the view    
  6.     _viewElement = d.querySelector('[view]');          
  7.     if (!_viewElement) return//do nothing if view element is not found      
  8.    
  9.     //Set the default route  
  10.     _defaultRoute = this._routeMap[Object.getOwnPropertyNames(this._routeMap)[0]];      
  11.    
  12.     //start the Mvc manager  
  13.     w.onhashchange = startMvcDelegate;  
  14.     startMvcDelegate();  

 

在上面的代码中,我们从startMvc 方法中创建了一个代理方法startMvcDelegate 。当哈希值变化时,这个代理都会被调用。下面就是当哈希值变化时我们做的操作的先后顺序:

1)获取哈希值

2)从哈希中获取路由值

3)从路由map对象_routeMap中获取路由对象routeObj 

4)如果url中没有路由信息,需要获取缺省的路由对象

5)最后,调用跟这个路由有关的控制器并且为这个视图元素的视图提供服务

上面的所有步骤都被下面的startMvc方法所实现

 
  1. //function to start the mvc support  
  2. function startMvc() {  
  3.     var pageHash = w.location.hash.replace('#', ''),  
  4.         routeName = null,  
  5.         routeObj = null;                  
  6.            
  7.     routeName = pageHash.replace('/', ''); //get the name of the route from the hash          
  8.     routeObj = this._routeMap[routeName]; //get the route object      
  9.    
  10.     //Set to default route object if no route found  
  11.     if (!routeObj)  
  12.         routeObj = _defaultRoute;  
  13.        
  14.     loadTemplate(routeObj, _viewElement, pageHash); //fetch and set the view of the route  

 

下一步,我们需要使用XML HTTP请求异步加载合适的视图。为此,我们会传递路由对象的值和视图元素给方法loadTemplate。

 
  1. //Function to load external html data  
  2. function loadTemplate(routeObject, view) {  
  3.     var xmlhttp;  
  4.     if (window.XMLHttpRequest) {  
  5.         // code for IE7+, Firefox, Chrome, Opera, Safari  
  6.         xmlhttp = new XMLHttpRequest();  
  7.     }  
  8.     else {  
  9.         // code for IE6, IE5  
  10.         xmlhttp = new ActiveXObject('Microsoft.XMLHTTP');  
  11.     }  
  12.     xmlhttp.onreadystatechange = function () {  
  13.         if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {  
  14.             loadView(routeObject, view, xmlhttp.responseText);  
  15.         }  
  16.     }  
  17.     xmlhttp.open('GET', routeObject.template, true);  
  18.     xmlhttp.send();  

 

当前只剩加载视图和将对象模型与视图模板绑定了。我们会创建一个空的模型对象,然后传递与方法相关的模型来唤醒路由控制器。更新后的模型对象会与先前已经加载的XHR调用中的HTML模板绑定。

loadView 方法被用于调用控制器方法,以及准备模型对象。

replaceToken方法被用于与HTML模板一起绑定模型

  1. //Function to load the view with the template  
  2. function loadView(routeObject, viewElement, viewHtml) {  
  3.     var model = {};   
  4.    
  5.     //get the resultant model from the controller of the current route    
  6.     routeObject.controller(model);   
  7.    
  8.     //bind the model with the view      
  9.     viewHtml = replaceToken(viewHtml, model);   
  10.        
  11.     //load the view into the view element  
  12.     viewElement.innerHTML = viewHtml;   
  13. }  
  14.    
  15. function replaceToken(viewHtml, model) {  
  16.     var modelProps = Object.getOwnPropertyNames(model),  
  17.            
  18.     modelProps.forEach(function (element, index, array) {  
  19.         viewHtml = viewHtml.replace('{{' + element + '}}', model[element]);  
  20.     });  
  21.     return viewHtml;  

最后,我们将插件曝光于js全局范围外

 
  1. //attach the mvc object to the window  
  2. w['jsMvc'] = new jsMvc(); 

 

现在,是时候在我们单页应用中使用这个MVC插件。在下一个代码段中,下面这些会实现:

1)在web页面中引入这个代码

2)用控制器添加路由信息和视图模板信息

3)创建控制器功能

4)最后,初始化lib。

除了上面我们需要的链接让我们导航到不同的路径外,一个容器元素的视图属性包含着视图模板html。

  1. <!DOCTYPE html> 
  2. <html> 
  3. <head> 
  4.     <title>JavaScript Mvc</title> 
  5.     <script src="jsMvc.js"></script> 
  6.     <!--[if lt IE 9]> <script src="jsMvc-ie8.js"></script> <![endif]--> 
  7.        
  8.     <style type="text/css"> 
  9.         .NavLinkContainer {  
  10.             padding: 5px;  
  11.             background-color: lightyellow;  
  12.         }  
  13.    
  14.         .NavLink {  
  15.             background-color:black;  
  16.             color: white;  
  17.             font-weight:800;  
  18.             text-decoration:none;  
  19.             padding:5px;  
  20.             border-radius:4px;  
  21.         }  
  22.             .NavLink:hover {  
  23.                 background-color:gray;  
  24.             }  
  25.     </style> 
  26. </head> 
  27. <body> 
  28.     <h3>Navigation Links</h3> 
  29.     <div class="NavLinkContainer"> 
  30.         <a class="NavLink" href="index.html#/home">Home</a>   
  31.       
  32.         <a class="NavLink" href="index.html#/contact">Contact</a>   
  33.    
  34.         <a class="NavLink" href="index.html#/admin">Admin</a>   
  35.           
  36.     </div> 
  37.     <br /> 
  38.     <br /> 
  39.     <h3>View</h3> 
  40.     <div view></div> 
  41.     <script> 
  42.         jsMvc.AddRoute(HomeController, &apos;home&apos;, &apos;Views/home.html&apos;);  
  43.         jsMvc.AddRoute(ContactController, &apos;contact&apos;, &apos;Views/contact.html&apos;);  
  44.         jsMvc.AddRoute(AdminController, &apos;admin&apos;, &apos;Views/admin.html&apos;);  
  45.         jsMvc.Initialize();  
  46.    
  47.         function HomeController(model) {  
  48.             model.Message = &apos;Hello World&apos;;  
  49.         }  
  50.    
  51.         function ContactController(model) {  
  52.             model.FirstName = "John";  
  53.             model.LastName = "Doe";  
  54.             model.Phone = &apos;555-123456&apos;;  
  55.         }  
  56.    
  57.         function AdminController(model) {  
  58.             model.UserName = "John";  
  59.             model.Password = "MyPassword";  
  60.         }  
  61.     </script> 
  62. </body> 
  63. </html> 

上面的代码有一段包含一个为IE的条件注释。

  1. <!--[if lt IE 9]> <script src="jsMvc-ie8.js"></script> <![endif]--> 

如果IE的版本低于9,那么function.bind,Object.getOwnPropertyNames和Array.forEach属性将不会被支持。因此我们要通过判断浏览器是否低于IE9来反馈代码是否支持。

其中的内容有home.html, contact.html 和 admin.html 请看下面:

home.html:

  1. {{Message}} 

contact.html:

  1. {{FirstName}} {{LastName}}  
  2. <br /> 
  3. {{Phone}} 

admin.html:

  1. <div style="padding:2px;margin:2px;text-align:left;"> 
  2.     <label for="txtUserName">User Name</label> 
  3.     <input type="text" id="txtUserName" value="{{UserName}}" /> 
  4. </div> 
  5. <div style="padding:2px;margin:2px;text-align:left;"> 
  6.     <label for="txtPassword">Password</label> 
  7.     <input type="password" id="txtPassword" value="{{Password}}" /> 
  8. </div> 

完整的代码可以从给定的下载链接中得到。

 

如何运行代码

运行该代码比较简单,需要在你喜欢的Web服务器上创建一个Web应用,下面以IIS为例来说明。

首先在默认站点中新增一个Web应用.

然后设置必填信息:别名,物理路径,应用池,用户认证信息,点击OK。

最后定位到Web应用的内容目录,浏览你想打开的HTML页面即可。

跑在服务器里是必要的,因为代码加载从存储于外部文件中的视图,浏览器不会允许我们的代码在非宿主服务器环境下执行。当然如果你使用Visual Studio那么直接在目标html文件上右键,选择‘View In Browser’即可。

浏览器支持

大部分的现代浏览器都支持本代码。针对IE8及以下的浏览器,有一份单独的代码来支持,但很不幸,这份代码远多于100行。因此这代码不是百分百跨浏览器兼容的,所以当你决定在项目中使用时需要对代码进行微调。

兴趣点

This example demonstrates这个示例向我们展示了对于非常明确地需求来说,真没必要全部使用js库和框架来实现。Web应用是资源密集型的,最好只使用必要的代码而丢掉其他多余部分。

目前的代码能做的就这些了。没有诸如Web服务调用,动态事件绑定功能的。很快我会提供支持更多特性的升级版本。

英文:JavaScript MVC Style Framework in Less Than 100 Lines of Code

分享到:
评论

相关推荐

    100 行代码实现的 JavaScript MVC 样式框架

    在这种模式下,JavaScript 负责处理用户交互、数据处理以及与服务器的通信,而"100行代码实现的JavaScript MVC样式框架"则是在这个概念上创建的一个轻量级解决方案。 首先,让我们理解MVC(Model-View-Controller)...

    少于100行代码JavaScript MVC样式框架

    **JavaScript MVC样式框架详解** 在Web开发领域,MVC(Model-View-Controller)模式是一种广泛应用的设计模式,它有助于组织代码结构,实现数据、视图和业务逻辑的分离。本篇将深入探讨如何使用不到100行的...

    超级简单实现JavaScript MVC 样式框架

    在文章中描述的简易JavaScript MVC框架中,利用了URL中的"#"来实现MVC模式的导航。这种哈希路由机制允许在不重新加载页面的情况下,通过改变URL中的哈希值来请求不同的内容。当URL的哈希值改变时,框架会加载相应的...

    coreMVC框架源代码

    总的来说,`coreMVC`框架提供了基础的MVC结构,便于组织和管理代码,同时也允许开发者进行高度定制,以适应各种项目需求。通过深入理解并熟练运用`coreMVC`,开发者能够构建出高效、可维护的Web应用程序。

    100行代码实现的JavaScriptMVC样式框架

    使用过JavaScript框架(如AngularJS,Backbone或者Ember)的人都很熟悉在UI(用户界面,前端)中mvc的工作机理。这些框架实现了MVC,使得在一个单页面中实现根据需要变化视图时更加轻松,而模型-视图-控制器(mvc)的...

    MVC框架实现简单的管理系统.rar

    总结来说,"MVC框架实现简单的管理系统"项目通过整合MVC设计模式、ASP.NET Web开发框架、SQL Server数据库以及前端技术,实现了一个功能完善的超市管理系统。这个系统不仅展示了如何在实际项目中应用这些技术,还...

    MVC的javascript的WEB富应用开发源代码

    描述部分同样重申了这一主题,暗示我们将会看到的是一个用JavaScript实现MVC设计模式的实际开发案例。这意味着源代码将包含模型层、视图层和控制器层的代码,用于组织和管理Web应用程序的逻辑。 **JavaScript MVC...

    ASP.NET MVC+EF框架+EasyUI实现权限管理系列(24)之前的代码

    10. **Scripts** and **Stylesheets** - EasyUI的JavaScript和CSS文件,用于实现前端界面的样式和功能。 通过这一系列教程,你将学习如何结合这些技术来创建一个完整的权限管理系统,包括用户注册、登录、角色管理...

    Asp.net MVC快速开发框架源码 mvc+Bootstrap

    Asp.Net MVC是一种基于Microsoft .NET Framework的开源应用程序框架,用于构建动态、数据驱动的Web应用程序。它结合了ASP.NET的便利性和Model-View-Controller(MVC)的设计模式,提供了一个灵活、测试友好且可控制...

    net开发框架(mvc)

    .NET开发框架,特别是MVC(Model-View-Controller)模式,是Microsoft提供的一种用于构建高效、可维护的Web应用程序的强大工具。MVC架构允许开发者将应用程序的业务逻辑、用户界面和数据访问分离开来,提高了代码的...

    AdminLTE框架代码实现折叠左侧边栏

    总之,AdminLTE框架通过前端技术实现了左侧边栏的灵活控制,提供了对MVC开发模式的良好支持,并且允许开发者通过简单的代码修改来满足界面展示和功能实现的需求。开发者在实际使用中可以根据项目具体情况进行适当的...

    最简单的MVC框架源码

    MVC(Model-View-Controller)框架是软件开发中一种常用的设计模式,主要应用于Web应用程序,目的是将业务逻辑、数据处理和用户界面分离,使代码更易于维护和扩展。Discuz! 是一个知名的PHP社区论坛系统,它也采用了...

    新MVC框架(带菜单权限)

    在.NET MVC5框架下,该系统利用Model-View-Controller的设计模式,将业务逻辑、数据处理和用户界面分离开来,从而提高代码的可维护性和可扩展性。Model层负责处理业务逻辑和数据模型,View层呈现用户界面,而...

    PHPmvc框架项目

    在PHP中,视图通常是一系列PHP文件,其中包含HTML、CSS和JavaScript代码,用于渲染页面布局和样式。 3. **控制器(Controller)**:控制器是模型和视图之间的桥梁,接收用户请求,调用模型进行数据处理,然后更新或...

    asp.net mvc+Bootstrap Fileinput框架实现的文件上传

    以上是关于"asp.net mvc+Bootstrap Fileinput框架实现的文件上传"的相关知识点,这个示例提供了在ASP.NET MVC环境中集成Bootstrap Fileinput进行文件上传的完整流程,对于开发者来说具有很好的参考价值。通过学习和...

    mvc5ef高端后台快速开发框架

    该框架旨在帮助开发者快速搭建具备高端特性的后台应用,通过集成MVC和EF,实现了数据访问层与业务逻辑层的良好分离。 **描述详解:** 描述中提到,这个框架的后台使用了MVC(Model-View-Controller)架构,这是一...

    自己写的PHP MVC框架,轻量框架,含bootstrap组件

    通过学习和理解框架的结构,可以了解MVC模式如何工作,以及如何有效地组织代码。同时,通过实践使用数据库操作类和Bootstrap,可以提升对前端开发和后端交互的理解。 **6. 开发和调试** 这个轻量级框架可能没有大型...

Global site tag (gtag.js) - Google Analytics