前端遇到的一些坑
原文是这样记录的:
Caching
$http
responses are not cached by default. To enable caching, you must set the config.cache value or the default cache value to TRUE or to a cache object (created with$cacheFactory
). If defined, the value of config.cache takes precedence over the default cache value.In order to:
- cache all responses - set the default cache value to TRUE or to a cache object
- cache a specific response - set config.cache value to TRUE or to a cache object
If caching is enabled, but neither the default cache nor config.cache are set to a cache object, then the default
$cacheFactory("$http")
object is used.The default cache value can be set by updating the
$http.defaults.cache
property or the$httpProvider.defaults.cache
property.When caching is enabled,
$http
stores the response from the server using the relevant cache object. The next time the same request is made, the response is returned from the cache without sending a request to the server.Take note that:
- Only GET and JSONP requests are cached.
- The cache key is the request URL including search parameters; headers are not considered.
- Cached responses are returned asynchronously, in the same way as responses from the server.
- If multiple identical requests are made using the same cache, which is not yet populated, one request will be made to the server and remaining requests will return the same response.
- A cache-control header on the response does not affect if or how responses are cached.
翻译:
缓存
$http响应默认不是缓存的。为了能够缓存,必须设置config.cache的值,或者默认的cache值为TRUE,或者创建缓存对象(由$cacheFactory创建
)。如果定义了,配置的cache值比默认的cache值优先级高。
为了:
- 缓存所有响应 - 设置缓存值为TRUE或者设置缓存对象
- 缓存指定响应 - 设置config.cache的值为TRUE或者设置缓存对象
如果缓存生效,但是既没有设置默认cache,也没有设置config.cache为缓存对象,那么默认的 $cacheFactory("$http")将会使用。
默认的cache值可以通过更新$http.defaults.cache属性或
$httpProvider.defaults.cache属性
来设置
当缓存生效时, $http通过使用相关缓存对象,存储来自服务器的响应。如果下一次执行了同样的请求,响应是来自缓存,而不是发送一个请求至服务端。
注意:
- 只有GET和JSONP请求有缓存
- 缓存的key是请求的URL,包含搜索参数,不包含头部
- 缓存响应是通过异步返回的,与通过服务端响应的方式是一样的。
- 如果执行多个同样的请求,使用同样的缓存,缓存不是一直存在的,一个请求发送到服务端,剩下的请求返回同样的响应。
- 响应头的cache-control不会影响是否换存和如何缓存的
2、记录路由切换时,记录路由的变化
通过angularjs自带的$locationChangeStart
.run(['$rootScope', '$window', '$location', '$log', function ($rootScope, $window, $location, $log) { var locationChangeStartOff = $rootScope.$on('$locationChangeStart', function(event , next, current) { $log.log('locationChangeStart'); $log.log(arguments); }); }])
如果请求的参数放在angular自带的params中,并不能很好滴获取页面的请求参数,所以上面的这种解决方案并不是很有效。
只能另想其法了。
因为页面的请求URL变化,是通过点击来触发的,可以在触发URL状态变化后,记录状态变化的请求URL,并将请求的URL放在sessionStorage中。
比如:
//切换待办已办已建 $scope.changeTable=function(code){ $scope.nowCode=code; $scope.getOrderDate(pNum,pSize,$scope.nowCode,$scope.status,$scope.searchInfo,$scope.whichOrder); //获取当前请求的URL,并保存至sessionStorage中 sessionStorage.setItem('orderUrl', JSON.stringify({ url:$location.absUrl(), pageNum:pNum, pageSize:pSize, code:code, type:$scope.status, keyWord:$scope.searchInfo, orderBy:$scope.whichOrder})); $rootScope.orderAbsUrl = JSON.parse(sessionStorage.getItem('orderUrl')); console.log($rootScope.orderAbsUrl); };
下载相应的stateEvent.js文件,就可以解决相应的问题。
3、ng-click获取当前点击对象,获取自定义属性值
<span class="operate">
<i class="iconfont icon-beifen_download" data-value="Windows Server 2008 R2" ng-click="downLoad($event.target)" title="下载"></i>
</span>
$scope.downLoad = function (evt) { var fileName = $(evt).data('value'); console.log(fileName); };/
4、bootstrap模态框清除缓存
bootstrap 模态框清除缓存,一直不知道如何解决问题,
网上常见的解决方案是:
$('body').on('hidden.bs.modal', '.modal', function () { $(this).removeData('bs.modal'); });
但是对于的情况不太有效
<div class="modal allocateModel" tabindex="-1" role="dialog" id="userSysAllocate"> <div class="modal-dialog allocateDialog" role="document"> <div class="modal-content allocateContent"> <div class="modal-header allocateHeader"> <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> <h4 class="modal-title">分配备份系统</h4> </div> <div class="modal-body allocateBody" id="allocateContent"> <span class="selectHeader">请选择一个或多个备份系统</span> <div class="selectBtn"> <div class="forSelect"> <input type="checkbox" ng-model="allSelected" ng-checked="allSelected" class="checkIpt" ng-click="selectAll()" value="全选"><span class="selectEle">全选</span> </div> <ul> <li class="roleSelect" ng-repeat="rUser in rUsers track by $index" style="float: left;"> <input type="checkbox" ng-disabled="rUser.creatorId == userBackupId" ng-checked="rUser.relativeState" ng-model="rUser.relativeState" name="chosed" ng-click="allChoose()" class="allCheck checkIptOne" value="{{rUser.systemPkId}}"><span class="selectEle slectRht">{{rUser.systemName}}</span> </li> </ul> </div> </div> <div class="modal-footer allocateFooter"> <button type="button" class="btn btn-default allocateCancle" data-dismiss="modal">取 消</button> <button type="button" class="btn btn-primary allocateConfirm" ng-click="allocateSubmit(userBackupId)">确 定</button> </div> </div> </div> </div>
对应的全选和反选操作是通过原生的Dom操作来实现的,但除了全选的input选择框,剩下都是通过ng-repeat后台获取的,这种是采用的angular方式,也就是angular和原生的Dom操作混用,刚开始还觉得没有问题,后发现全选和反选后,点击取消,再次打开模态框,勾选的没有取消。这就是混用导致的问题。
所以解决方案就是要么就全部使用原生的dom操作,要么就全部使用angular方式。避免混用出现的不可预测的问题。
下面是开始的解决方案,也是出现问题的
$scope.selectAll = function () { var objSelect = document.getElementsByClassName('allCheck'), len = objSelect.length; if($scope.allSelected) { for(var i=0; i<len; i++) { objSelect[i].checked = true; } } else { for(var i=0; i<len; i++) { objSelect[i].checked = false; } } }; $scope.allChoose = function () { var objChoose = document.getElementsByName('chosed'), objTrue = [], len = objChoose.length; for(var i=0; i<len; i++) { objTrue.push(objChoose[i].checked); } var checkRes = objTrue.every(function(item){ return item == true }); $scope.allSelected = checkRes == true ? true : false; };
采用纯angular方式
$scope.selectAll = function () { var len = $scope.rUsers ? $scope.rUsers.length : 0; if($scope.allSelected) { for(var i=0; i<len; i++) { $scope.rUsers[i].relativeState = true; } } else { for(var i=0; i<len; i++) { $scope.rUsers[i].relativeState = false; } } }; $scope.allChoose = function () { var len = $scope.rUsers ? $scope.rUsers.length : 0, objTrue = []; for(var i=0; i<len; i++) { objTrue.push($scope.rUsers[i].relativeState); } var checkRes = objTrue.every(function(item){ return item == true }); $scope.allSelected = checkRes == true ? true : false; }; $('body').on('hidden.bs.modal', '.modal', function () { $(this).removeData('bs.modal'); $scope.sysPrivilege = []; $scope.allSelected = false; });
5、使用splice删除数组中符合条件的项
删除符合条件的项,使用splice来删除,采用倒序的方式,不用break。
如:
var str = ['sidebar.roleList{"#":null','sidebar.modifyPassword{"#":null','sidebar.modifyPassword{"#":null'];
for(var i=str.length;i--;){
if(str[i].indexOf('sidebar.modifyPassword') != -1){
str.splice(i,1);
}
}
console.log(str);
结果见上。
6、AngularJS下$http上传文件(AngularJS file upload/post file)
angularjs上传多个文件,按照网上提示的设置headers: {Content-Type': undefined}和transformRequest: angular.identity,但是仍然提示失败,后来又寻找到另外的一种解决方案:
$http({ method:'POST', url: 'url', headers: { 'Content-Type': undefined }, data: data, transformRequest: (data, headersGetter) => { let formData = new FormData(); angular.forEach(data, function (value, key) { formData.append(key, value); }); return formData; } }) .then(function(response, header, config, status) { handle(response, resovle, reject); }, function(response, header, config, status) { reject('接口访问异常'); });
不支持箭头函数,仍然提示上传附件失败,改成下面的格式就可以了。不知道是什么原因。
function uploadFile(url, data) { return $q(function(resovle, reject) { $http({ url: url, method: 'POST', data: data, headers: {'Content-Type': undefined}, transformRequest: function (data, headersGetter) { var formData = new FormData(); angular.forEach(data, function (value, key) { formData.append(key, value); }); return formData; } }).then(function(response, header, config, status) { handle(response, resovle, reject); }, function(response, header, config, status) { reject('接口访问异常'); }) }) }
7、点击空白区域或非目标区域,关闭气泡,或弹出模态框
下面是jQuery写法
$(document).mouseup(function(e){ var _con = $(' 目标区域 '); // 设置目标区域 if(!_con.is(e.target) && _con.has(e.target).length === 0){ // Mark 1 some code... // 功能代码 } }); /* Mark 1 的原理: 判断点击事件发生在区域外的条件是: 1. 点击事件的对象不是目标区域本身 2. 事件对象同时也不是目标区域的子元素 */
对于angularjs而言,需要注入$document
$document.mouseup(function(e){ var _con = angular.element(".notice-operate"); // 设置目标区域 if(!_con.is(e.target) && _con.has(e.target).length === 0){ // Mark 1 $scope.close_popups(); // 功能代码 } });
8、$stateParams获取不到值,返回undefined。
找了好久,不知原因所在,后来在在网上查到依赖注入输入不一致导致,修改成一致,问题解决了,代码还是要规范。
angular.module('frontierApp.userManage', ['ui.router', 'frontierApp.pagination', 'angular-popups']) .config(['$stateProvider', userConfig]) .controller('UserListCtrl', ['UserManageService', '$rootScope', '$state','$scope', '$stateParams', '$document', 'BASE_URL', UserListCtrl]) .controller('UserDetailCtrl', ['UserManageService', '$rootScope', '$state','$scope', '$http', '$stateParams', UserDetailCtrl]) .controller('UserEditCtrl', ['UserManageService', '$rootScope','$state','$scope', '$http', '$stateParams', UserEditCtrl]) .controller('UserCreateCtrl', ['UserManageService', '$rootScope','$state','$scope', '$stateParams', UserCreateCtrl]);
function UserDetailCtrl(UserManageService, $rootScope, $state, $scope, $stateParams) {
/*代码*/
}
改成如下
angular.module('frontierApp.userManage', ['ui.router', 'frontierApp.pagination', 'angular-popups']) .config(['$stateProvider', userConfig]) .controller('UserListCtrl', ['UserManageService', '$rootScope', '$state','$scope', '$stateParams', '$document', 'BASE_URL', UserListCtrl]) .controller('UserDetailCtrl', ['UserManageService', '$rootScope', '$state','$scope','$stateParams', UserDetailCtrl]) .controller('UserEditCtrl', ['UserManageService', '$rootScope','$state','$scope','$stateParams', UserEditCtrl]) .controller('UserCreateCtrl', ['UserManageService', '$rootScope','$state','$scope', '$stateParams', UserCreateCtrl]);
function UserDetailCtrl(UserManageService, $rootScope, $state, $scope, $stateParams) { /*代码*/ }
9,IE10浏览器导出,报400错误。
查了下,http请求报400错误的原因:
1)前端提交数据的字段名称或者是字段类型和后台的实体类不一致,导致无法封装;
2)前端提交的到后台的数据应该是json字符串类型,而前端没有将对象转化为字符串类型;
导出代码
location.href = BASE_URL + '/user/userinfos/xls?idOrName='+ keyword;
解决方法:
var keyword = $scope.serkey ? $scope.serkey : ""; var data = {idOrName : encodeURI(keyword)}; location.href = BASE_URL + '/user/userinfos/xls' + "?" + jsonToUrlStr(data);
其中jsonToUrlStr函数见下:
function jsonToUrlStr(data) { var strArr = []; for (var m in data) { strArr.push(m + '=' + data[m]); } return strArr.join('&'); }
未完待续。。。