最近前端比较火的框架,可数facebook的react了,一个专门针对移动端开发的前端高性能框架。当然google的angularjs也是一个很火的前端框架,在SPA应用上算是非常出色的。具体的基础入门大家可以看看菜鸟网络的http://www.runoob.com/angularjs/angularjs-tutorial.html,这里都是一些基本知识点
下面要说的是,我本人在应用angular中遇到的一些问题和平时用jquery实现的方式的异同。
(1)单页面应用中加载有关angualr的js文件
在进入单页面的初始化时,所有用到的angualr的js需要一次性加载,不能做到按需加载。
比如在路由中,我们设置了很多的不同页面和对应路由,那么进入不同的路由,我们就需要按需加载不同的的angualr的controller的js文件了。如果我们在页面中直接通过<script src="./test.js"></script>加载angular的这个test.js文件时,这个只会通过xhr的异步对象请求方式加载进来的,test.js文件时加载进来了,但是它并没有将view视图中双向绑定那样,把请求返回来的数据通过$scope的作用域绑定显示出来。具体的原因是因为通过xhr异步加载的test.js文件已将是处于angular的上下文之外了,说的简单点,即是处于两个不同的环境域中,所以对于数据绑定也就是model来说,这个过程是跨域的,不会发生的。(AngularJS 上下文之外的任何地方修改了 model ,那么你就需要通过手动调用 $apply() 来通知 AngularJS 。这就像告诉 AngularJS ,你修改了一些 models ,希望 AngularJS 帮你触发 watchers 来做出正确的响应)。当然如果是普通的js文件,这是可以加载并且可以执行的。
那么对于这种情况,我们应该怎么解决呢?因为在单页应用中,当功能越来越多,越来越复杂的时候,我们就需要按需来加载不同路由下的js文件了!下面,我在github上找到一个比较好的开源的解决方案!
官网:https://oclazyload.readme.io/docs/oclazyloadprovider
ui-router的演示:http://plnkr.co/edit/u18KQc?p=preview
那么我们可以npm install oclazyload 安装
var app = angular.module('app', ['ngRoute','oc.lazyLoad']);
app.config(['$routeProvider',
function($routeProvider) {
$routeProvider
.when('/main', {
templateUrl: '/home/index/main',
controller: 'MainCtrl'
})
.when('/dashboard', {
templateUrl: '/home/index/view',
controller: 'DashboardCtrl',
resolve: {
loadMyCtrl:['$ocLazyLoad',function ($ocLazyLoad) {
return $ocLazyLoad.load({
name:"view",
files:["/static/js/angular-gridster/demo/dashboard/script.js"]
});
}]
}
})
.otherwise({
redirectTo: '/main'
});
}
])
其中最重要就是
resolve: {
loadMyCtrl:['$ocLazyLoad',function ($ocLazyLoad) {
return $ocLazyLoad.load({
name:"view",
files:["/static/js/angular-gridster/demo/dashboard/script.js"]
});
}]
}
这个resove 是在执行路由渲染模板前进行一个操作,resove里面的值由key:value组成,key的值可以自定义,基本模式就是这样子,return 回来一个promise.所以按照上面的路由配置就可以方便实现按需动态加载,可以给我们的开发带来更加清晰的过程。
angular本身的ng-router在功能上还是受限,建议如果要用路由的话,可以用开源的angular-ui-router,这个功能强大,而且可以多个层级的路由,模板嵌套等。
安装angular-ui-router 直接用npm install angular-ui-router
(2)angular的$http.post(),传输json数据格式问题
在实际项目中,我们遇到了一个很常见问题,当使用
$http.post(url,{'name':'bing','sex':1}).success(function(response){
});
post一个json数据过去的时候,在服务端php(或者一些其他语言),当我们用$_POST的时候,却没有办法获取到这个json数据。
因为按照我们平时在用jquery的时候
$.post({
url:...,
data:{'name':'bing','sex':1},
.....
});
同样也是这样子,一般是可以成功的将数据post到服务端的,为什么angualr就不可以呢?
在httpd通信的请求中,发送请求时,可以通过content-type指定请求体的发包是以何种格式来实现的!
application/x-www-form-urlencoded是标准的表单发包方式,普通的表单提交,或者js发包,默认都是通过这种方式实现的。也就是说post方法的请求体内容数据最终必须转成application/x-www-form-urlencoded,也就是'name=bing&sex=1',服务端才可以通过$_POST获取到数据。
那么jquery为什么可以呢?
下面看一下jquery的官方说明:
data:将自动转换为请求字符串格式。GET 请求中将附加在 URL 后面。查看 processData 选项说明,以禁止此自动转换。对象必须为"{键:值}"格式。如果这个参数是一个数组,jQuery会按照traditional 参数的值, 将自动转化为一个同名的多值查询字符串(查看下面的说明)。注:如 {foo:["bar1", "bar2"]} 转换为 'foo=bar1&foo=bar2'。
也就是说jquery会自动将json数据格式转为字符串格式后(序列化后),再进行post的传输发包。
而在angualr中,请求post过去的json数据并不会转为name=bing&sex=1这种格式的字符串,而是默认就是json,但由于http通信中并没有所谓的json,所有在传输的时候,也就是,application/json可以将它理解为text/plain,普通字符串。那么不满足发包的格式。自然在服务端$_POST就没法接收数据了。
具体的解决办法:
(1)利用jquery的$.param()方法
var queryData = $.param({'name':'bing','sex':1});
$http({
url : 'test.php',
method : 'POST',
data : queryData,
headers : {'Content-Type':'application/x-www-form-urlencoded'},
}).success(function(response) {
});
其中headers : {'Content-Type':'application/x-www-form-urlencoded'}需要设置。有人说,缺点就是引入jquery,但本人认为在一个应用系统中,大部分都会使用jquery的,angular和jquery相互结合开发,才是强强组合。
而且$.param()处理对象序列化的层数更深层,这个也是非常方便。
(2)利用angular自身封装的$httpParamSerializer()
{'foo': 'bar'}
results infoo=bar
{'foo': Date.now()}
results infoo=2015-04-01T09%3A50%3A49.262Z
(toISOString()
and encoded representation of a Date object){'foo': ['bar', 'baz']}
results infoo=bar&foo=baz
(repeated key for each array element){'foo': {'bar':'baz'}}
results infoo=%7B%22bar%22%3A%22baz%22%7D
(stringified and encoded representation of an object)
https://docs.angularjs.org/api/ng/service/$httpParamSerializerJQLike
一种使用方法
$http({
url: myUrl,
method: 'GET',
params: myParams,
paramSerializer: '$httpParamSerializerJQLike'
});
另一种使用方法
.controller(function($http, $httpParamSerializerJQLike) {
//...
$http({
url: myUrl,
method: 'POST',
data: $httpParamSerializerJQLike(myData),
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
});
});
(3)自己重新定义序列化
var ballApp = angular.module('BallApp', [], function($httpProvider) {
// 修改 header
$httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=utf-8';
// Serialize function
//只能是嵌套两层的对象
var param = function(obj) {
var query = '', name, value, fullSubName, subName, subValue, innerObj,i;
for(name in obj) {
value = obj[name];
//如果值是数组
if(value instanceof Array) {
for(i = 0; i < value.length; ++i) {
subValue = value[i];
fullSubName = name + '[' + i + ']';
innerObj = {};
innerObj[fullSubName] = subValue;
query += param(innerObj) + '&';
}
//如果值是对象
} else if(value instanceof Object) {
for(subName in value) {
subValue = value[subName];
fullSubName = name + '[' + subName + ']';
innerObj = {};
innerObj[fullSubName] = subValue;
query += param(innerObj) + '&';
}
如果值是字符串
} else if(value !== undefined && value !== null) {
query += encodeURIComponent(name) + '=' + encodeURIComponent(value) + '&';
}
}
return query.length ? query.substr(0, query.length - 1) : query;
}
//重写transformRequest参数处理方法(利用param function 处理)
$httpProvider.defaults.transformRequest = [function(data) {
return angular.isObject(data) && String(data) !== '[object File]' ? param(data) : data;
}];
});
ballApp.controller('AjaxCtrl', function($scope, $http) {
$scope.ajax = function() {
$http.post('test.php', {name: 'Febr'})
.success(function(data) {
console.log(data);
});
};
});
如果您觉得本文对你有帮助,那就按按鼠标,顶一下,让更多的人可以看到它......