19、angular1全局方法、五种服务类型、过滤、重要指令,ng-、单选框|复选框|下拉框三者联合案例展示、下拉表格嵌套、子组件向父组件传值、directive自定义标签、div拖拽、获取不到新value、多种forEach用法示例、undefined+1、ui.router路由模块、ui.router实际执行步骤、jqLite的API参考、前端路由

一、全局方法
1、config 配置模块。在提供者注册和配置阶段执行。只能注入提供者和常量配置块。在config阶段,注入 provider 的时候需要加上 provider 后缀,可以调用非 $get方法。
2、run 运行模块。执行后创建了发射器和用于启动应用程序。只能注入运行实例和常量。返回的方法在 run 阶段注入的时候,无需加 provider 后缀,只能调用 $get 返回的方法。
3、执行的先后顺序:provider(定义默认)>config(修改默认)>run(最后执行)
(1)定义服务calc
 app.provider('calc',function () {this.currency = '&';console.log(1);});
(2)配置服务calc
 app.config(function (calcProvider) { calcProvider.currency = '钱';console.log(2);});
(3)运行服务calc
 app.run(function (calc) { console.log(3);});

二、五种服务类型
来源:https://blog.csdn.net/qq_33587050/article/details/52138069
1、constant服务:constant不可以修改,可以注入到config里。
(1)app.constant("name",obj)
(2)name为服务的名字,obj为一个json对象.
(3)constant创建服务返回一个json对象(也就是第二个参数中传入的对象)。
2、value服务:value可以修改,不可以注入到config里。
(1)app.value("name",obj)
(2)name为服务的名字,obj为一个json对象.
(3)value创建服务返回一个json对象(也就是第二个参数中传入的对象)。
3、service服务
(1)app.service("name",constructor)
(2)name为服务的名字,第二个参数是一个构造函数,它的实例是实际被注入的服务。
4、factory服务
(1)app.factory("name",function(){return obj})
(2)name为服务的名字,第二个参数是一个普通函数,函数返回对象obj,obj是实际被注入的服务.
5、provider服务
(1)App.provider("myConfig", function () { this.$get= function () { return lastObj }});
(2)name为服务的名字,第二个参数是一个构造函数,其内要有$get方法,$get方法要返回对象lastObj,lastObj是真正被注入的服务。this.$get中的this不是myConfig,lastObj中的this才是myConfig。
6、装饰服务
(1)app.config(function($provide){ $provide.decorator("name",function($delegate){ return $delegate }) });
(2)同样是通过config,在参数函数中注入$provider服务,$provider服务有个decorator方法,它接受两个参数,第一个参数"name",是要被装饰的服务的名字,第二个参数是一个函数,函数中注入$delegate,$delegate就是被装饰的服务的实例,然后在函数中操作$delegate,就相当于操作了该服务的实例。
(3)示例:
app.config(function ($provide) {//通过config,在参数函数中注入$provider服务
    $provide.decorator('name',function ($delegate) {//$provider服务有个decorator方法,它接受两个参数,
        var fn = $delegate; //先保存以前的$delegate
        $delegate = function () {//在外面套一层函数
            var list = Array.from(arguments);
            list[1] = list[1]+2000;
            fn.apply(null,list);
        };
        return $delegate;//在函数中返回$delegate;
    })
});

三、过滤
1、表达式中添加过滤器
<p>姓名为 {{ lastName | uppercase }}</p>
<p>姓名为 {{ lastName | lowercase }}</p>
<p>总价 = {{ (quantity * price) | currency }}</p>
2、向指令添加过滤器
  <li ng-repeat="x in names | orderBy:'country'">
    {{ x.name + ', ' + x.country }}
  </li>
  <input type="text" ng-model="test">
  <li ng-repeat="x in names | filter:test | orderBy:'country'">
    {{ (x.name | uppercase) + ', ' + x.country }}
  </li>
3、自定义过滤器
app.filter('reverse', function() { //可以注入依赖
    return function(text) {
        return text.split("").reverse().join("");
    }
});
4、filter使用规则:
(1)用来处理一个数组,然后可以过滤出含有某个子串的元素,作为一个子数组来返回。
(2)可以是字符串数组,也可以是对象数组。
(3)如果是对象数组,可以匹配属性的值。
(4)如果是字符串数组,可以匹配字符串的组成部分。

四、重要指令(ng-)  
1、ng-if、ng-hide、ng-show的用法
(1)ng-if 如果条件为 false时; “移除” HTML 元素。
(2)ng-show 如果条件为 false时; “隐藏” HTML 元素。
(3)ng-hide 如果条件为 true时; “隐藏” HTML 元素。
(4)ng-trim="false",自动去掉(input)前后空格。
另外:<span> {{protoNum}} </span>
<img src="" ng-hide="protoNum==undefined? false:protoNum+1"/>
(1)在HTML里,undefined+1的运行结果是字符串“undefined1”,
(2)在js里,undefined+1的运行结果是数字NaN。
2、ng-repeat:用于遍历数组或对象,
(1)<tr ng-repeat="(key,value) in arrayOrObject"><td>{{key}}{{value}}</td></tr>,
用这种格式遍历数组,key是每一项的索引,value是每一项的值。
用这种格式遍历对象,key是每一项的属性名,value是每一项的属性值。
(2)<tr ng-repeat="item in arrayOrObject"><td>{{item}}</td></tr>,
用这种格式遍历数组,item是数组中的每一项;
用这种格式遍历对象,item是对象中的每一项的属性值。
3、ng-model
以<input type="text" ng-model="name">{{name}}为例:
(1)如果input所在的作用域内已经声明name并给name赋值了,那么ng-model会把该值获取到,并在input里输出。同时{{name}}也会把该值取到页面上。当input里面的值改变时,ng-model把作用域内的name值进行修改,同时{{name}}也会用修改后的name值覆盖原来页面上的name值。 
(2)如果input所在的作用域内没有声明name,那么ng-model会在作用域内声明一个name。当input里面输入值后,ng-model会对作用域内的name进行赋值,同时{{name}}也会在页面上输出。
(3)原理:ng-model根据input标签的type属性值的不同,监听用户的输入事件如onchange,onkeyup,onkeydown。
(4)type="radio",ng-model的值就是选中的那个radio所对应的ng-value的值;初始化单选框,yesOrNo=1,则前者选中,yesOrNo=2,则后者选中,此单选框被选中;点击1单选框,则1单选框被选中,赋值yesOrNo=1
<input type="radio" name="inlineRadioOptions" ng-model="yesOrNo" ng-value="1">。//ng-value:设置输入框的值。
<input type="radio" name="inlineRadioOptions" ng-model="yesOrNo" ng-value="2">。//ng-value:设置输入框的值。
(5)type="checkbox"
<input type="checkbox" ng-model="all"> Check all<br><br>
<input type="checkbox" ng-checked="all">Volvo<br>
<input type="checkbox" ng-checked="all">Ford<br>
<input type="checkbox" ng-checked="all">Mercedes
(6)<select ng-model="myLog.resultDo" ng-options="item.value as item.key for item in resultDo"></select>
$scope.resultDo = [
  { value: '', key: '全部' },
  { value: '已读', key: '已读' },
  { value: '未读', key: '未读' }
]
https://blog.csdn.net/mydtudysy/article/details/78040969
4、ng-bind-html,如果没有$sce或$sanitize的辅助,它是不会生效的。
(1)内置的$sce.trustAsHtml(),它不经过净化,直接将html绑定给元素,保留所有的属性和事件。
(2)注入第三方模块ngSanitize就行了,不用注入$sanitize服务,$sanitize会自动对html标签进行净化,并会把标签的属性以及绑定在元素上的事件都移除,仅保留了标签和内容。
(3)$sce用法示例
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title></title>
    <script type="text/javascript" src="https://cdn.bootcss.com/angular.js/1.5.8/angular.js"></script>
</head>
<body ng-app="myApp" ng-controller="myCtl">
<div ng-bind-html="content">
</div>
</body>
</html>
<script>
    var app = angular.module('myApp', []);
    app.controller('myCtl',function($scope,$sce){
        $scope.temporaryContent="My name is: <h1 >John Doe</h1>";
        $scope.content = $sce.trustAsHtml($scope.temporaryContent);
    });
</script>
(4)ngSanitize用法示例
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title></title>
    <script type="text/javascript" src="https://cdn.bootcss.com/angular.js/1.5.8/angular.js"></script>
    <script src="https://cdn.bootcss.com/angular-sanitize/1.5.9/angular-sanitize.js"></script>
</head>
<body >
<div ng-app="myApp" ng-controller="myCtrl">
    <p ng-bind-html="myText"></p>
</div>
</body>
</html>
<script>
var app = angular.module("myApp", ['ngSanitize']);
app.controller("myCtrl", function($scope) {
    $scope.myText = "My name is: <h1 >John Doe</h1>";
});
</script>
5、ng-class(三元、数组、对象)、ng-bind(三元、数组)、ng-style(三元)与ng-src(三元双括号)用法示例
<!DOCTYPE html>
<html  ng-app="myModel">
<head>
  <meta charset="UTF-8">
  <title>样式</title>
  <style>
    .red{color:red}
    .green{color:green}
  </style>
  <script type="text/javascript" src="https://cdn.bootcss.com/angular.js/1.6.2/angular.js"></script>
</head>
<body>
<div ng-controller="firstCtrl">
  <div ng-class="isTrue?'red':'green'">class布尔</div>
  <div ng-class="['red','green'][num1]">class数组</div>
  <div ng-class="{'red':isTrue,'green':!isTrue}">class对象</div>
  <div ng-color':'green','width':'200px'}:{'color':'red','width':'300px'}">style布尔</div>
  <div ng-width': width? width:'400px','height': height? height:'400px', }">style对象</div>
  <div><span ng-bind="isTrue?'连接':'未连接'"></span><span>--bind布尔</span></div>
  <div><span ng-bind="['未连接','连接'][li.status]"></span><span>--bind数组</span></div>
</div>
</body>
</html>
<script>
  var app = angular.module('myModel', []);
  app.controller('firstCtrl', function ($scope) {
    $scope.isTrue=true;
    $scope.num1=1;
    $scope.width='200px';
    $scope.height='20px';
  });
</script>
<img ng-src="{{isTrue?path1:path2}}" alt=""/>
6、ng-transclude
<!DOCTYPE html>
<html  ng-app="myModel">
<head>
  <meta charset="UTF-8">
  <title>多个插槽之angular1.6.2版</title>
  <script type="text/javascript" src="https://cdn.bootcss.com/angular.js/1.6.2/angular.js"></script>
</head>
<body>
  <div ng-controller="thisCtrl">
    <panel color="blue">
      <panel-header><h1>{{title}}</h1></panel-header>
      <panel-body><h1>{{content}}</h1></panel-body>
      <panel-footer><h1>{{footer}}</h1></panel-footer>
    </panel>
  </div>
</body>
<script>
  var app = angular.module('myModel', []);
  app.controller('thisCtrl',function($scope){
    $scope.title = "头";
    $scope.content = "体";
    $scope.footer = "脚";
  });
  app.directive('panel', function(){
    return {
      template: `
        <div >
          <div>下面放置插槽header:</div>
          <div ng-transclude="header"></div>
          <div>下面放置插槽body:</div>
          <div ng-transclude="body"></div>
          <div>下面放置插槽footer:</div>
          <div ng-transclude="footer"></div>
        </div>
      `,
      restrict: 'E',
      replace: true,
      transclude: {
        'header': 'panelHeader',
        'body': 'panelBody',
        'footer': 'panelFooter'
      },
      controller: function ($scope) {
           
      },
      link: function (scope, element, attr,) {
        scope.aaa = attr.color
      }  
    }
  });
</script>
</html>
7、ng-app
根模块的依赖模块加载完毕后,根模块才可以挂载到页面上
(1)用法一
<html ng-app="myApp" ng-controller="myCtrl">
  <body></body>
</html>
<script>
  //此处导入依赖['deploy1','deploy2']
  var app = angular.module('myApp', ['deploy1','deploy2']);
  app.controller('myCtrl', function ($scope) { });
</script>
(2)用法二
<html ng-controller="myCtrl">
  <body></body>
</html>
<script>
  var app = angular.module('myApp', ['deploy1','deploy2']);
  app.controller('myCtrl', function ($scope) { });
  //此处导入依赖['deploy1','deploy2']
  angular.bootstrap(document, ['myApp']);
</script>

五、单选框|复选框|下拉框三者联合案例展示
说明:单选框与复选框在点击事件发生时的区别
1、单选框在点击后:呈现选中状态,ng-model取值ng-value(初始化时,两者相等则选中);
2、复选框在点击后:呈现相反状态,ng-model取反ng-model(初始化时,布尔转换ng-checked的结果赋值给ng-model,决定是否选中),ng-checked永远保持原始值;
<!DOCTYPE html>
<html  ng-app="myModel">
<head>
  <meta charset="UTF-8">
  <title>联合案例展示</title>
  <script type="text/javascript" src="https://cdn.bootcss.com/angular.js/1.6.2/angular.js"></script>
</head>
<body>
<div ng-controller="firstCtrl">
  <div >
    <span>右边是type="checkbox"</span>
    <input type="checkbox"  ng-checked="checkboxCheck" ng-model="checkboxModel" ng-click="checkbox()">
  </div>
  <div >
    <span>右边是select</span>
    <select ng-model="myLog.resultDo" ng-options="item.back as item.front for item in resultDo"  ng-change="selectOption()"></select>
  </div>
  <div >
    <span>右边是type="radio"</span>
    <input  type="radio" name="options" ng-model="deviceMode.mode" ng-value="0"  ng-click="selectRadio()"/>
    <label for="terminal"  ng-click="selectRadio()">终端</label>
    <input  type="radio" name="options" ng-model="deviceMode.mode" ng-value="1"  ng-click="selectRadio()"/>
    <label for="platform" ng-click="selectRadio()">平台</label>
  </div>
  </div>
</body>
</html>
<script>
  var app = angular.module('myModel', []);
  app.controller('firstCtrl', function ($scope) {
    $scope.myLog={resultDo:"全部后台"};
    $scope.resultDo = [{ back: '全部后台', front: '全部前端' },{ back: '已读后台', front: '已读前端' },{ back: '未读后台', front: '未读前端' }];
    $scope.deviceMode = {mode: 0};
    $scope.checkboxCheck = false;/*永远不变*/
    $scope.checkboxModel = true;/*交替改变*/
    $scope.checkbox = function () {
      console.log($scope.checkboxCheck);
      console.log($scope.checkboxModel)
    };
    $scope.selectRadio = function () {
      console.log($scope.deviceMode)
    };
    $scope.selectOption = function () {
      console.log($scope.myLog.resultDo)
    };
  });
</script>
3、下拉框分组
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
  <title></title>
  <script type="text/javascript" src="https://cdn.bootcss.com/angular.js/1.6.2/angular.js"></script>
</head>
<body ng-app="myapp">
  <div ng-controller="mainCtrl">
    <div>
      <p>你的选择是:{{selectedOption}}</p>
      <select ng-options="item.id as item.name group by item.sex for item in resultDo"
        ng-model="selectedOption"></select>
    </div>
  </div>
  <script type="text/javascript">
    var myapp = angular.module('myapp', []);
    myapp.controller('mainCtrl', ['$scope', function ($scope) {
      $scope.selectedOption ="hanmeimei";
      //定义包含对象的数组 resultDo
      $scope.resultDo = [
        { "id": "lilei", "name": "李雷", "sex": "man" },
        { "id": "hanmeimei", "name": "韩梅梅", "sex": "woman" },
        { "id": "jack", "name": "杰克", "sex": "man" }
      ];
    }])
  </script>
</body>
</html>
4、下拉框可输入
<div class="form-group">
  <label>资产名称</label>
  <div class="form-group">
    <input 
      list="device_name"
      type="text"
      class="form-control"
       ng-model="addDialogItem.device_name"/>
    <datalist >
      <option 
        ng-repeat="option in assetName track by $index" 
        value="{{option.device_name}}">{{option.device_name}}</option>
    </datalist>
  </div>
</div>

六、下拉表格嵌套
<table class="table">
  <thead>
    <tr>
      <th>
        <button>序号</button>
      </th>
      <th ng-repeat="li in title track by $index">
        <button>{{li}}</button>
      </th>
    </tr>
  </thead>
  <tbody ng-repeat="li in list__detail track by $index">
    <tr>
      <td>
        <div>
          <img ng-src="{{''}}" alt=""/>
        </div>
      </td>
      <td ng-bind="li.name"></td>
      <td ng-bind="li.name"></td>
      <td ng-bind="li.name"></td>
      <td ng-bind="li.name"></td>
    </tr>
    <tr ng-if="li.is_show">
      <td colspan="9999"><!-- 这点很重要,td下面放div -->
        <div >
          <div>此处可以通过jquery.json-viewer.js,格式化JSON数据</div>
          <div>js代码为$('#JSONData').jsonViewer(JSON.parse(data))</div>
        </div>
      </td>
    </tr>
    <tr ng-if="li.is_show">
      <td colspan="9999"><!-- 这点很重要,td下面放table -->
        <table>
          <thead>
            <tr>
              <th>文字</th>
              <th>文字</th>
              <th>文字</th>
              <th>文字</th>
              <th>文字</th>
            </tr>
          </thead>
          <tbody>
            <tr ng-repeat="item in list track by $index">
              <td ng-bind="item.name"></td>
              <td ng-bind="item.name"></td>
              <td ng-bind="item.name"></td>
              <td ng-bind="item.name"></td>
              <td ng-bind="item.name"></td>
            </tr>
            <tr>
              <td colspan="9999" ng-if="list.length<1">暂无数据可显示。</td>
            </tr>
          </tbody>
        </table>
        <!-- 此处分页组件 -->
      </td>
    </tr>
  </tbody>
</table> 

七、子组件向父组件传值
思路:在父组件定义一个函数,在函数体里,将函数的参数赋值给父组件$scope的一个属性;通过属性传参的方式把这个函数传给子组件。在子组件里,给这个函数传参并执行,实现子组件向父组件传值!
<!DOCTYPE html>
<html  ng-app="appModule" ng-controller="ancestorCtrl">
<head>
    <meta charset="UTF-8">
    <title>子组件向父组件传值</title>
    <script type="text/javascript" src="https://cdn.bootcss.com/angular.js/1.5.8/angular.js"></script>
</head>
<body>
<my-parent></my-parent>
</body>
</html>
<script>
var app = angular.module('appModule', []);
app.controller("ancestorCtrl", function ($scope) {});
app.directive('myParent', function () {
  return {
    template: "<div><my-child son-method='parentMethod'></my-child>" + "<div>{{sonData}}</div></div>",
    restrict: 'E',//指令类型  E:element A:attribute M:comment C: class
    replace: true,//模板放在<my-parent>内部还是取代它,默认是false,放在其内部
    controller: function ($scope) {
      $scope.parentMethod = function (key) {
        $scope.sonData = key;
      };
    },
  }
});
app.directive('myChild', function () {
  return {
    template: "<div><button ng-click='thisMethod(\"222\")'>点击获取来自子组件的数据</button></div>",
    restrict: 'E',
    replace: true,
    scope: {
      sonMethod:'=sonMethod'
    },
    controller: function ($scope) {
      $scope.index = 1;
      $scope.thisMethod = function (key) {
        $scope.index += 1;
        $scope.sonData = key + $scope.index;
        $scope.sonMethod($scope.sonData)
      };
    },
  }
})
</script>

八、directive自定义标签
1、基本案例
<!DOCTYPE html>
<html  ng-app="appModule" ng-controller="thisCtrl">
<head>
  <meta charset="UTF-8">
  <title></title>
  <script type="text/javascript" src="https://cdn.bootcss.com/angular.js/1.5.8/angular.js"></script>
</head>
<body>
  <this-div outer-function='outerFunction'>
    <button ng-click="slotFunction()">这是插槽-可以读取当前页的内容</button>
  </this-div>
</body>
</html>
<script>
  var app = angular.module('appModule', []);
  app.controller("thisCtrl", function ($scope) {
    $scope.slotContent = "这是组件的插槽内容!";
    $scope.slotFunction = function () {
      console.log($scope.slotContent)
    };
    $scope.outerFunction= function () {
      console.log($scope.slotContent)
    };
  });
  app.directive('thisDiv', function () {
    var str = '';
    str += "<div>";
    str += "<div ng-transclude></div>";
    str += "<button ng-click='innerFunction()'>这是组件-可以读取当前页的内容</button>";
    str += "</div>";
    return {
      template: str,
      restrict: 'E',
      replace: true,
      transclude: true,
      scope: {
        outerFunction: '='
      },
      controller: function ($scope) {
        $scope.innerFunction = function () {
          $scope.outerFunction()
        }
      }
    }
  });
</script>
2、嵌套
<!DOCTYPE html>
<html  ng-app="appModule" ng-controller="ancestorCtrl">
<head>
    <meta charset="UTF-8">
    <title></title>
    <script type="text/javascript" src="https://cdn.bootcss.com/angular.js/1.5.8/angular.js"></script>
</head>
<body>
<my-parent>
    {{ancestorName}}
    <my-child selfAttr="myAttr">{{childName}}</my-child>
</my-parent>
</body>
</html>
<script>
    var app = angular.module('appModule', []);
    app.controller("ancestorCtrl", function ($scope) {
        $scope.ancestorName = "我所处的位置,表明我只能在ng-transclude里出现。";
        $scope.childName = "变量必须定义在作用域里,myParent和myChild的作用域我进不去。";
    });
    app.directive('myParent', function () {
        return {
            template: "<div><p>第一段</p>" + "<div ng-transclude></div>" + "<p>第二段</p>" + "<div>{{parentName}}</div></div>",
            //template: '<div>我是指令生<div ng-transclude></div>成的内容</div>',//templateUrl导入自定义元素的模板
            restrict: 'E',//指令类型  E:element A:attribute M:comment C: class
            replace: true,//模板放在<my-parent>内部还是取代它,默认是false,放在其内部
            transclude: true,//是否保留自定义指令开闭标签之间的内容,该内容插入模板中使用ng-transclude属性的地方,默认为false,如上。<div ng-view></div>通过路由放入数据
            scope: {
              //获取自定义标签的属性值//false:继承父作用域;true:继承父作用域且创建独立作用域;{}:不继承父作用域且创建独立作用域。
              //scope:{name:'@name',绑定字符串  name:'=name',绑定变量  name:'&name',绑定函数}。传进来的变量,在值改变后,父作用域的该变量的值也随之改变。
            },
            controller: function ($scope) {
              //指令的controller和link可以进行互换。controller的主要作用(1)导入自定义或ng内置的服务;(2)提供可在子指令里复用的行为。
              $scope.focusAAA = function () {};
              this.parentMethod = function (son) {
                console.log('son:',son);
              }
            },
            compile: function(element, attributes) {
              //compile和link是相斥的。如果同时设置了两项,compile返回的函数会被当作链接函数把后面定义的link函数所取代,也就是说,后面的link函数将起不到作用。controller先运行,compile后运行,link不运行
            },
            link: function (scope, element, attr, ctrl, linker) {}
        }
    });
    app.directive('myChild', function () {
        return {
            template: "<div><span ng-click='toParent()'>这里是span1;</span><span>这里是span2。</span><div ng-transclude></div></div>",
            restrict: 'E',
            replace: true,
            transclude: true,
            scope: {},
            require: '?^myParent',//?不要抛出异常;^允许查找父元素的controller
            controller: function ($scope) {
              console.log( $scope.parentMethod  )
            },
            /*compile: function(element, attributes) {},*/
            //'myParent':在当前指令中查找控制器;'^myParent'在上游指令中查找控制器;'?^myParent':当前指令若没有,就向上游查找
            link: function (scope, element, attr, ctrl, linker) {
                ctrl.parentMethod();
                linker(scope, function (clone) {
                    console.log(clone.text())
                })
            }
        }
    })
</script>

九、div拖拽
<!DOCTYPE html>
<html >

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <style>
        .drag-container {
            display: flex;
            justify-content: flex-start;
            align-items: center;
        }

        .drag-container .drag-box {
            display: flex;
            align-items: center;
            justify-content: center;
            width: 200px;
            height: 200px;
            margin: 20px;
            color: #fff;
            font-size: 20px;
            font-weight: bold;
        }

        .drag-container .drag-box .drag-item {
            display: flex;
            align-items: center;
            justify-content: center;
            width: 150px;
            height: 150px;
        }
    </style>
    <title>ng-dragger</title>
</head>

<body ng-app="app" ng-controller="draggerController">
    <div class="drag-container">
        <div ng-repeat="item in dragArr" class="drag-box" ng-drop="true" ng-drop-success="onDropComplete($index, $data, $event)">
            <div class="drag-item" ng-drag="true" ng-drag-data="{{item}}" ng->{{item.text}}</div>
        </div>
        <div ng-repeat="item in dragArr" class="drag-box" ng-drop="true" ng-drop-success="onDropComplete($index, $data, $event)">
            <div class="drag-item" ng-drag="true" ng-drag-data="{{item}}" ng->{{item.text}}</div>
        </div>
    </div>

    <script src="https://cdn.bootcss.com/angular.js/1.3.1/angular.js"></script>
    <script src="https://cdn.bootcss.com/ngDraggable/0.1.11/ngDraggable.js"></script>
    <script>
        var myApp = angular.module('app', ['ngDraggable']);
        myApp.controller('draggerController', function($scope) {
            $scope.dragArr = [{
                text: '方块1',
                color: 'green',
                key: 'arr1'
            }, {
                text: '方块2',
                color: 'blue',
                key: 'arr1'
            }, {
                text: '方块3',
                color: '#888',
                key: 'arr1'
            }, {
                text: '方块4',
                color: '#888',
                key: 'arr2'
            }, {
                text: '方块5',
                color: '#888',
                key: 'arr2'
            }, {
                text: '方块6',
                color: '#888',
                key: 'arr2'
            }];

            $scope.onDropComplete = function(index, obj, $event) {
                var otherObj = $scope.dragArr[index];
                var otherIndex = $scope.dragArr.findIndex(vv => Object.is(vv.text, obj.text));
                if (otherObj.key !== obj.key) return;
                $scope.dragArr[index] = obj;
                $scope.dragArr[otherIndex] = otherObj;
            }

        })
    </script>
</body>

</html>

十、获取不到新value
症状:angular对象数据的value被更改后,获取的仍然是旧value
原因:在第三方插件或原生JS里进行的变化,没法触发脏值检测。
angular.module('myApp', []).controller('MessageController', function ($scope) {
  $scope.getMessage = function () {
    setTimeout(function () {
      $scope.$apply(function () {
        $scope.message = 'Fetched after 3 seconds';
        console.log('message:' + $scope.message);
      });
    }, 2000);
  }
  $scope.getMessage();
});
$scope.getMessage = function () {
  setTimeout(function () {
    $scope.message = 'Fetched after two seconds';
    console.log('message:' + $scope.message);
    $scope.$apply(); //this triggers a $digest
  }, 2000);
}
angular.element(document).ready(function () {
  var config = {
    elem: '#' + $scope.dateInputId,
    theme: '#007bff',
    trigger: 'click',
    done: function (value) {
      $scope.dateModel = value;
      $scope.$apply();//在此处执行
      angular.isFunction($scope.updata) ? $scope.updata() : '';
      //在此处执行无效
    }
  };
  laydate.render(config);
});

十一、[].forEach|$.each|angular.forEach用法示例
<!DOCTYPE html>
<html >
<head>
  <meta charset="UTF-8">
  <title></title>
</head>
<body>
本代码不能运行
</body>
</html>
<script>
  //[].forEach
  [3, 3, 3].forEach(function (a, b, c, d) {
    //3 0 [ 3, 3, 3, 3, 3 ] undefined
    console.log(a, b, c, d)
  })
  //$.each
  $.each([3, 3, 3, 3], function (a, b, c) {
    console.log(a, b, c)
    //0 3 undefined

  })
  $.each({ a: 'b' }, function (a, b) {
    console.log(a, b)
    //a,b
  });
  //angular.forEach
  angular.forEach([3, 3, 3], function (a, b, c, d) {
    console.log(a, b, c, d)
    //3 0 Array(6) undefined
  });
  angular.forEach({ a: 'b' }, function (a, b) {
    console.log(a, b)
    //b,a
  });
</script>

十二、undefined+1
在HTML里,undefined+1的运行结果是字符串“undefined1”,
在js里,undefined+1的运行结果是数字NaN。

十三、ui.router路由模块
1、提供$stateProvider对象,
(1)用$stateProvider.state(stateNameString, stateConfigObject)配置路由。
(2)用template去替换<ui-view></ui-view>或<div ui-view></div>。
(3)stateConfigObject包含以下内容:
(3-1)template: string/function,html模板字符串,或者一个返回html模板字符串的函数。
(3-2)templateUrl:string/function,模板路径的字符串,或者返回模板路径字符串的函数。
(3-3)templateProvider:function,返回html模板字符串或模板路径的服务。
(3-4)controller:string/function,新注册一个控制器函数或者一个已注册的控制器的名称字符串。
(3-5)controllerProvider:function,返回控制器或者控制器名称的服务
(3-6)controllerAs:string,控制器别名。
(3-7)parent:string/object,手动指定该状态的父级。
(3-8)resolve:object,将会被注入controller去执行的函数,<string,function>形式。
(3-9)url:string,当前状态的对应url。
(3-10)views:object,视图展示的配置。<string,object>形式。
(3-11)abstract:boolean,一个永远不会被激活的抽象的状态,但可以给其子级提供特性的继承。默认是true。
(3-12)onEnter:function,当进入一个状态后的回调函数。
(3-13)onExit:function,当退出一个状态后的回调函数。
(3-14)reloadOnSearch:boolean,如果为false,那么当一个search/query参数改变时不会触发相同的状态,用于当你修改$location.search()的时候不想重新加载页面。默认为true。
(3-15)data:object,任意对象数据,用于自定义配置。继承父级状态的data属性。换句话说,通过原型继承可以达到添加一个data数据从而整个树结构都能获取到。
(3-16)params:url里的参数值,通过它可以实现页面间的参数传递。params:{params1:null,params2:null...}
2、提供$urlRouterProvider对象,
(1)用$urlRouterProvider.when(url,otherUrl/handler)配置匹配的前端路由,
(2)用$urlRouterProvider.otherwise('/login')配置不匹配的前端路由。

十四、ui.router实际执行步骤
$stateParams.params;
$state.go('page',{ thisParams: '123'})
附1:ngRoute模块提供$routeProvider服务
1、$routeProvider.when('/bookDetail/:bookId',{}).when()
2、<a class="btn btn-default" href="#/bookDetail/{{book.id}}">//实参
3、var bookId = $routeParams.bookId;//获取实参
附2:ui.router和ngRoute的区别
1、ui.router模块提供$urlRouterProvider、$stateProvider、$stateParams服务
2、ngRoute模块提供$routeProvider、$routeParams服务
以下是流程
1、定义路由状态;
$stateProvider
 .state('page2', {
   url: '/event-safe/:thisParams',
   params: {
     thisParams: null//前端可以根据thisParams的取值不同,进行不同的处理,与上面的:thisParams二选一使用
   },
   templateUrl: 'event/event-safe.html',
   controller: 'eventSafeCtrl',
 })
2、激活路由的方式
(1)$state.go():优先级最高的激活方式
(2)ui-sref:点击包含此指令跳转,例如<a ui-sref="page2({type:1})"></a>
(3)ng-href:<a ng-href="#/page2/1"></a>
3、ui.router路由嵌套:通过 .语法进行路由层级配置
代码示例一:
/* 以下是index.html */
<div>
 <span>其他内容</span>
 <a ui-sref="about">About</a>
 <a ui-sref="home">Home</a>
 <span>其他内容</span>
 <div ui-view></div>
</div>
/* 以下是home.html */
<div>
 <span>其他内容</span>
 <a ui-sref=".list">List</a>
 <a ui-sref=".graph">Paragraph</a>
 <span>其他内容</span>
 <div ui-view></div>
</div>
$stateProvider
 .state("about", {
   url: "/about",
   templateUrl: "about.html",
 })
 .state("home", {
   url: "/home",
   templateUrl: "home.html",
 })
 .state("home.list", {
   url: "/list",
   templateUrl: "home-list.html",
   controller: function ($scope) {
     $scope.dogs = ["Bernese", "Husky", "Goldendoodle"];
   },
 })
 .state("home.graph", {
   url: "/graph",
   template: "I could sure use a drink right now.",
 });
代码示例二:
<div>
 <div ui-view="filters"></div>
 <div ui-view="mailbox"></div>
 <div ui-view="priority"></div>
</div>
$stateProvider
 .state('inbox', {
   views: {
     'filters': {
       template: '<h4>Filter inbox</h4>',
       controller: function($scope) {}
     },
     'mailbox': {
       templateUrl: 'partials/mailbox.html'
     },
     'priority': {
       template: '<h4>Priority inbox</h4>',
       resolve: {
         facebook: function() {
           return FB.messages();
         }
       }
     }
   }
 }); 
 
十五、jqLite的API参考
在jQuery中,$()里面是通过各种选择器获得元素;在jqLite中,通过angular.element(param)获得元素;param只有两种:一种是类似html元素的字符串,一种是Dom元素。如:var email=angular.element('<input name="email" >angular.element(document.getElementById(‘myId’));
jqLite API参考:https://blog.csdn.net/chi1130/article/details/78556097
01、addClass()  //为每个匹配的元素添加指定的样式类名
02、after() 在匹配元素集合中的每个元素后面插入参数所指定的内容,作为其兄弟节点
03、append()    //在每个匹配元素里面的末尾处插入参数内容
04、attr()  //获取匹配的元素集合中的第一个元素的属性的值
05、bind()  //为一个元素绑定一个事件处理程序
06、children()  //获得匹配元素集合中每个元素的子元素,选择器选择性筛选
07、clone() //创建一个匹配的元素集合的深度拷贝副本
08、contents()  //获得匹配元素集合中每个元素的子元素,包括文字和注释节点
09、css()   //获取匹配元素集合中的第一个元素的样式属性的值
10、data()  //在匹配元素上存储任意相关数据
11、detach()    //从DOM中去掉所有匹配的元素
12、empty() //从DOM中移除集合中匹配元素的所有子节点
13、eq()    //减少匹配元素的集合为指定的索引的哪一个元素
14、find()  //通过一个选择器,jQuery对象,或元素过滤,得到当前匹配的元素集合中每个元素的后代
15、hasClass()  //确定任何一个匹配元素是否有被分配给定的(样式)类
16、html()  //获取集合中第一个匹配元素的HTML内容
17、next()  //取得匹配的元素集合中每一个元素紧邻的后面同辈元素的元素集合。如果提供一个选择器,那么只有紧跟着的兄弟元素满足选择器时,才会返回此元素
18、on()    //在选定的元素上绑定一个或多个事件处理函数
19、off()   //移除一个事件处理函数
20、one()   //为元素的事件添加处理函数。处理函数在每个元素上每种事件类型最多执行一次
21、parent()    //取得匹配元素集合中,每个元素的父元素,可以提供一个可选的选择器
22、prepend()   //将参数内容插入到每个匹配元素的前面(元素内部)
23、prop()  //获取匹配的元素集中第一个元素的属性(property)值
24、ready() //当DOM准备就绪时,指定一个函数来执行
25、remove()    //将匹配元素集合从DOM中删除。(同时移除元素上的事件及 jQuery 数据。)
26、removeAttr()    //为匹配的元素集合中的每个元素中移除一个属性(attribute)
27、removeClass()   //移除集合中每个匹配元素上一个,多个或全部样式
28、removeData()    //在元素上移除绑定的数据
29、replaceWith()   //用提供的内容替换集合中所有匹配的元素并且返回被删除元素的集合
30、text()  //得到匹配元素集合中每个元素的合并文本,包括他们的后代
31、toggleClass()   //在匹配的元素集合中的每个元素上添加或删除一个或多个样式类,取决于这个样式类是否存在或值切换属性。即:如果存在(不存在)就删除(添加)一个类
32、triggerHandler()    //为一个事件执行附加到元素的所有处理程序
33、unbind()    //从元素上删除一个以前附加事件处理程序
34、val()   //获取匹配的元素集合中第一个元素的当前值
35、wrap()  //在每个匹配的元素外层包上一个html元素
 
十六、前端路由及触发条件
1、前端路由的作用是 
(1)记录当前页面的状态; 
(2)可以使用浏览器的前进后退功能;
2、前端路由的实现是浏览器的hash模式,该模式能做到: 
(1)url变化时,不向后台发送请求;
(2)截获url地址,并解析出需要的信息来匹配路由规则。 
(3)另外,使用浏览器的history模式时,当url变化时,会向后台发送请求;
3、angular1前端路由触发条件
(1)<a href="#bbb">Home</a>
(2)$state.go('login')