angular-按需加载angularjs和$http.post的二三事

来源:互联网 发布:淘宝买iphone8靠谱吗 编辑:程序博客网 时间:2024/06/16 07:00
前面的24个章节都是关于yii2框架的理解以及应用,本来是向按照一个一个章节系列写下去的,每个分类都能够比较集中,清晰。但是在项目中又会用到其他的知识,只能够按照平时积累写下去咯,可能会有些乱!

最近前端比较火的框架,可数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 in foo=bar
  • {'foo': Date.now()} results in foo=2015-04-01T09%3A50%3A49.262Z (toISOString() and encoded representation of a Date object)
  • {'foo': ['bar', 'baz']} results in foo=bar&foo=baz (repeated key for each array element)
  • {'foo': {'bar':'baz'}} results in foo=%7B%22bar%22%3A%22baz%22%7D (stringified and encoded representation of an object)
另外还可以使用$httpParamSerializerJQLike

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);        });    };});


如果您觉得本文对你有帮助,那就按按鼠标,顶一下,让更多的人可以看到它......






6 0
原创粉丝点击