Angularjs歸納與臺管理端中Angularjs的實踐

1、Angularjs 歸納

一、雙向綁定(第一印象)

<!DOCTYPE html>
<html ng-app>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>雙向綁定(第一印象)</title>
  <script src="http://cdn.tig.qq.com/js/lib/angular-1.3.15.min.js"></script>
</head>
<body>
  <input type="text" ng-model="msg">
  {{msg}}
</body>
</html>

二、MVC 模式

Mjavascript

Vphp

  • 數據模型變化驅動視圖視圖html

  • 聲明式 UI 結構vue

Cjava

  • 做用域 $scopereact

  • 做用域層級與繼承jquery

  • 做用域與事件系統angularjs

三、模塊與依賴注入

定義

var myMod = angular.module('myMod', []);
  • 爲何要使用模塊?bootstrap

  • 咱們須要使用其餘的協做模塊怎麼辦?後端

簡單回答開始的兩個問題:

問題一:若是不使用模塊,那隻能使用全局的控制器方式。污染全局變量,難以管理、維護、組織、複用代碼。
模塊化能夠解決這些問題,它帶來了命名空間和組織代碼,複用代碼等。

問題二:依賴注入解決模塊之間的協做問題。

低級版本Angular中使用controller不須要在模塊中註冊

<!DOCTYPE html>
<html ng-app>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>低級版本Angular中使用controller不須要模塊</title>
  <script src="http://code.angularjs.org/angular-1.0.1.min.js"></script>
</head>
<body>
  <p>低級版本Angular中使用controller不須要模塊</p>
  <div ng-controller="HelloCtrl">
    <input type="text" ng-model="data.msg"> {{data.msg}}
  </div>
  <script type="text/javascript">
    var HelloCtrl = function($scope) {
     $scope.data = {msg:123};
  }
  </script>
</body>
</html>

以後控制器的須要在模塊上註冊

<!DOCTYPE html>
<html ng-app="myMod">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>模塊上註冊控制器</title>
  <script src="http://cdn.tig.qq.com/js/lib/angular-1.3.15.min.js"></script>
</head>
<body>
  <div ng-controller="helloCtrl">
    <input type="text" ng-model="msg"> {{msg}}
  </div>
  <script type="text/javascript">
    var myMod = angular.module('myMod', []);
    myMod.controller('helloCtrl', function($scope) {
     $scope.msg = "msg";
    });
  </script>
</body>
</html>

模塊上註冊控制器

var myMod = angular.module('myMod', []);
myMod.controller('helloCtrl', function($scope) {
  $scope.msg = "msg";
});

模塊上註冊定義服務

  • myMod.value(...)

  • 服務

    • myMod.service(...)

    • myMod.factory(...)

    • myMod.provider(...)

    • myMode.constant(...)

除了 constant,其餘都是 provider 的封裝。

模塊的生命週期

  • 配置階段:收集對象建立的解決方案,並進行配置。 myMod.config(...)

  • 運行階段:執行全部初始化後的邏輯。myMod.run(...)

不一樣的階段與不一樣的註冊方法。

  • 配置階段能夠注入:常量值、Provider

  • 運行階段能夠注入:常量值、變量值、Service、Factory

模塊依賴

var myMod = angular.module('myMod', ['myMod2', 'myMod3']);

服務的跨模塊可見性

兄弟模塊之間能夠相互使用服務,也能夠覆蓋兄弟的服務。

四、指令

定義

myModule.directive('myDir', function(){
    return myDirDefine;
});

myDirDefine 是個對象,有幾個基本的屬性:

  • name 指令名稱

  • restrict 指令存在形式A(屬性attribute)、E(element)、C(class)、M(comment),常見的是 A 和 E

  • templte 指令模版字符串

  • templateUrl 指令模版的URL路徑

  • replace 是否使用模版內容替換指令現有的元素

  • tansclude 是否爲指令模版和編譯函數提供指令元素中的內容。vue.js中 稱之爲 slot(插槽)

  • scope 做用域

  • controller 指令控制器函數,做用:對外提供接口

  • require 設置須要注入的指令,也就是須要依賴的指令

  • link 連接函數:處理指令內部事務,好比 Dom 操做等

  • compile 編譯函數

指令與控制器的交互

  • 在指令上定義屬性與外部的控制器進行交互

例子1:

項目中使用(AngularUI 中翻頁指令的使用):

uib-pagination 翻頁指令和外部控制器的 方法 pageChanged(e) 須要進行交互

<uib-pagination total-items="groups.total" ng-model="currentPage" class="pagination-sm" ng-change="pageChanged(e)"></uib-pagination>

例子2:

參考:大漠窮秋的學習視頻 《AngularJS實戰》

在指令 loader 上定義屬性 howToLoad,與外部控制器交互

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width">
    <title>JS Bin</title>
    <script src="http://cdn.tig.qq.com/js/lib/angular-1.3.15.min.js"></script>
</head>
<style>
    .loader{
        background-color: blue;
        padding-top:5px
    }
</style>
<body>
    <div ng-controller="helloCtrl">
        <input type="text" ng-model="msg"> {{msg}}
    </div>
    <div ng-controller="helloCtrl1">
        <loader howToLoad="loadData1()"></loader>
    </div>
    <div>
        <p>ddd</p>
    </div>
    <div ng-controller="helloCtrl2">
        <loader howToLoad="loadData2()"></loader>
    </div>
    <script type="text/javascript">
        var myModule = angular.module('myModule', []);
        myModule.controller('helloCtrl', function($scope) {
            $scope.msg = "hahaha";
        });
        
         myModule.controller('helloCtrl1', function($scope) {
            $scope.loadData1 = function(){
                console.log('加載數據1');
            };
        });
        
         myModule.controller('helloCtrl2', function($scope) {
            $scope.loadData2 = function(){
                console.log('加載數據2');
            };
        });
        
        myModule.directive('loader', function(){
            return {
                restrict:'E',
                template:'<div class="loader">加載數據指令</div>',
                link: function(scope, element, attr){
                    element.bind('mouseenter', function(){
                        scope.$apply(attr.howtoload);
                    })
                }
            };
        });
        angular.bootstrap(document, ['myModule']);
    </script>
</body>
</html>

指令與指令之間的交互

  • 指令的controller 爲指令對外暴露一組public方法,提供給其餘指令調用

  • require 設置依賴的指令

  • link 函數中第四個參數,將獲得依賴指令的控制器

例子1:

咱們常常會看到不少指令編寫會依賴 ng-model 指令,例以下面的指令

myMod.directive('phoneNo', function() {
  return {
    restrict: 'A',
    require: '?ngModel',
    link: function(scope, element, attrs, ngModelCtrl) {
      if (!ngModelCtrl) return;

      function validPhoneNo(value) {
        var PHONE_NO_REGEXP = /^1[3|4|5|8][0-9]\d{8}$/;
        var valid = !ngModelCtrl.$isEmpty(value) && PHONE_NO_REGEXP.test(value);
        ngModelCtrl.$setValidity('valid', valid);

        return valid ? value : undefined;
      }

      ngModelCtrl.$parsers.unshift(validPhoneNo);
      ngModelCtrl.$formatters.unshift(validPhoneNo);
    }
  };
});

使用指令:

<input phone-no type="tel" placeholder="填寫11位有效手機號碼" ng-model="address.phoneNo" required>

固然能夠更簡單的使用官方的 ng-pattern 指令

<input type="tel" ng-pattern="/^1[3|4|5|8][0-9]\d{8}$/" placeholder="填寫11位有效手機號碼" ng-model="address.phoneNo" required>

例子2:

參考:大漠窮秋的學習視頻 《AngularJS實戰》

指令 player 在本身的控制器上定義了對外能夠調用的接口
指令 power、指令 speed、指令 height 分別都定義了須要依賴 指令 player、而且在自身的 link 函數中使用了 player 的接口。

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width">
    <title>JS Bin</title>
    <script src="http://cdn.tig.qq.com/js/lib/angular-1.3.15.min.js"></script>
</head>
<style>
    .loader{
        background-color: blue;
        padding-top:5px
    }
</style>
<body>
    <div ng-controller="helloCtrl">
        <input type="text" ng-model="msg"> {{msg}}
        <div>
            <player power>球員1 :力量</player>
        </div>
        <div>
            <player power speed>球員2:力量 + 速度</player>
        </div>
        <div>
            <player power speed height>球員3: 力量 + 速度 + 身高</player>
        </div>
    </div>
    
    <script type="text/javascript">
        var myModule = angular.module('myModule', []);
        myModule.controller('helloCtrl', function($scope) {
            $scope.msg = "hahaha";
        });
        
        myModule.directive('player', function(){
            return {
                restrict:'AE',
                scope:{},
                controller:function($scope){
                    $scope.ability = [];
                    this.addPower = function(){
                       $scope.ability.push('power'); 
                    };
                    
                    this.addSpeed = function(){
                       $scope.ability.push('speed'); 
                    };
                    
                    this.addHeight = function(){
                       $scope.ability.push('height'); 
                    };
                },
                link: function(scope, element, attr){
                    element.bind('mouseenter', function(){
                        console.log(scope.ability);
                    })
                }
            };
        });
        
        myModule.directive('power', function(){
            return {
                restrict:'A',
                require: '^player',
                link: function(scope, element, attr, controller){
                    controller.addPower()
                };
            };
        });
        
        myModule.directive('speed', function(){
            return {
                restrict:'A',
                require: '^player',
                link: function(scope, element, attr, controller){
                    controller.addSpeed()
                };
            };
        });
        
        myModule.directive('height', function(){
            return {
                restrict:'A',
                require: '^player',
                link: function(scope, element, attr, controller){
                    controller.addHeight()
                };
            };
        });
      
        angular.bootstrap(document, ['myModule']);
    </script>
</body>

</html>

理解 scope

scope 的取值

  • false 默認是false,複用組件具體位置所在的做用域

  • true 建立子做用域,該做用域繼承來自它具體所在位置的做用域

  • {...} 建立獨立做用域,與父做用域徹底隔離

實際開發中每每咱們會建立獨立做用域,完成與父做用域隔離。

能夠經過監視來是屬性表達式與模版做用域的屬性保持一致,但須要手動設置來實現(在link中顯示的從attr中讀取值,並賦值給scope)。
更方便的是使用scope的綁定策略。

  • @:使用@將屬性做爲字符串傳遞給指令(例子中的str),也能夠將外層的scope值在屬性值中以{{}}插入(例子中的str2)

  • =:與外部的屬性進行雙向綁定

  • &:傳遞外部的一個回調函數

scope:{
    attr1:'@attribute1', 
    attr2:'=attribute2',
    attr3:'&attribute3'
}

首先這裏的 scope 是獨立做用域,關於綁定策略須要 注意 兩點:

  • 屬性命名使用 - 鏈接,變量變現爲駝峯式

  • 回調函數傳遞參數的寫法

例子

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width">
    <title>指令的scope</title>
    <script src="http://cdn.tig.qq.com/js/lib/angular-1.3.15.min.js"></script>
</head>
<style>
    .loader{
        background-color: blue;
        padding-top:5px
    }
</style>
<body>

    <div ng-controller="helloCtrl">
        <input type="text" ng-model="msg">
        <input type="text" ng-model="str2">
        <input type="text" ng-model="str">
        <p>如下是指令</p>
        
        <my-directive msg="msg" str="1234" str2={{str2}} click-btn="clickBtn(name)">自己的html</my-directive>
        
    </div>
    
    <script type="text/javascript">
        var myModule = angular.module('myModule', []);
        myModule.controller('helloCtrl', function($scope) {
            $scope.msg = "hahaha";
            $scope.str2 = "使用@傳遞一個字符串";
            
            $scope.clickBtn = function(name){
                console.log(name);
            }
        });
        
        myModule.directive('myDirective', function(){
            return {
                restrict:'E',
                scope:{
                    msg:'=',
                    str:'@',
                    str2:'@',
                    clickBtn: '&'
                },
                template:'<input type="text" ng-model="msg"><p>{{str}}</p><p>{{str2}}</p><input type="text" ng-model="userName"><button ng-click="clickBtn({name:userName})">Click Me</button>',
                link: function(scope, ele, attr){
                    console.log(scope);
                    console.log(attr);
                }
            };
        })
        angular.bootstrap(document, ['myModule']);
    </script>
</body>

</html>

能夠對比 vue.js 中建立組件、組件通訊。

和angular指令指令同樣vue.js組件的定義也須要注意到屬性命名寫法

<component-a :msg="msg" hh="來自字面量語法" :click-handle="clickHandle"></component-a>
<my-component
  :foo="baz"
  :bar="qux"
  @event-a="doThis"
  @event-b="doThat">

  <!-- content -->
  <img slot="icon" src="...">
  <p slot="main-text">Hello!</p>

</my-component>

vue.js 中編寫可複用的組件

組件的 API 來自三部分:props、事件、slot
-props 容許外部環境傳遞數據給組件(其中數據也能夠是 action)
-事件 容許在組件內觸發外部環境的 action
-slot 容許外部環境插入內容到組件的視圖結構內 (包括指定插入內容在組件中的位置)

對比 React

react 也是經過 props 傳遞。對屬性命名沒有和Angular、vue這種要求

<MiniPost ref="miniPost" onOk={this.sendPost} placeholder={postPlaceholder}/>

2、後臺管理端中Angularjs的實踐

爲何選擇 Angularjs

  • Angularjs 適合管理後臺類型的項目

  • 開發效率高

  • 先後端部分解耦

怎麼使用

1、使用 requirejs 管理咱們的js文件(不強求),這一步和 angularjs 沒有關係。

require.config({
  urlArgs: "v=" + (new Date()).getTime(),// 體驗環境和正式環境會替換爲構建版本號
  baseUrl: "/js/",
  paths: {
    "jquery": "vendor/jquery-1.11.3.min",
    "underscore": "vendor/underscore.min",
    "moment": "vendor/moment.min",
    "angular": "vendor/angular.min",
    "ui-router": "vendor/angular-ui-router.min",
    "ng-file-upload": "vendor/ng-file-upload",
    "ng-sanitize": "vendor/angular-sanitize.min",
    "ui-bootstrap": "vendor/ui-bootstrap-tpls-0.12.1.min",
    "angular-datetimepicker": "vendor/angular-datetimepicker",
    "ui-select": "vendor/ui-select",
    "checklist-model": "vendor/checklist-model",
    "directives": "vendor/directives",
    "tfl": "tfl/js/tfl-core",
    "tfl-editor": "tfl/js/tfl-editor"
  },
  shim: {
    "angular": {
      exports: "angular"
    },
    "ui-router": {
      deps: ["angular"]
    },
    "ng-file-upload": {
      deps: ["angular"]
    },
    "ng-sanitize": {
      deps: ["angular"]
    },
    "ui-bootstrap": {
      deps: ["angular"]
    },
    "ui-select": {
      deps: ["angular"]
    },
    "checklist-model": {
      deps: ["angular"]
    },
    "angular-datetimepicker": {
      deps: ["angular", "moment"]
    },
    "serviceModule": {
      deps: ["angular"]
    },
    "directives": {
      deps: ["angular", 'tfl']
    }
  }
});

2、咱們不會整站在根目錄下直接使用,而是根據不一樣業務模塊分拆開,這樣有利於代碼的維護和組織,我的認爲這點很重要

網站路由 一部分交給後臺(/shop/goods)、一部分交給 angular(#/部分)

http://demo.com/shop/goods#/
http://demo.com/shop/goods#/detail/100034
http://demo.com/shop/goods#/edit/100034
http://demo.com/shop/goods#/edit/100034

demo.com/shop/goods 後臺 php 吐出的直出的頁面(固然這個的外出有個整站的layout)

<div ui-view></div>

<script>
    require(['shop/goods'], function(){
    });
</script>

業務 shop/goods.js

define(['jquery', 'angular', 'ui-router', 'serviceModule'], function($, angular) {

  var myModule = angular.module('myModule', [
    'ui.router', 'serviceModule'
  ]);

  myModule.config(['$httpProvider', '$stateProvider', '$urlRouterProvider',
    function($httpProvider, $stateProvider, $urlRouterProvider) {

      $httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8';
      $httpProvider.defaults.transformRequest = function(data) {
        if (data === undefined) {
          return data;
        }
        return $.param(data);
      };

      $urlRouterProvider.otherwise('/');

      $stateProvider.state('demo', {
        abstract: true,
        url: '/',
        template: '<div ui-view></div>',
        controller: ['$scope', function($scope) {

        }]
      });

      $stateProvider.state('demo.list', {
        url: '',
        pageTitle: 'list頁',
        templateUrl: '/views/demo.list.html',
        controller: ['$scope', function($scope) {
        }]
      });

      $stateProvider.state('demo.detail', {
        url: 'detail/{id:[0-9]+}',
        pageTitle: '詳情頁',
        templateUrl: '/views/demo.detail.html',
        resolve: {
          data: ['$stateParams', 'Test', function($stateParams, Test) {
            return Test.fetch($stateParams.id);
          }]
        },
        controller: ['$scope', 'data', function($scope, data) {
          console.log(12);
          $scope.data = data;
        }]
      });

      $stateProvider.state('demo.add', {
        url: 'add',
        pageTitle: '新增編輯頁',
        templateUrl: '/views/demo.add.html',

        controller: ['$scope', function($scope) {
          console.log('add');
        }]
      });
    }]);

  angular.bootstrap(document, ['myModule']);
});

serviceModule.js 定義一個和後臺數據交換的模塊 serviceModule

define(['angular'], function(angular) {
  'use strict';
  var serviceModule = angular.module('serviceModule', []);
  serviceModule.factory('Test', ['$http', function($http) {
    return {
      fetch: function(id) {
        return $http.get('/test/get/' + id).then(function(res) {
          return res.data;
        });
      },
      list: function(search) {
        return $http.get('/test/list', {params: search}).then(function(res) {
          return res.data;
        });
      },
      save: function(data, cb) {
        $http.post('/test/save', data).success(cb);
      }
    };
  }]);
});

就這樣商品模塊就搞定啦。

參考:

相關文章
相關標籤/搜索