前端遇到的一些坑

1、 angular强制清除浏览器缓存

 原文是这样记录的:

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">&times;</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('&');
    }

  

  

  

未完待续。。。  

posted @ 2017-09-04 16:47  Tome.Wong  阅读(880)  评论(0编辑  收藏  举报