19、angular1之pass-word组件、input-select组件 、only-select组件(两种)、on-off组件(缺八)

122 阅读2分钟

19、angular1之pass-word组件、input-select组件 、only-select组件(两种)、on-off组件、layui中的datetime示例、京东购物车、两种作用域绑定、两种函数传递

一、pass-word组件(自定义密码输入框,可预览)
使用场景:修改密码时,对密码进行多方位验证,并显示验证结果。
<!DOCTYPE html>
<html lang="en" ng-app="myModel">
<head>
  <meta charset="UTF-8">
  <title>passWord</title>
  <script type="text/javascript" src="https://cdn.bootcss.com/angular.js/1.6.2/angular.js"></script>
</head>
<body>
  <div ng-controller="thisCtrl">
    <pass-word 
      label-width="150" 
      is-must-fill="true" 
      label-text="原密码" 
      this-type="password" 
      placeholder="原密码" 
      is-disabled="false"
      self-show='pastShow'
      is-past-input='true' 
      self-data="oldPassword" 
      verify="verify" 
    ></pass-word>
    <pass-word 
      label-width="150" 
      is-must-fill="true" 
      label-text="输入新密码" 
      this-type="password"  
      placeholder="输入新密码" 
      is-disabled="false" 
      is-first-input='true' 
      key-of-reg-exp="simplePassword" 
      self-data="params.newPassword" 
      sibling-data="newPasswordSecond" 
      one-tip="oneTip" 
      many-tips="manyTips"
      self-show='selfShow'
      sibling-show='siblingShow'
    ></pass-word>
    <pass-word 
      label-width="150" 
      is-must-fill="true" 
      label-text="再次输入新密码" 
      this-type="password"  
      placeholder="再次输入新密码" 
      is-disabled="false" 
      key-of-reg-exp="simplePassword" 
      self-data="newPasswordSecond" 
      sibling-data="params.newPassword" 
      one-tip="oneTip" 
      many-tips="manyTips" 
      self-show='siblingShow'
      sibling-show='selfShow'
    ></pass-word>   
  </div>
</body>
</html>
<script>
  var app = angular.module('myModel', []);
  app.controller('thisCtrl', function ($scope) {
    $scope.params = {};//发给后台
    $scope.pastShow = {
      isShowOneTip:false,
      isGreenOneTip:false,
      isShowManyTips:false,
    };
    $scope.selfShow = {
      isShowOneTip:false,
      isGreenOneTip:false,
      isShowManyTips:false,
    };
    $scope.siblingShow = {
      isShowOneTip:false,
      isGreenOneTip:false,
      isShowManyTips:false,
    };
    $scope.oneTip = {//由当前页传至本组件
      success: '自定义_输入符合要求!',
      empty: '自定义_该项不能为空!',
      different: '自定义_两次密码输入不一致!',
      formatError: '自定义_输入不符合要求,请输入以字母开头的4-24个字符!'
    };
    $scope.manyTips= [
      '密码要求:',
      '1.必须包含:数字',
      '2.必须包含:字母',
      '3.必须包含:小写字母',
      '4.必须包含:大写字母',
      '5.必须包含:下划线',
    ];
    $scope.oldPassword= '';
    $scope.params.newPassword='';
    $scope.newPasswordSecond= '';
    $scope.verify = function() {
      //把原密码告诉后台,根据后台判断结果,决定是否继续验证
      return true
    }
  });
  app.directive('passWord', function () {
    var html = `
      <div style="display:flex;align-items:center">
        <div ng-style="{width:(labelWidth||130)+'px'}" style="text-align:right;margin-right:10px;">
          <span ng-show="isMustFill" style="color:red;">*</span>
          <label ng-bind="labelText||'密码'"></label>
        </div>
        <div style="padding:10px 0; position:relative;">
          <input 
            type="{{ thisType ? thisType : 'text' }}" 
            ng-model="selfData" placeholder="{{placeholder||''}}" 
            ng-disabled="isDisabled" ng-focus="focus()" 
            ng-change="changeOrBlur()" 
            ng-blur="changeOrBlur()" 
            ng-trim="false" 
            style="width:290px;height:30px"
          >
          <img 
            src="{{servicePicture.eyeClose}}" 
            ng-click="isShowEyeOpen=true;thisType='text'" 
            ng-show="!isShowEyeOpen" 
            style="width:14px;height:14px;position:absolute;right:10px;top:20px;cursor:pointer;padding:5px;"
          >   
          <img 
            src="{{servicePicture.eyeOpen}}" 
            ng-click="isShowEyeOpen=false;thisType='password'" 
            ng-show="isShowEyeOpen" 
            style="width:14px;height:14px;position:absolute;right:10px;top:20px;cursor:pointer;padding:5px;"
          >
        </div>
        <div style="position:relative">
          <div ng-show="selfShow.isShowOneTip">
            <img 
              src="{{selfShow.isGreenOneTip ? servicePicture.correct : servicePicture.error}}" 
              style="width:14px;height:14px;position:relative;left:5px;">
            <span 
              ng-bind="singleTipText" 
              ng-style="selfShow.isGreenOneTip?{ \'color\':\'green\'}:{\'color\':\'red\'}" 
              style="position:relative;left:5px;">
            ></span>
          </div>  
          <div ng-show="selfShow.isShowManyTips && manyTips.length>0" style="position:absolute;top:0;display:flex">
            <img 
              src="{{servicePicture.triangle}}" 
              style="width:14px;height:14px;position:relative;z-index:3;left:5px;"
            >
            <div style="width:200px;border:1px solid #DCDCDC;position:relative;top:-5px;left:3px;padding:5px;">
              <div ng-repeat="li in manyTips" ng-bind="li"></div>
            </div>
          </div>
        </div>
      </div>
      `;
    return {
      restrict: 'E',
      template: html,
      scope: {
        //以下是16种配置项。这是输入框组件,适用于密码输入、普通输入(isPastInput/isFirstInput:true)、旁边提示和弹窗提示。
        labelWidth: '@labelWidth',//标签宽度
        labelText: '@labelText',//标签文字
        placeholder: '@placeholder',//输入框内提示文字
        thisType: '@thisType',//输入框类型(文字或密码)
        keyOfRegExp: '@keyOfRegExp',//会用到的正则
        isMustFill: '=isMustFill',//该项是否必填
        isDisabled: '=isDisabled',//该项是否禁用
        isPastInput: '=isPastInput',//该项是不是原密码xxxxxxxxxxx
        isFirstInput: '=isFirstInput',//该项是不是第一次输入新密码xxxxxxxxxxxx
        selfData: '=selfData',//自身数据============
        siblingData: '=siblingData',//兄弟数据===============
        oneTip: '=oneTip',//单条提示
        manyTips: '=manyTips',//多条提示
        selfShow: '=selfShow',//自身的提示是否显示出来============
        siblingShow: '=siblingShow',//兄弟的提示是否显示出来=============
        verify: '=verify',//verify是函数,但按照变量传进来更好xxxxxxxxxxx
      },
      replace: true,
      controller: function ($scope, serviceRegExp, servicePicture) {
        $scope.servicePicture = servicePicture;
        $scope.inputChange = function (params, message) {
          var params = params;
          var config = {
            init: [false, false, false],
            focus: [false, false, true],
            empty: [true, false, false],
            formatError: [true, false, false],
            different: [true, false, false],
            wrong: [true, false, false],
            success: [true, true, false],
          };
          $scope.selfShow.isShowOneTip = config[params][0];
          $scope.selfShow.isGreenOneTip = config[params][1];
          $scope.selfShow.isShowManyTips = config[params][2];
          $scope.singleTipText = ($scope.oneTip && $scope.oneTip[params]) || message;
        };
        $scope.focus = function () {
          if($scope.isPastInput){
            $scope.inputChange('init');
            return
          }
          if($scope.isFirstInput){
            $scope.siblingData='';
            $scope.siblingShow = {
              isShowOneTip:false,
              isGreenOneTip:false,
              isShowManyTips:false,
            };
          }
          $scope.inputChange('focus');
        };
        $scope.changeOrBlur = function () {
          if ($scope.isMustFill && $scope.selfData=="") {//判断该项是否可以为空
            $scope.inputChange('empty', '该项不能为空!');
            return
          }
          if ($scope.keyOfRegExp && !(serviceRegExp[$scope.keyOfRegExp].test($scope.selfData))) {
            $scope.inputChange('formatError', '格式错误!');
            return
          }
          if (!$scope.isPastInput && !$scope.isFirstInput && $scope.selfData != $scope.siblingData) {
            $scope.inputChange('different', '两次密码输入不一致!');
            return
          }
          if(angular.isFunction($scope.verify) && !$scope.verify()){//验证原密码是否正确
            $scope.inputChange('wrong', '原密码输入错误!');
            return
          };
          $scope.inputChange('success', '输入符合要求!');
        };
      },
      link: function (scope, ele, attrs) {
       
      }
    };
  });
  app.factory('serviceRegExp', function () {
    return {
      simplePassword: /^[a-zA-Z][a-zA-Z0-9]{4,24}$/,//简单密码验证,以大小写字母开头,由大小写字母和数字构成的,共5-25位的密码
      complexPassword: /^(?![a-zA-z]+$)(?!\d+$)(?![!@#$%^&*?_|~=+\-<>[{}/\'\":;,.\]*]+$)(?![a-zA-z\d]+$)(?![a-zA-z!@#$%^&*?_|~=+\-<>[{}/\'\":;,.\]*]+$)(?![\d!@#$%^&*?_|~=+\-<>[{}/\'\":;,.\]*]+$)[a-zA-Z\d!@#$%^&*?_|~=+\-<>[{}/\'\":;,.\]*]{6,25}$/,//复杂密码验证,同时包含字母、数字、特殊符号如!@#$%^&*?_|~=+\-<>[{}/\'\":;,.\]
      ipFrom0To255: /^(1\d{2}|2[0-4]\d|25[0-5]|[1-9]\d|\d)\.(1\d{2}|2[0-4]\d|25[0-5]|[1-9]\d|\d)\.(1\d{2}|2[0-4]\d|25[0-5]|[1-9]\d|\d)\.(1\d{2}|2[0-4]\d|25[0-5]|[1-9]\d|\d)$/,//ip地址验证,从0.0.0.0~255.255.255.255
      portFrom0To65535:/^([0-9]|[1-9]\d{1,3}|[1-5]\d{4}|6[0-4]\d{3}|65[0-4]\d{2}|655[0-2]\d|6553[0-5])$/,
      mac:/^[A-Fa-f\d]{2}:[A-Fa-f\d]{2}:[A-Fa-f\d]{2}:[A-Fa-f\d]{2}:[A-Fa-f\d]{2}:[A-Fa-f\d]{2}$/,
      mobilePhone: /^1[3456789]\d{9}$/,//手机号码验证,中国大陆
      numberNotLimit: /^(0|[1-9][0-9]*)$/,//0或非0开头的数字
      numberWithLimit: /^(0|[1-9][0-9]{3,4})$/,//0或非0开头的数字4-5位
      emailNotLimit: /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/,//邮箱验证
      chineseCharacters: /^[\u4e00-\u9fa5]{0,}$/,//汉字验证
      blankSpace: /^\s*$/ //零到多个空格
    };
  });
  app.factory('servicePicture', function () {
    return {
      eyeClose: 'data:image/png;base64,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',
      eyeOpen: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAAXNSR0IArs4c6QAACXFJREFUeAHtmXtsVEUUh3eXttgCVUCIxVc0+EDFiKUoAoJURdDyVkEjERFKKSgP0fpCFI2oGCC0UKo8JQpNEFEEgUZAUUCKAlYe1igGoVJQEajQJ35n07vMvTu7vbvd9R/vJJOZOXPOmXN+M3Pm7F2XyykOAg4CDgIOAg4CDgIOAg4CDgIOAv9HBNzRdnrcuHHxZWVlt7LO7dS2bre75dmzZ1vQb0k/kX4Z7Qna47TFtHtpf4iNjd2UnZ19ONr2RQWAkSNHipPDMP5e2hTauHAcAYg9yK9FdkleXt634eioSyaiAIwYMeIWjB6N0Q+wcFhOBzF4t8fjeSc+Pn7e9OnTTwfhC2kqIgCkp6cPZtXxON4+pNXDYAbgUurbgDGbcioMFSaRegHAjl+LtlxqV5PW/2ZwFBCy5syZswBAzoa7ZFgAjBkzpmFFRcVz7HgWC4d81DF4D3LraLfQVqJnLFWCZMilVkfG3Llzd4UsjEDIAHDcxdB3MfiqUBbE0CpkZrNrb+bm5h5SZSV2MN6q0kLsV6B3AnqzQ5RzxYQigPNyz99EpoFG7h9oCRq6kDY0aNAgkzu7VzeP8a1ramp0U3ZpccjPwr7bmjRpMnzatGlldgVtnQB2SBybRx2kUfwPu/si9D4BjvHyVq1aDZo8eXKVKjtq1KiLqqurO0Prj5y8GjpQVRG1f4TBp9ShVJMP2CJP5wCezX2qQKC+SVjHhPNJ0D+j3qiZX8fupUNvyQ5ss85jzOqkpKQ+qvMZGRldcfwNeOXYh13Q3ZO13az7Hg43VxUxd4o6jCuRr9J1fY+OaNBGjx59BYo2M7Y6XwE9HZR7sMgBjBhnyCjtSbK54arzgDkT5zfCUy/na9d4khdgTVxc3E3Y8pWyrgtAGmPTMq7EJJWu6wcEAOHriPSbUXalRfAIyHcn6uYJHQc9GNDDwuOC9oqaypIdvgbPE1a+cMfYlSpXc9asWb9xyrqhR2KT6TmE52V4Xg+2hhYAcR7hTQi2sgh/GxMTk8Ku+xAvLS1Nhrepha8yISFhvkETfezIs8Y4Qm0sG9FBdMkp4zQ+Q6DtC/CnLfqzWH+6heYb+gHAG38Js3LnL/Rx0UHx2kaNGnUmkh9U6VVVVR3VsfSFl3T1T4X+nJCVcUS6AG9amyvxMaD0ZH1ThgjfWE7CbFo/G0wAEKCalpeXfwbjpRYL13HM+gbIwU1AiRwGfG7Iszvn0R9ojCPZYqf8qjQVQNgECHdBPG6acLkyOAk5FprLBwAIxRKgPobhepUJZ9bzjEkkP6PSlb71+AsA3xvzJSUl7TC0oTGOZMs6iTp9gLBV4hRzxyzzGcSip1WaDwCUvc2EvMtq2cDO9w7ivDjrl0wB5G+KkrZKP6JdgPVb21iAOPUdINzBWL2KLmLRVECQvMNbvAAIAWVjDKK0OLafQNY/mPPCh9yv0lpKBnQ38USO6EjLXCSHKtB+egGhiKCdhi9qYHRj22J87iQCHu79NRAky1OLoJY2Y8YM6z1Sebx9lP/iR+S5Y4ETPKMH0d1OMx8REjusA9+km6D9NYTB1GpjApsaUleSjbb2cFznMmhsTNJWUgfyzhcrtGBd331XmUSnLKTSIt0HgO12dOLLSjZqlMqLbc3xPVuugPWOlpDB7VaZg/VRvgfldsEKpiqkOdY8xO7utCvEdXgH3r0W/hsEgKkW4mW87Z/Ix0wLPdjww2CT0ZhjB1eEopcncAr8bSwy73vIoN4CzQ/UCZR35Evu0vz8fFu/0DiK8lXG9GtP1ReFfjVZX8Dszroe8egRaM+rdOzdxQs3yfsK0HkMwhaVgX7vgoICv8TBwuMd8u7uBzQ5Yv9VeZ81f7azGPlNZ56+dy28JxnfLy+cFwDpAIDk0QcsjJyc9BcsNO2QUzCZib+1k5ElHuXL8EQ7KnnhroRProrpsx22jjCCvBcAUUaQkK+t8maekLFR2NkpgDDUGAdqRZ5jaXpuAvHWh84aj8+cOfNIXTrY+fOJ8qvgM6Xq+DcbW5ca8j4AhMBEEegMout7M2sZ8wChT20/YMOxXIP82IAM9ZxA93jWkHQ9aJEAjqPLYTIFPWirUlNTn1CF/YJcYWHhT+3bty+GWRw2AJLf/ANTUlIOMB/0iWT+G+Rlh3pQ/fSri9vts3YNzstHzzoDH9ln4pkzZ1ZzciUNVss2BmlZWVkVKlFr4I4dO4pwtggl/WA2eDyM+yYnJ//FvCgLWJgvRF5+EfaiqklWQJkgE4dxvh/Om14qHX9mZmbzysrK9dhp+pkM74/UO3nx/GKU4ZyfPnZyX4cOHXagbACTxo8ON/2egNAsLS2tYOPGjTV+grUE5A926dJlHjlFDDuYrOgIJGKiI3OamkNSNphjv8c0qRlwReWjSwH2mhI7dBSj424ALNGI1f2Rgje0O4rl3jVSFaD4SwLSA2Rjv6t0XZ+c+1J0DKE+zLzpXmr4d6J7Bbrz7OgWeWwcgOMLqabThp5Cvhn24rPZUc06XpLsaJ2FBTqhXO5VooX5MIs8ypOy3kIPOJQvTpyKtoDRBtl4Wjkh8uOrGGOL5BtfQGHLBLrkH6pXsespy5QMC/gl2A8QT2nmfCRbAAg3u9gGwz+ie7VP+lxnPj+dJ9j59XhOpH49njn5sryA6neiAHQZyd0Q8htTwNOtaBsAEZa3FeVLQPw+jTK5Y5P4erSQhaOWFtf+ofIiNqSznl8Mw74ZOD8BGwLGJ9X2kAAQQRZ2k2FNpH2F2lBVVtv/ifYlgMiPJBCALwmN5BhSTfGIsXzAOUgdTrBbK2O7JWQADMXEhRu4v4sY32zQ1BZjfgegxQSz+UTx/eqc3b6AzY7fzjqy2/IXmg5wUTefOl73zMlksBI2AKKUXYmlkR2RX1rnUwOVfUxson4BMNsJdkcIdidUZnGWkyWf0C6mtsNp+bKbShWatqDrEDnCcMlAtQw2iPUCwNAvxxNjJuGEfP8TUOos8JfDVEr9E7mmtElUW7LwyY+3XH4UvVzfwBsRADDIW8jELuelyMShYRCa1ZIj1uC0nJoF6H+D414SCcURBcAwiBORQP8h6oPUrlS7OwurX5EfZluoixITEz8I5b9/P00aQlQAUNeRHyfk5/dwp7tBlzRVarB4Icd7N7v8He1mkpk1OTk5fyATlRJ1AHRWc0KScOwCQGnCvKSv5Th7jIB2rEWLFn/ZfcN1uh2ag4CDgIOAg4CDgIOAg4CDgIOAPQT+BekJrkwYCCycAAAAAElFTkSuQmCC',
      correct: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAAXNSR0IArs4c6QAACZBJREFUeAHdGgtQVNf13LfL8lEUCopOrUFAUEKIttISRaQ1TjOZxjaET2HBZBhLTJoYY6M2pqJT22k1NanENNVYohVW64I2TduJITPBf2mGiAZMICAq1h+0KLvyWXbf7bmPWdzH2+/bt7BwZ+Ddd849555z9txzz7n3EfBxe6giP9zIDSwmFvogBUigQBMIgQhKSShOzf5YMxBCDRRIJ6HQTACaqIo0TuQDTn6u1XUNDvHNf5xL+TZL91QyoSSfp3QZAJkHQDl5sxAeaes5Qqopobq2/KoL8vg4plLMAMnHCid0d/atJECLKKXJjqeUj0Fhz1MCZRGTIvbWPbGnRz6n+5ReGyDun9pJljumF4HSNah45H3WvusRQjqR+5uq8MBdLY9XdHszk1cGQFcvAEp+h4pHeSOEfFpykyPwyiVtZYVcHrIMEFelnWHp6y9HxZfInVhZOlKj0ZCC5hz9fzzl67EB4g7lpprNlqMYnKZ5OpmPx98AFTx5Oa+q1pN5PIrOsyqyCy0Wc40fKs90ng4WUiMsSw8s4JYBttAtXIwuaxul/J8phUAP+I/wUBpEeTgQU5H1WyazO5O7XAKM0T5dgx6jfKY7DP1lDAFS+bQ2KXcL2YK5hOOmcowaxFyZHbENeytdjfNDfOKFho6griMXP3Ymm1MPmFWRtQIj/X5nDPwdRzgoxAyy3JGcDg3Aoj0LeP695h2pZQsnfaCiGY52B7sGYPu8ubf/Uz+N9rbaudu/odFwKfbyBLuR0tLXh5mV3+3z7iprb9x0k4naXQYSAwyue0i3x2Vsw2iGvRxBtARiDmdPpia+Gev2qWNbWfvSYxF1CwuoeNsCSuQBdICuHq/KM5Owok2oXG3sM+QBQj3f0XMFcRE2+HHXZaV0aGRw9IXvH7jHlBvyAGNnTzG+j2vlmcLoBZHs4Ib1WRsyAO73RYOg8f+fnVpZtRQMMLsiex6u/SQrcLw/0QuSZx3KfZjpKRjADFQ7FpUujH8MypeWQPHc5R6LT3hLPiNSC5TC6a3HPEaV4JcpK4EZgLVF05JBowqAXQ1VbsvEU8ATa9hA5hxZEdHXe68D8FDebepRHKgmKtix8AVYHr1YJEW78Rakv/9TEcz5C+EnaMgU9UB/b/pYUT5QpYE/Ln4FMr7+TYlu5zqbJTDnAMrdG4DFap6nDzof6B/Y0IAQKMvYCAumzpEIdPZmA2ys3S2BuwJgTpCkxl8/wdXA0cZHBk2G/d/bBInh0RJRPmr/N7x46g0w8WYJziWA8gkYBKlfG2DGhKlwYOkmiA6dLtGnsvUT2FD7DvB4ECirURKvxtiHtzmYBchskzQT4KWHciAqOBz+0HgULna1yeQkJZs9+RtwAH/5qJCvSZB7v/gAfv3ZfgncEwDeN0aq8aY2FLNAWU3DBYB+2VaID5sp0KfhdrT8ww1wFSOyt21exGx477sbISzQeoF8n+Pr9To09pH7AJk9vIkO5VD5iTLpITkidkh5xmNy4ETYnb4eglXenZwzQ1Y8ulmiPHP11zDYKaE8k5cSEipkguxFTvvq7jXoNglF1RD5nPAHYPsjzw+9e9p5fOYj8KeMVyFEHSQiHcAgt/rU70HXUi2Ce/uCV+9glMvkrskIa8+UsgpLxOIHDyyCVYk/EsHcecmLexTeSntZyOpsx/ea+2FlzW/gH1fP2IK97hNKDaqwzMTnkFO4XG5thhsCaWqUuJZaOC0JznU0ux0PmME2LygC3JtFotztN8KKT34FtbcviuCKvBBgt8uU3bV71XZ+rofqa3iIbNM4PJAvTVsDbBtz1V6dXwgb5hdIht3u7YLcj0vA8yxPwsouAL9i6eTQ5J7mkHaZrT1dCq3d4ttpFsH3LFkPQZjC2mvMSNtSn4PixB9K0FcMNyHro9eg6c5VCU4xAKHNLAg2KcHQaO6F4uPbwDjQK2I3F7O37anSoKjh1PB22lrIiV0qGs9evui6jMr/AtqNtyU4RQGEa8IlAI1KMb3Ufd1uUHwiOg1+YlOzswhfhnv8YzNTJVPXdXwJudUl0Nl3R4JTGoDu36iakvVwhwUs65C5OPrInI0Zgbn2d6LENdZCDJJ1nU1gMPVgalsCKVPnSmY4fv0cFGG07zH3SXCKAzD4BQaHvCAojZch59kxkZKT7F3yc1g6Y4GIJYvoXf0GiJ4kzes/uHwKvectMFOLiMZnL4TUX9ZWzh9MhAgom12g1C9jfsC8wbaxTNGe8uXNx+Cl0ztHTnkUCnMAQWfBACpOpbMVVIm+YaAHnj2+He4NC4rDebNjrE2fvovlmDiZGj5O6Xc14QSdBQO0/Pgvn+F2qFgwtArb0n0NfnZ2lyRTZHiWPW6t2wc7zh+0Dh+xJ677hq+0+no24eASYB1CynwhwbH2Wviw/V8i1hbeAuvOvg1lX/5dBB+pF0w2h3QdMkCwGvagF/zPF0I8f3IHnLwuGFzIE1adeB2q2mp8MZU7PP8bHMC9ax0o2vqiK7I2o29usSKVfoZjZtiDhU2/xaQ0a7f5Ya1R0qat3GolGPIABggLmbgTB3RYkUo/2RY4qsoD3CYBpNRWL5EB6p/cdwezo/W2A8ZTHz/aX38pR3/XVifREmAIjM4kRpd9Ap9ptgPHeh+/GzzZVlCZPlwPkQcwJC4Bim6iRcv4uBIZLorv3lGnW5xKrbU3g8QAbBC6yVUOVJlIOHrRyp60MmBMB46DzNa8Q+32yO0agA1sLTh8GvfLVfaIxhIMY9qzrXmVZxzJ7NAAjOBSfuV7uCbedETs73DCkR2tWv0+Z3I6NQAjTAkg6zCA/M0ZE7/EEfjr03lJLnc0lwbQ5+gtCzQkcyx5Ai7dN1ICuCxXX4qzH06yDTr7NWMOPlVEefIObpEaZ+NGCycEPLbmXbi9rXweGYARxpbnLOLBcgSLV9fHvbYz+bgvbHVCtHcc8OyJ4HIJDCcSdgf88Bjd7PRw3Gi9o/KnMHf5trNo70g2jz3AyohljLEHs5/Bsn479vGGeeQbKt7BUveW/MP7sS/rREW2Aazqzjv6TFh3j3END7Aa82jZN0xWfm49B8v2Ula8sfrFLRoHg7w2gJVvwvtFoSZDdzH+DEVYUSRa4co+yUUUuCxEQ3Y35uhl32nayqSYAWyZxlZkf4sHPh83mWV41peEx33y5sGja8xBGtCg1RxwOozudbbzKNGXJ5gHM8cdzp7Cm0k6D/gxFn6TgwrFo1Ei0SihuG6Frx8whhjQRAbEdSKuGdiNDV5acGp6oiVH77PzCabG/wG2eybyIe8HlAAAAABJRU5ErkJggg==',
      error: 'data:image/png;base64,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',
      triangle: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAoCAYAAAD+MdrbAAAAAXNSR0IArs4c6QAAAvpJREFUSA2tl7uLE1EUxmcmk6cJ2WTzQDBBBGEVbBR8oY3IglraiCCWVlaipa1iLVYW7oKVIuL6YC0s7f0T8jQmhAghD/L0+wZnPJPE3TvJXpi9Z07u+c059373zqyuHVCbTqd6qVR6diA4wMxisbhVKBSm+qrEarUaGQ6Hb8C5TtZKQJSYnEwmH8G5QBjb0sByuXxkPB7vgnHSIv39Y8gbVRtlnkBm3zHeBQsEAt4zRGbnAfuEhUjKBEKhkJZOp70BMWfXAHqLKyJhkUhES6VSlku5ZGR2B6APs7BYLObASFQCQmMPUOYWYKbMLB6Pa4lEQrr2LhkAHbCniHgko3Rdt0DRaFS6Ldv1RPkrs8GcvYTvrvQTxvkKh8PS7dgLdQhQGCVS/TeckTAMw7BWMhgMSrfLngNiP3JSqP6LcqTP59MymYzm9/ule872SQ/Vj/tvuM5Iv2maWjab3RfGGCdDqH9jNBrtYu7yEkb1MzOWq9IsIObsHEBU/7oMctSPhVBtOubsGFbuB2AuDUj1q8I4zgTsySyM6p8VrCrUBOyyHEz181q2caZdsw39Lcuy4gj7KgntdltrNpvS5ck2sJIPEfFTRnU6Ha1er2uYDulWsg0I9he0dhWLU5YR/X7fgnqdAkdglUolB2Gz/A0J5lajsLn1VJoD5GBsvXVk9BmlnpXB3Ho83vfbx4xxAemo1WqHBoPBO0A3eW83bj1myq24V5sDcjBgfmzHbfS3ZDChPAu5Jf/XXBq0B2GBhrlc7jb657aPPReo0Who3W5Xul32QiBHADbN5/P30T+WEcja0in1uqgtLHl2IA6QewC/AMyVwKJtqgTkAzCnN1Hya5iu858vqmTy3ztfGUgoZHUF3zPvYcZ4bzd51HkCEoCT/TQ+377AzNhA9s5hLJ2qNso/jvK5q47KmKU+lmwA5HO41+vxHXTK9rH3XLIMbrVaa5DPDqCXbL9LBrZTtcdr4jfktIlrRzVGaRwy5Ef7K+h19Y92+4mAWv9W/AHAizQaNQfgsAAAAABJRU5ErkJggg=='
    };
  });
</script>

二、input-select(自定义输入框和下拉框,可预览)
使用场景:有个select标签,选择其中的一项,向后台发送请求,然后根据后台返回的数据,渲染input或select标签,如果是select,还可以继续选择。。。
<!DOCTYPE html>
<html lang="en" ng-app="myModel">

<head>
  <meta charset="UTF-8">
  <title>input和select</title>
  <script type="text/javascript" src="https://cdn.bootcss.com/angular.js/1.6.2/angular.js"></script>
</head>

<body>
  <div ng-controller="thisCtrl">
    <div>
      <p>=====可预览=====</p>
      <p>1、向后台发送请求,获取返回数据,填充$scope.formDatas</p>
      <p>2、向后台发送请求,获取返回数据,填充$scope.formDatas</p>
    </div>
    <input-select ng-if="formDatas.length>0" form-datas="formDatas">
    </input-select>
  </div>
</body>

</html>
<script>
  var app = angular.module('myModel', []);
  app.controller('thisCtrl', function ($scope/*,cyRequest*/) {
    //此处,向后台发送请求,获取返回数据,填充$scope.formDatas
    $scope.formDatas = [
      { 
        type: 'input',
        inputLabel: '输入框',
        inputValue: '',
      },{
        type: 'select',
        selectLabel: '选择框标签',
        selectValue: '后台1',
        selectOptions: [
          { back: '后台0', front: '前端0' },
          { back: '后台1', front: '前端1' },
          { back: '后台2', front: '前端2' },
          { back: '后台3', front: '前端3' },
          { back: '后台4', front: '前端4' },
          { back: '后台5', front: '前端5' },
        ],
        selectChainThis: [],//默认值。
        selectChainNext: null,
        children: [],//子级。
      },{
        type: 'select',
        selectLabel: '选择框标签2222',
        selectValue: '后台1',
        selectOptions: [
          { back: '后台0', front: '前端0' },
          { back: '后台1', front: '前端1' },
          { back: '后台2', front: '前端2' },
          { back: '后台3', front: '前端3' },
          { back: '后台4', front: '前端4' },
          { back: '后台5', front: '前端5' },
        ],
        selectChainThis: [],//默认值。
        selectChainNext: null,
        children: [],//子级。
      }
    ];
  });
  app.directive('inputSelect', function () {
    var html = `
        <div style="margin-left:10px;">
          <div ng-repeat="formData in formDatas track by $index">
            <div ng-if="formData.type==='input'" style="margin:10px 0">
              <label ng-bind="formData.inputLabel+':'" style="width:200px;text-align:right;display:inline-block"></label> 
              <input ng-model="formData.inputValue" type="text" style="width:300px;border:1px solid gray;height:26px;border-radius:4px;"/>   
            </div>
            <div ng-if="formData.type==='select'" style="margin:10px 0">
              <label ng-bind="formData.selectLabel+':'" style="width:200px;text-align:right;display:inline-block"></label>
              <select  
              ng-model="formData.selectValue" 
              ng-options="option.back as option.front for option in formData.selectOptions" 
              ng-change="clickOption(formData)"
              style="width:306px;border:1px solid gray;height:26px;border-radius:4px;"
              ></select>
              <input-select ng-if="formData.children.length>0" form-datas="formData.children"></input-select> 
            </div>
          </div>
        </div>
      `;
    return {
      restrict: 'E',
      template: html,
      scope: {
        formDatas: '=formDatas'
      },
      replace: true,
      controller: function ($scope) {//此处注入“公共请求服务”
        $scope.clickOption = function (formData) {
          var objOuter={};
          objOuter[formData.selectLabel] = formData.selectValue;
          formData.selectChainNext = angular.copy(formData.selectChainThis);
          formData.selectChainNext.push(objOuter);
          //此处,把formData.selectChainNext作为“公共请求服务”的参数,向后台发送请求,获取返回数据result并加工,然后填充formData.children
          var result=[
            {
              type:'input',
              label:'输入框'
            },{
              type:'select',
              label:'选择框标签'
            },{
              type:'select',
              label:'选择框标签2'
            }
          ];
          angular.forEach(result,function(value,index){
            var objInner = { };
            if(value.type==='input'){
              objInner.type = value.type;
              objInner.inputLabel = value.label;
              objInner.inputValue = '';
            }else if(value.type==='select'){
              objInner.type = value.type;
              objInner.selectLabel = value.label;
              objInner.selectValue = '后台1';
              objInner.selectOptions = [
                { back: '后台0', front: '前端0' },
                { back: '后台1', front: '前端1' },
                { back: '后台2', front: '前端2' },
                { back: '后台3', front: '前端3' },
                { back: '后台4', front: '前端4' },
                { back: '后台5', front: '前端5' },
              ];
              objInner.selectChainThis = angular.copy(formData.selectChainNext);
              objInner.selectChainNext = null;
              objInner.children = [];
              if(index===1){
                console.log(objInner.selectChainThis)
              }
            }
            formData.children.push(objInner)
          })
        };
      },
      link: function (scope, ele, attrs) {

      }
    };
  })
</script>

三、only-select(两种)
<!DOCTYPE html>
<html lang="en" ng-app="myModel">
<head>
  <meta charset="UTF-8">
  <title>onlySelect</title>
  <script type="text/javascript" src="https://cdn.bootcss.com/angular.js/1.6.2/angular.js"></script>
</head>
<body>
  <div ng-controller="thisCtrl">
    <div>一、此消彼长式</div>
    <div>使用场景:</div>
    <div>有上下两行数据,上行有很多备选项</div>
    <div>每点击上行的某项,则该项“会”消失并在下行出现</div>
    <div>每点击下行的某项,则该项“会”消失并在上行出现</div>
    <div style="margin-bottom:20px;">
      <span ng-click="getDataUp()" style="border-radius:5px;padding:2px;background:gray;">点击获取选中数据</span>
      <span ng-bind="selectedDatasUp"></span>
    </div>
    <div style="width:1000px;">
      <only-select-up form-datas-up="formDatasUp" current-datas-up="currentDatasUp" two-label-up="twoLabelUp"></only-select-up>
    </div> 
    <div style="width:1000px;border:1px solid gray;margin:100px 0"></div>
    <div>二、固定+动态增减</div>
    <div>使用场景:</div>
    <div>有上下两行数据,上行有很多备选项</div>
    <div>每点击上行的某项,则该项“不”消失并在下行出现,重复点击无效</div>
    <div>每点击下行的某项,则该项“会”消失,但对上行无影响</div>
    <div style="margin-bottom:20px;">
      <span ng-click="getDataDown()" style="border-radius:5px;padding:2px;background:gray;">点击获取选中数据</span>
      <span ng-bind="selectedDatasDown"></span>
    </div>
    <div style="width:1000px;">
      <only-select-down form-datas-down="formDatasDown" current-datas-down="currentDatasDown" two-label-down="twoLabelDown"></only-select-down>
    </div> 
  </div>
</body>
</html>
<script>
  var app = angular.module('myModel', []);
  app.controller('thisCtrl', function ($scope) {
    $scope.formDatasUp = [
              {
                value: '0',
                label: '选项一'
              },
              {
                value: '1',
                label: '选项二'
              },
              {
                value: '2',
                label: '选项三'
              },
              {
                value: '3',
                label: '选项四'
              },
              {
                value: '4',
                label: '选项五'
              }
            ];
    $scope.currentDatasUp = [];
    $scope.twoLabelUp = ['上面标签:','下面标签:'];
    $scope.getDataUp = function(){
      $scope.selectedDatasUp=angular.copy($scope.currentDatasUp);
    };
    ////////////////////////////////////////////////////////////////////////////////////////
    $scope.formDatasDown = [
              {
                value: '0',
                label: '选项一'
              },
              {
                value: '1',
                label: '选项二'
              },
              {
                value: '2',
                label: '选项三'
              },
              {
                value: '3',
                label: '选项四'
              },
              {
                value: '4',
                label: '选项五'
              }
            ];
    $scope.currentDatasDown = [];
    $scope.twoLabelDown = ['备选项:','被选项:'];
    $scope.getDataDown = function(){
      $scope.selectedDatasDown=angular.copy($scope.currentDatasDown);
    };
  });
  app.directive('onlySelectUp', function () {
    var html = `
        <div>
          
          <div style="width:100%;height:30px;line-height:30px;border:1px solid green;padding:5px;">
            <span ng-bind="twoLabelUp[0]"></span>
            <span ng-repeat="upData in upDatas track by $index" ng-bind="upData.label" ng-click="clickUpUp(upData.value)" style="border-radius:5px;display:inline-block;margin-right:10px;padding:2px;background:gray"></span>
          </div>
          <div style="width:100%;height:30px;line-height:30px;border:1px solid red;padding:5px;">
            <span ng-bind="twoLabelUp[1]"></span>
            <span ng-repeat="downData in downDatas track by $index" ng-bind="downData.label" ng-click="clickUPDown(downData.value)" style="border-radius:5px;display:inline-block;margin-right:10px;padding:2px;background:gray"></span>
          </div>
        </div>
      `;
    return {
      restrict: 'E',
      template: html,
      scope: {
        formDatasUp: '=formDatasUp',
        currentDatasUp: '=currentDatasUp',
        twoLabelUp: '=twoLabelUp',
      },
      replace: true,
      controller: function ($scope) {
        $scope.upDatas = angular.copy($scope.formDatasUp);
        $scope.downDatas = [];
       
        $scope.clickUpUp = function (valueOuter) {
          angular.forEach($scope.upDatas,function(value,index){
            if(valueOuter===value.value){
              $scope.upDatas.splice(index,1);
              $scope.downDatas.push(value);
              $scope.currentDatasUp.push(value.value);
              console.log($scope.currentDatasUp)
            }
          })
        };
        $scope.clickUPDown = function (valueOuter) {
          angular.forEach($scope.downDatas,function(value,index){
            if(valueOuter===value.value){
              $scope.upDatas.push(value);
              $scope.downDatas.splice(index,1);
              var thisIndex=$scope.currentDatasUp.indexOf(value.value)
              if(thisIndex>-1){
                $scope.currentDatasUp.splice(thisIndex,1);
              }
              console.log($scope.currentDatasUp)
            }
          })
        };
      },
      link: function (scope, ele, attrs) {

      }
    };
  });
  app.directive('onlySelectDown', function () {
    var html = `
        <div>
          
          <div style="width:100%;height:30px;line-height:30px;border:1px solid green;padding:5px;">
            <span ng-bind="twoLabelDown[0]"></span>
            <span ng-repeat="upData in upDatasDown track by $index" ng-bind="upData.label" ng-click="clickDownUp(upData)" style="border-radius:5px;display:inline-block;margin-right:10px;padding:2px;background:gray"></span>
          </div>
          <div style="width:100%;height:30px;line-height:30px;border:1px solid red;padding:5px;">
            <span ng-bind="twoLabelDown[1]"></span>
            <span ng-repeat="downData in downDatasDown track by $index" ng-bind="downData.label" ng-click="clickDownDown(downData,$index)" style="border-radius:5px;display:inline-block;margin-right:10px;padding:2px;background:gray"></span>
          </div>
        </div>
      `;
    return {
      restrict: 'E',
      template: html,
      scope: {
        formDatasDown: '=formDatasDown',
        currentDatasDown: '=currentDatasDown',
        twoLabelDown: '=twoLabelDown',
      },
      replace: true,
      controller: function ($scope) {
        $scope.upDatasDown = angular.copy($scope.formDatasDown);
        $scope.downDatasDown = [];
        $scope.clickDownUp = function (data) {
          var thisIndex=$scope.currentDatasDown.indexOf(data.value)
          if(thisIndex>-1){
            return
          }else{
            $scope.downDatasDown.push(data);
            $scope.currentDatasDown.push(data.value);
          }
        };
        $scope.clickDownDown = function (data,index) {
          $scope.downDatasDown.splice(index,1);
          var thisIndex=$scope.currentDatasDown.indexOf(data.value)
          if(thisIndex>-1){
            $scope.currentDatasDown.splice(thisIndex,1);
          }
        };
      },
      link: function (scope, ele, attrs) {

      }
    };
  })
</script>
四、on-off组件(真实逻辑,点击后,转圈、向后台发送请求、返回数据、给开关赋值、开关展示状态。点击后,立即改成相反状态,是不对的。)
<html lang="en" 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>
  <style>
    table{
      border-collapse: collapse;
      width:1000px;
    }
    table td,table th {
      padding: 5px;
      border: 1px solid #cbcbcb;
    }
    table thead {
      background-color: #e0e0e0;
      color: #000;
      text-align: left;
    }
  </style>
</head>
<body>
  <div ng-controller="thisCtrl">
    <on-off this-switch="parentSwitch">
      <span>{{parentSwitch.state?"总开关已开启":"总开关已关闭"}}。总开关关闭时,不能操作分开关!</span>
    </on-off>
    <table>
      <thead>
        <tr>
          <th>序号</th>
          <th>数据1</th>
          <th>数据2</th>
          <th>数据3</th>
          <th>开关1</th>
          <th>开关2</th>
        </tr>
      </thead>
      <tbody>
        <tr ng-repeat="item in tableDatas track by $index">
          <td ng-bind="$index+1"></td>
          <td ng-bind="item.value1"></td>
          <td ng-bind="item.value2"></td>
          <td ng-bind="item.value3"></td>
          <td>
            <on-off parent-switch="parentSwitch" this-switch="item.value4"></on-off>
          </td>
          <td>
            <on-off parent-switch="parentSwitch" this-switch="item.value5"></on-off>
          </td>
        </tr>
      </tbody>
    </table>
  </div>
</body>
</html>
<script>
var app = angular.module('myModel', []);
app.controller('thisCtrl', function ($scope) {
  //以下通过向后台请求,获取总开关的数据fromServerParent,经加工后为$scope.parentSwitch
  var fromServerParent={
    isOn:true
  };
  $scope.parentSwitch={
    state:fromServerParent.isOn,
    callback:function(){
      this.state=!this.state; 
    }
  };
  //以下通过向后台请求,获取分开关的数据fromServerData,经加工后为$scope.tableDatas
  var fromServerData=[
    {value1:"数据1",value2:"数据2",value3:"数据3",isOn:true,isSwitch:true},
    {value1:"数据1",value2:"数据2",value3:"数据3",isOn:true,isSwitch:true},
    {value1:"数据1",value2:"数据2",value3:"数据3",isOn:true,isSwitch:true},
    {value1:"数据1",value2:"数据2",value3:"数据3",isOn:true,isSwitch:true},
    {value1:"数据1",value2:"数据2",value3:"数据3",isOn:true,isSwitch:true},
    {value1:"数据1",value2:"数据2",value3:"数据3",isOn:true,isSwitch:true},
    {value1:"数据1",value2:"数据2",value3:"数据3",isOn:true,isSwitch:true}
  ];
  var tableDatas=[];
  angular.forEach(fromServerData,function(value,key){
    var item={};
    item.value1=value.value1;
    item.value2=value.value2;
    item.value3=value.value3;
    item.value4={
      state:value.isOn,
      callback:function(){
       this.state=!this.state; 
      }
    };
    item.value5={
      state:value.isSwitch,
      callback:function(){
       this.state=!this.state; 
      }
    };
    tableDatas.push(item)
  })
  $scope.tableDatas=tableDatas;
});
app.directive('onOff', function () {
  var html = `
  <div style="display:flex;align-content:center;padding-bottom:10px;">
    <img ng-src="{{thisSwitch.state?onOff.yes:onOff.no}}" width="65px" height="30px" ng-click="clickSwitch()"/>
    <span ng-transclude style="height:30px;line-height:30px;padding-left:10px;"></span>
  </div>
  `;
  return {
    restrict: 'E',
    template: html,
    scope: {
      thisSwitch: '=thisSwitch',
      parentSwitch: '=parentSwitch',
    },
    transclude:true,
    replace: false,
    controller: function ($scope,onOff) {
      $scope.onOff = onOff;
      $scope.clickSwitch = function(){
        //以下总开关关闭时,不能操作分开关!
        if($scope.parentSwitch && !$scope.parentSwitch.state){
          return
        }
        $scope.thisSwitch.callback()
      };
    },
    link: function (scope, ele, attr) {
      
    }
  };
});
app.factory('onOff', function () {
  return {
    yes: 'data:image/png;base64,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',
    no: 'data:image/png;base64,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',
  };
})
</script>
 
五、angular1里用layui中的datetime示例
来源:https://www.layui.com/doc/modules/laydate.html#type
<dir-datepicker date-model="pagin_init.filter_option.beginTime"></dir-datepicker>
(function () {
  angular
    .module('common-dir')
    .directive('dirDatepicker', function () {
      return {
        restrict: 'E',
        template: '<input  type="text" class="form-control common-select-time" ng-model="dateModel"  id="{{dateInputId}}"  style="width:214px" ng-disabled="isDisable" />',
        replace: true,
        scope: {
          format: '@',
          dateModel: '=',
          isDisable: '=',
          callback: '&'
        },
        controller: function ($scope) {
          $scope.dateInputId = 'id' + Math.random();
          angular.element(document).ready(function () {
            var config = {
              elem: '#' + $scope.dateInputId,
              theme: '#007bff',
              trigger: 'click',
              done: function (value) {
                $scope.dateModel = value;
                angular.isFunction($scope.callback) ? $scope.callback() : '';
              }
            };
            if ($scope.format) {
              config.format = $scope.format;//自定义格式
            } else {
              config.type = 'datetime';//控件选择类型
            }
            laydate.render(config);
          });
        },
        link: function () {
        }
      };
    });
})();
控件选择完毕后的回调
点击日期、清空、现在、确定均会触发。回调返回三个参数,分别代表:生成的值、日期时间对象、结束的日期时间对象
laydate.render({
  elem: '#test',
  done: function(value, date, endDate){
    console.log(value); //得到日期生成的值,如:2017-08-18
    console.log(date); //得到日期时间对象:{year: 2017, month: 8, date: 18, hours: 0, minutes: 0, seconds: 0}
    console.log(endDate); //得结束的日期时间对象,开启范围选择(range: true)才会返回。对象成员同上。
  }
});

六、agular1实现京东购物车
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/4.1.1/css/bootstrap.css">
  <script type="text/javascript" src="https://cdn.bootcss.com/angular.js/1.5.8/angular.js"></script>
</head>
<body ng-app="myApp" ng-controller="myCtrl" style="margin:20px;" ng-cloak >
  <div>
    <label>全选</label>
    <input type="checkbox" ng-model="allCheck" ng-click="allChecked()">
    <span>总金额:{{ totalMoney() | currency:"¥"}}</span>
  </div>
  <table class="table table-bordered" ng-repeat="oneShop in allShops track by $index"  ng-init="outerIndex = $index" style="margin:30px auto">
    <thead>
    <tr>
      <th><input type="checkbox" ng-model="oneShop.checked" ng-click="shopChecked(oneShop,allShops)"></th>
      <th colspan="7">{{oneShop.shopName}}</th>
    </tr>
    </thead>
    <tbody>
      <tr ng-repeat="oneGoods in oneShop.shopGoods track by $index"  ng-init="innerIndex = $index">
        <td><input type="checkbox" ng-model="oneGoods.checked" ng-click="singleGoods(oneGoods,oneShop.shopGoods,oneShop,allShops)"></td>
        <td>{{oneGoods.goodsName}}</td>
        <td>{{oneGoods.price}}元/件,共</td>
        <td><span ng-click="add(oneGoods,oneShop.shopGoods,oneShop,allShops)" style="display: inline-block;width:25px;text-align: center; border:1px solid gray;user-select: none;cursor: pointer;">+</span></td>
        <td>{{oneGoods.number=oneGoods.number||1}}</td>
        <td><span ng-click="reduce(oneGoods,oneShop.shopGoods,oneShop,allShops)" style="display: inline-block;width:25px;text-align: center; border:1px solid gray;user-select: none;cursor: pointer;">-</span></td>
        <td>件,本商品共: {{oneGoods.singleMoney}}元</td>
        <td ng-click="delete(innerIndex,outerIndex,oneShop,allShops)" style="user-select: none;cursor: pointer;">删除</td>
      </tr>
    </tbody>
</table>
</body>
</html>
<script>
var myApp = angular.module("myApp", []);
myApp.controller("myCtrl", function ($scope) {
  $scope.allShops = [
    {
      shopName: "专卖店一:北京鸡",
      shopGoods: [
        {
          goodsName: "北京鸡1",
          picture: "images/allShops_01.jpg",
          price: 150.0,
          singleMoney: 150.0,
        },
        {
          goodsName: "北京鸡2",
          picture: "images/allShops_02.jpg",
          price: 119.0,
          singleMoney: 119.0,
        },
        {
          goodsName: "北京鸡3",
          picture: "images/allShops_03.jpg",
          price: 101.0,
          singleMoney: 101.0,
        },
      ],
    },
    {
      shopName: "专卖店二:北京鸭",
      shopGoods: [
        {
          goodsName: "北京鸭1",
          picture: "images/allShops_04.jpg",
          price: 89.0,
          singleMoney: 89.0,
        },
        {
          goodsName: "北京鸭2",
          picture: "images/allShops_05.jpg",
          price: 99.0,
          singleMoney: 99.0,
        },
      ],
    },
    {
      shopName: "专卖店三:北京鹅",
      shopGoods: [
        {
          goodsName: "北京鹅1",
          picture: "images/allShops_06.jpg",
          price: 289.0,
          singleMoney: 289.0,
        },
      ],
    },
  ];
  //点击加减按钮,数量加减;点击删除按钮,删除商品
  $scope.reduce = function (goods, allGoodsOfOneShop, oneShop, allShops) {
    goods.number--;
    if (goods.number <= 1) goods.number = 1;
    goods.singleMoney = goods.price * goods.number;
    goods.checked = true;
    $scope.singleGoods(goods, allGoodsOfOneShop, oneShop, allShops);
  };
  $scope.add = function (goods, allGoodsOfOneShop, oneShop, allShops) {
    goods.number++;
    goods.singleMoney = goods.price * goods.number;
    goods.checked = true;
    $scope.singleGoods(goods, allGoodsOfOneShop, oneShop, allShops);
  };
  //删除该件商品
  $scope.delete = function (innerIndex, outerIndex, oneShop, allShops) {
    console.log(innerIndex);
    console.log(outerIndex);
    console.log(oneShop);
    console.log(allShops);
    oneShop.shopGoods.splice(innerIndex, 1);
    if (oneShop.shopGoods.length <= 0) {
      allShops.splice(outerIndex, 1);
    }
  };
  /*所有商品总金额计算*/
  $scope.totalMoney = function () {
    var total = 0;
    angular.forEach($scope.allShops, function (outerItem) {
      angular.forEach(outerItem.shopGoods, function (innerItem) {
        if (innerItem.checked) {
          total += innerItem.price * innerItem.number;
        }
      });
    });
    return total;
  };
  /*单件商品选择*/
  $scope.singleGoods = function (
    oneGoods,
    allGoodsOfOneShop,
    oneShop,
    allShops
  ) {
    var flag = true;
    if (oneGoods.checked) {
      angular.forEach(allGoodsOfOneShop, function (innerItem) {
        if (
          innerItem.checked == false ||
          typeof innerItem.checked == "undefined"
        ) {
          flag = false;
        }
      });
    } else {
      $scope.allCheck = false;
      oneShop.checked = false;
      flag = false;
    }
    if (flag) {
      oneShop.checked = true;
      angular.forEach(allShops, function (outerItem) {
        if (
          outerItem.checked == false ||
          typeof outerItem.checked == "undefined"
        ) {
          flag = false;
        }
      });
    }
    if (flag) {
      $scope.allCheck = true;
    }
  };
  /*单家商铺选择*/
  $scope.shopChecked = function (oneShop, allShops) {
    if (oneShop.checked) {
      var flag = true;
      angular.forEach(oneShop.shopGoods, function (innerItem) {
        innerItem.checked = true;
      });
      angular.forEach(allShops, function (outerItem) {
        console.log(outerItem.checked);
        if (
          outerItem.checked == false ||
          typeof outerItem.checked == "undefined"
        ) {
          flag = false;
        }
      });
      if (flag) {
        $scope.allCheck = true;
      }
    } else {
      $scope.allCheck = false;
      angular.forEach(oneShop.shopGoods, function (innerItem) {
        innerItem.checked = false;
      });
    }
  };
  /*全部商铺商品选择*/
  $scope.allChecked = function () {
    if ($scope.allCheck) {
      angular.forEach($scope.allShops, function (oneShop) {
        oneShop.checked = true;
        angular.forEach(oneShop.shopGoods, function (innerItem) {
          innerItem.checked = true;
        });
      });
    } else {
      angular.forEach($scope.allShops, function (oneShop) {
        oneShop.checked = false;
        angular.forEach(oneShop.shopGoods, function (innerItem) {
          innerItem.checked = false;
        });
      });
    }
  };
});    
</script>
 
七、angular1两种作用域绑定
angular1模块、控制器和作用域的两种绑定方式,模块不必通过ng-app关联到HTML的标签上,也不必通过angular.bootstrap()关联到HTML的标签上!
1、正常绑定 
<!DOCTYPE html>
<html ng-app="app">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script src="http://apps.bdimg.com/libs/angular.js/1.4.6/angular.min.js"></script>
<body>
  <div>
    <div ng-controller="myCtrl">
      {{ hello }}
    </div>
  </div>
  <script type="text/javascript">
    var module = angular.module("app", []);
    module.controller("myCtrl", function ($scope) {
      //app模块的控制器(myCtrl)将作用域的hello 赋值为 "a Angular app"
      $scope.hello = "a Angular app";
    });
  </script>
</body>
</html>
2、异常绑定
<!DOCTYPE html>
<html>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script src="http://apps.bdimg.com/libs/angular.js/1.4.6/angular.min.js"></script>
<body>
  <div id="app1">
    <div ng-controller="myCtrl">
      {{ hello }}
    </div>
  </div>
  <div id="app2">
    <div ng-controller="myCtrl">
      {{ hello }}
    </div>
  </div>
  <script type="text/javascript">
    var module1 = angular.module("test1", []);
    module1.controller("myCtrl", function ($scope) {
      //test1模块的控制器(myCtrl)将作用域的hello 赋值为 "a Angular app"
      $scope.hello = "a Angular app";
    });
    var module2 = angular.module("test2", []);
    module2.controller("myCtrl", function ($scope) {
      //test2模块的控制器(myCtrl)将作用域的hello 赋值为 "a Angular app"
      $scope.hello = " another Angular app";
    });
    /*此方法用于手动加载angularjs模板*/
    angular.bootstrap(document.getElementById("app1"), ['test1']);
    /*此方法用于手动加载angularjs模板*/
    angular.bootstrap(document.getElementById("app2"), ['test2']);
  </script>
</body>
</html>