利用前端MVC框架AngularJS实践设计模式
Posted 天码营
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了利用前端MVC框架AngularJS实践设计模式相关的知识,希望对你有一定的参考价值。
「内容简介」AngularJS是一个用来构建大型应用,高性能的Web应用程序的框架,在AngularJS应用中也有设计模式的身影。
AngularJS是什么
AngularJS是一个开源Web应用程序框架。最初是由MISKO Hevery和Adam Abrons于2009年开发,现在是由谷歌维护。
特性
AngularJS是一个功能强大的基于javascript开发框架用于创建富互联网应用(RIA)。
AngularJS为开发者提供的选项(使用JavaScript)在一个干净的MVC(模型-视图-控制器)的方式来编写客户端应用程序。
AngularJS写的应用都是跨浏览器兼容。AngularJS使用JavaScript代码自动处理适应每种浏览器。
AngularJS是开源的,完全免费的,并且由数千名世界各地的开发者开发维护。它是根据Apache许可证2.0版许可发布。
总体来说,AngularJS是一个用来构建大型应用,高性能的Web应用程序的框架,同时使它们易于维护。
核心特征
数据绑定: 模型和视图组件之间的数据自动同步。
适用范围: 这些对象参考模型。它们充当控制器和视图之间的胶水。
控制器: 这些Javascript函数绑定到特定的范围。
服务: AngularJS配有多个内置服务,例如
$http
可作为一个XMLHttpRequest
请求。这些单一对象在应用程序只实例化一次。过滤器: 从一个数组的条目中选择一个子集,并返回一个新的数组。
指令: 指令是关于DOM元素标记(如元素,属性,CSS等等)。这些可以被用来创建作为新的,自定义部件的自定义html标签。AngularJS设有内置指令(如:
ngBind
,ngModel
...)模板:这些符合从控制器和模型信息的呈现的视图。这些可以是单个文件(如
index.html
),或使用“谐音”在一个页面多个视图。路由: 它是切换视图的概念。
模型视图: MVC是一个设计模式将应用划分为不同的部分(称为模型,视图和控制器),每个都有不同的职责。
深层链接: 深层链接,可以使应用程序状态进行编码在URL中而能够添加到书签。应用程序可从URL恢复到相同的状态。
依赖注入: AngularJS有一个内置的依赖注入子系统,开发人员通过使应用程序从而更易于开发,理解和测试。
AngularJS的简单实例
AngularJs程序分为3部分:模板,表现层逻辑,数据。
模板:我们用html,css写的ui视图代码,其中包含AngularJs的指令,表达式,并最终会被AngularJs编译机制编译为附加在dom树上。AngularJs的指令(
directive
)可以由我们自由扩展。表现层逻辑:包括应用程序逻辑和行为。用JavaScript定义作为视图控制器逻辑。在AngularJs作为MVC框架,在控制器中我们无需添加对于dom级的事件监听,这些在AngularJs中已经内置了。在ui节点dom事件发生后AngularJs会自动转到
scope
上的某个行为(Action
)逻辑。数据:视图对象(
viewobject
)需要被AngularJs Scope(1.0中作为service
出现)引用,可以使任何类型的JavaScript对象,数组,基本类型,对象。并且AngularJs会自动异步更新模型,即在ui发生改变的时他会自动刷新模型(mode
),反之在模型发生改变的时候也会自动刷新ui。在这里我们不需要定义形如getter
,setter
的一些列方法。
这里我们可以看一个简单的例子:
sample.html
:
<html> <head> <script ></script> <script ></script> </head> <body> <div ng-app="myApp" ng-controller="myCtrl"> <input ng-model="inputValue" /> <div>输入的内容:{{inputValue}}</div> <div> <script> angular.module('myApp', []) .controller('myCtrl', ['$scope', function($scope) { $scope.inputValue = 'hello world'; }]); </script> </body> </html>
在浏览器中打开的显示为:
当用户改变输入框内内容时,下面的内容也会相应的进行改变。
下面我们来分析这个程序:
AngularJS应用主要依赖于控制器来控制数据流在应用程序中.控制器使用ng-controller
指令定义。控制器是一个包含属性/属性和函数的JavaScript对象。每个控制器接受$scope
作为参数引用到应用程序/模块,由控制器来控制。
<div ng-app="myApp" ng-controller="myCtrl"> ... </div>
在这里,我们采用ng-controller
指令声明控制器myCtrl
。作为下一个步骤,我们将定义myCtrl
如下:
<script> angular.module('myApp', []) .controller('myCtrl', ['$scope', function($scope) { $scope.inputValue = 'hahaha'; }]); </script>
myCtrl
定义一个以$scope
作为参数的JavaScript对象。
$scope
表示应用程序,它使用myCtrl
对象。
$scope.inputValue
是myCtrl
对象的属性。
现在,我们可以在myCtrl使用ng-model
或表达式来获取$scope.inputValue
。
<input ng-model="inputValue" />
绑定$scope.inputValue
到输入框。
<div>输入的内容:{{inputValue}}</div>
绑定$scope.inputValue
到html。
现在,只要在输入框中输入任何字段,可以看到html自动更新。
在这之上AngularJs还为我们提供了一些列的有用的service,并允许我们添加自己特定业务的服务service,提供了底层的ajax,缓存,URL 路由,浏览器抽象等服务,以及这些服务我们可以采用AngularJs的注入机制任意组合。以此为基础我们可以利用AngularJs在前端进行各种设计模式的实践。
AngularJs下各种设计模式的实践
单例模式(singleton)
单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。
比如AngularJs对于组件依赖问题的解决方案:
获取依赖名称,并在缓存的hash表中查找:若该依赖存在,则直接将其作为参数传给需要该依赖的组件;否则AngularJs通过调用工厂(factory
)方法对其进行实例化。(需要注意在实例化该依赖时,有可能该依赖会有额外的依赖而产生了递归调用。)将该依赖存储到缓存的hash表中,再将其作为参数传给需要该依赖的组件。
下面是该方法GetService
的一个实现:
function getService(serviceName) { if (cache.hasOwnProperty(serviceName)) { if (cache[serviceName] === INSTANTIATING) { throw $injectorMinErr('cdep', 'Circular dependency found: {0}', path.join(' <- ')); } return cache[serviceName]; } else { try { path.unshift(serviceName); cache[serviceName] = INSTANTIATING; return cache[serviceName] = factory(serviceName); } catch (err) { if (cache[serviceName] === INSTANTIATING) { delete cache[serviceName]; } throw err; } finally { path.shift(); } } }
在这个例子中AngularJS就将每一个服务(Service
)就看做一个单例,同时我们将缓存(cache
)看作一个单例管理器。
工厂模式(Factory Method)
工厂模式是我们最常用的实例化对象模式了,是用工厂方法代替new操作的一种模式。
我们先来看一个代码片段:
myModule.config(function ($provide) { $provide.provider('foo', function () { var baz = 42; return { //Factory method $get: function (bar) { var baz = bar.baz(); return { baz: baz }; } }; }); });
在上面的代码中我们使用config
去回调定义一个新的供应商(provider
)。供应商(Provider
)是一个对象(Object
),他包含有一个$get
方法。
在AngularJs中,任意一个service
,filter
,directive
和controller
都包含有一个provider
用来实例化这个组件。
装饰模式(Decorator)
装饰模式是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。
AngularJS提供一种名为'out of the box'的方法去扩展一个已经存在的服务(service
)。利用$provide.decorator
方法就可以对任何一个你曾经定义的service
进行扩展或修改:
myModule.controller('MainCtrl', function (foo) { foo.bar(); }); myModule.factory('foo', function () { return { bar: function () { console.log('I\'m bar'); }, baz: function () { console.log('I\'m baz'); } }; }); myModule.config(function ($provide) { $provide.decorator('foo', function ($delegate) { var barBackup = $delegate.bar; $delegate.bar = function () { console.log('Decorated'); barBackup.apply($delegate, arguments); }; return $delegate; }); });
在这个例子中定义了一个新的服务foo
。在config
的回调中使用了$provide.decorator
,并且将foo
作为参数传递。在函数内部$delegate
作为foo
本身的一个引用,同时我们重新定义了其bar
方法。从而在foo
的基础上产生了一个新的服务。
外观模式(Facade)
外观模式为子系统中的一组接口提供一个一致的界面,定义一个高层接口,这个接口使得这一子系统更加容易使用。
在AngularJS中很多地方都用到了外观模式。每当你想要产生一个更高等级的Api时,你就会使用外观模式。
举个例子,让我们看看怎么创建一个XMLHttpRequest
的post
请求:
var http = new XMLHttpRequest(), url = '/example/new', params = encodeURIComponent(data); http.open("POST", url, true); http.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); http.setRequestHeader("Content-length", params.length); http.setRequestHeader("Connection", "close"); http.onreadystatechange = function () { if(http.readyState == 4 && http.status == 200) { alert(http.responseText); } } http.send(params);
当我们想要使用AngularJs的$http
时,我们这样写:
$http({ method: 'POST', url: '/example/new', data: data }) .then(function (response) { alert(response); });
或者
$http.post('/someUrl', data) .then(function (response) { alert(response); });
代理模式(Proxy)
代理模式分为三个种类:
抽象角色:通过接口或抽象类声明真实角色实现的业务方法。代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。
这里我们讲的例子是AngularJS中的抽象代理。
下面这个片段,我们使用User
来表示$resource
并调用其中的get
方法:
var User = $resource('/users/:id'), user = User.get({ id: 42 }); console.log(user); //{}
在这段代码中,console.log
将会输出一个空的对象。当User.get被调用时,由于Ajax请求是异步运行在后台的,所以还没有一个实际的用户就执行了console.log
。因此我们需要一个User.get的代理,当实际的响应到达时,能够正确的将其填充到我们的页面中。
在AngularJS当中,我们这样来实现:
function MainCtrl($scope, $resource) { var User = $resource('/users/:id'), $scope.user = User.get({ id: 42 }); }
<span ng-bind="user.name"></span>
了解更多Java Web开发内容:
点击下方“阅读原文”,可以获得更多天码营教程。
以上是关于利用前端MVC框架AngularJS实践设计模式的主要内容,如果未能解决你的问题,请参考以下文章