1. 程式人生 > >JS框架,你會喜歡AngularJS

JS框架,你會喜歡AngularJS

AngularJS
誕生於2009年,由Misko Hevery 等人建立,後為Google所收購。是一款優秀的前端JS框架,已經被用於Google的多款產品當中。AngularJS有著諸多特性,最為核心的是:MVC、模組化、自動化雙向資料繫結、語義化標籤、依賴注入等等。

可愛之處

AngularJS通過為開發者呈現一個更高層次的抽象來簡化應用的開發。如同其他的抽象技術一樣,這也會損失一部分靈活性。換句話說,並不是所有的應用都適合用AngularJS來做。AngularJS主要考慮的是構建CRUD應用。幸運的是,至少90%的WEB應用都是CRUD應用。但是要了解什麼適合用AngularJS構建,就得了解什麼不適合用AngularJS構建。
如遊戲,圖形介面編輯器,這種DOM操作很頻繁也很複雜的應用,和CRUD應用就有很大的不同,它們不適合用AngularJS來構建。像這種情況用一些更輕量、簡單的技術如jQuery可能會更好。

我呢自從工作就一直應用angularjs,,來實現幾乎所有的專案內容,所以今天就angular的基礎知識簡單進行一下彙總,希望能與熱愛學習新技術,喜歡angular的同伴們一起交流,以後陸續會把angular的各種詳細的應用以及遇到的問題,他的優勢以及 SEO的難點都會和大家分享,敬請期待吧!!!

來自網路

1、安裝引用


http://www.bootcdn.cn/ 中搜索angular下載

<script src="pathto/angular.js"></script>

2、簡單使用


<!DOCTYPE html>
<!-- 這裡使用 ng-app 指令  -->
<html ng-app="reminder"> <head> <meta charset="utf-8"> <title></title> <script src="angualr.js" charset="utf-8"></script> </head> <!-- 這裡使用 ng-controller --> <body ng-controller="mainControler"> <!-- ng-model指令 會在作用域中的 $scope 上 放置一個 info 的屬性 值為input的值 -->
<input type="text" name="name" value="" ng-model="info"> <!-- 雙花括號中可以寫 angular 表示式 下面寫法為取出 $scope上的 info 屬性的值--> <p></p> </body> <!-- controller的作用域範圍在這裡結束--> </html>

3、以模組化的方式來開發自己的應用 和 依賴注入


<!DOCTYPE html>
<html  ng-app="reminder">
  <head>
    <meta charset="utf-8">
    <title></title>
    <script src="angular.js"></script>
    <script src="index.js"></script>
  </head>
  <body ng-controller="mainControler">
    <table>
      <thead>
          <th>
              <td>姓名</td>
              <td>學號</td>
              <td>性別</td>
          </th>
      </thead>
      <tbody>
          <!-- ng-repeat 指令能從作用的$scopes身上取到資料,幫我們完成渲染-->
          <!-- 他會在每次資料變動的時候幫我們重新渲染 -->
          <tr ng-repeat="v in students">
              <td> </td>
              <td> </td>
              <td> </td>
          </tr>
          <tr>
              <td ng-click="addStudent()">+</td>
          </tr>
      </tbody>
    </table>
  </body>
</html>
  // 把我們的應用作用單獨的一個模組 和系統中的其他模組解耦
  var reminder = angular.module('reminder',[]);

  // 在我們的模組上建立一個控制器  來控制本模組中某個區域性的可見資料
  reminder.controller('mainControler',['$scope',function($scope){
    $socpe.students = [
      {id:1001,name:'A',sex:'nan'},
      {id:1002,name:'B',sex:'nv'},
      {id:1003,name:'C',sex:'nan'},
    ]
    $scope.addStudent = function(){
      this.stuents.push({id:Math.random(),name:'new man', sex:'nan'});
    }
  }]);

4、常用的裝飾型指令


裝飾性指令用來在 view 和 controler 之間協調運作

angularjs 概念介紹

angularjs API

  • ng-app
  • ng-controller

  • ng-repeat // track by $index 可以避免同id屬性報錯

  • ng-model
  • ng-init

  • ng-class

  • ng-show
  • ng-hide
  • ng-if
  • ng-switch

  • ng-[event]

  • ng-href
  • ng-src

5、元件型指令


元件型指 用來拆分複雜的html頁面

實現元件化開發 和一定程度的 複用

login.html

<div id="login">
  <div class="usernam"></div>
  <div class="password"></div>
  <button class="submit">Login</button>
</div>

index.html

<!DOCTYPE html>
<html ng-app="reminder">
  <head>
    <meta charset="utf-8">
    <title></title>
    <script src="angular.js" charset="utf-8"></script>
    <script src="index.js" charset="utf-8"></script>
  </head>
  <body ng-controller = "mainControler">
    <login></login>
  </body>
</html>

index.js

var reminder = angular.module('reminder',[]);
// 在整個模組的各個控制器作用域內  login指令都可用
reminder.directive('login',[function(){
  // Runs during compile
  return {
    restrict: 'AE', // E = Element, A = Attribute, C = Class, M = Comment
    templateUrl: 'login.html',
    // name: '',
    // priority: 1,
    // terminal: true,
    // scope: {}, // {} = isolate, true = child, false/undefined = no change
    // controller: function($scope, $element, $attrs, $transclude) {},
    // require: 'ngModel', // Array = multiple requires, ? = optional, ^ = check parent elements
    // template: '<h3>Hello Angular</h3>',
    // replace: true,
    // transclude: true,
    // compile: function(tElement, tAttrs, function transclude(function(scope, cloneLinkingFn){ return function linking(scope, elm, attrs){}})),
    // link: function($scope, iElm, iAttrs, controller) {
    // }
  };
}]);

6、在元件型指令中的link函式中使用jQuery或jqLite


一般推薦在自定義指令的link函式中使用jquery去操作dom元素.

在link函式中操作$scope身上的資料時一定要注意

呼叫$scope.$apply()方法讓angular啟動髒檢查機制來自動重新整理頁面

呼叫$scope.$apply()方法讓angular啟動髒檢查機制來自動重新整理頁面

呼叫$scope.$apply()方法讓angular啟動髒檢查機制來自動重新整理頁面

另外操作文件或者使用定時函式時,需要注入$document, $timeout 等服務

angular 內部提供angular.elements方法,類似於jQuery方法,得到jqLite物件

jqLite物件中的方法:

[
 "ready()",
 "toString()",
 "eq()",
 "length()",
 "push()",
 "sort()",
 "splice()",
 "data()",
 "inheritedData()",
 "scope()",
 "isolateScope()",
 "controller()",
 "injector()",
 "removeAttr()",
 "hasClass()",
 "css()",
 "attr()",
 "prop()",
 "text()",
 "val()",
 "html()",
 "empty()",
 "removeData()",
 "bind()",
 "unbind()",
 "on()",
 "off()",
 "one()",
 "replaceWith()",
 "children()",
 "contents()",
 "append()",
 "prepend()",
 "wrap()",
 "remove()",
 "detach()",
 "after()",
 "addClass()",
 "removeClass()",
 "toggleClass()",
 "parent()",
 "next()",
 "find()",
 "clone()",
 "triggerHandler()"
]

如果專案中不使用jQuery外掛,jqLite是很好的操作DOM,繫結事件的選擇。

在普通的controller中 也可以這樣使用:

<button type="button" name="button" ng-click="submit($event)"></button>
$scope.toggletododetail = function($event){
  console.log($event);
  var el = angular.elements() // 得到一個JqLite物件
  console.dir(el);  //檢視其中的方法,比jquery少很多
}

如果想使用jquery,先引入jquery 後引入angular.js,jQuery 會自動覆蓋jqLite,隨後不用任何配置就可以在程式碼中使用 $.

7、 ng-view 指令


angular 多頁面切換的方式

使用ng-view指令搭配 $routeProvider配置整個應用的狀態

<script src="angular-route.js"></script>
<div class="">
   <title-bar></title-bar>  

   <!-- 當應用處於'#/view'這種狀態時,ng-view會被替換成對應的配置好的html頁面-->
   <!-- 通過ajax請求的方式 或者 從快取中 或者從頁面中獲取-->
   <div ng-view></div>

   <tab-bar>
     <ul>
       <li><a href="#/view"></a></li>
       <li><a href="#/"></a></li>
     </ul>
   </tab-bar>
</div>
var myapp = angular.module('myapp',[]);

myapp.controller('mainctrl',['$scope',function($scope){
  //main.html 的控制器
}]);
myapp.controller('infoctrl',['$scope','$routeParams',function($scope,$routeParams){
  //info.html 的控制器
  console.log($routeParams.id);
}]);

myapp.config(['$routeProvider',function($routeProvider) {
  $routeProvider.when('/',{
    controller:'main',
    templateUrl:'main.html'
  }).when('/view/:id',{
    controller:'infoctrl',
    templateUrl:'info.html',
    publicAccess:true
  }).otherwise({
    redirectTo:'/'
  });
}])

通過內建的router瞭解了其工作原理之後,請在工程中使用angular-ui-router;

切換狀態可以使用a連結,也可以在js中切換

使用內建的$location 服務

myapp.controller('listCtrl',[
  '$scope',
  '$location',
  function($scope,$location){
    $socpe.whenClick = function(url){
      $location.path(url); //可讀可寫,參考文件
    }
  }
])

8、服務


為什麼需要服務?

多頁面切換的過程中 有些資料被鎖死在對應的controller內。 需要把這些公共的資料以服務的形式組織起來,隨需隨取

服務在整個頁面的生命週期中可用,我們一般把和後臺做資料互動這樣的任務,交給service去做, 而不是在controller內。

常用一個service代表後臺中一張表,及對錶的操作

var myapp = angular.module('myapp',[]);

// 可以在中括號中定義其他需要的服務
myapp.factory('$student',[ function(){
  return {
      students:[
        {...},
        {...},
        {...},
      ]
      getStudentsById:function(){
        ...
      },
      removeStudentsById:function(){

      },
      updateStudentsById:function(){

      },
      addStudent:function(id){

      }
  }
}]);

myapp.service('$copyRight',  function(){
  this.name = 'unique';
  this.date  = '2015';
  this.generatorCode = function () {
    return '<span>'+this.name+'</span><img src="erweima">';
  }
});

myapp.constant('$isLogin', {islogin:false});

myapp.value('$PI', Math.PI);

9、在服務中或其他地方使用$http服務


來看一個典型的服務及其使用

所有在服務中同資料庫的互動都採用這種方式

myapp.factory('User',[
  '$http',
  '$location',
  '$q',
  function($http,$location,$q){
    var User = {
      getAllUser:function(){
        //這裡涉及到非同步  所以使用$q延後執行
        var deferred = $q.defer();
        $http.get('/allUser')
        .success(function(data, status, headers, config){
          deferred.resolve(data);
        }).error(function(data, status, headers, config){
          deferred.reject(data);
        })
        return deferred.promise;
      }
    }
    return User;
  }
])
myapp.controller('userCtrl',[
  '$scope',
  'User',
  function($scope,User){
    //因為期間涉及到非同步,所以需要使用promise的程式設計思路來解決拿不到資料的問題
    User.getAllUser().then(function(data){
        $scope.users = data;
    },function(){
        $scope.users = []; //處理錯誤
    });
  }
])

10、過濾器


有的時候一些展現在頁面上的資料需要格式化,有的時候一些展現在頁面上列表需要排序,過濾。

我們使用過濾器,內建過濾器參考api文件,自定義過濾器的方式

過濾器的本質是一個函式

<!--prefix 是一個函式  第一個引數為 name 變數  第二個引數為:後面提供的值-->
<span></span>

所以自定義過濾器就相當於寫一個公用的在整個模組中可用的函式

myapp.filter('young',function(){
  return function(e,type){
    var r =  [];
    var _sex = type?'nan':'nv';
    for (var i = 0; i < e.length; i++) {
      if(e[i].age>=12 && e[i].age<=17 && e[i].sex == _sex){
        r.push(e[i]);
      }
    };
    return r;
  }
})
  <li ng-repeat="stu in students| young:1" ></li>

過濾器可以以類似服務的方式注入到各個 控制器,服務,指令,過濾器。

myapp.controller('indexCtrl',[
  '$scope',
  '$routeParams',
  'User',   // User為自定義的一個服務
  '$filter',// 注入$filter prefix為自定義的一個過濾器
  function($scope,$routeParams,User,$filter){
    $filter('prefix')();//這樣像使用正常函式一樣使用它
  }
])

11、使用動畫


<script src="angular-animate.js"></script>
var myapp = angular.module('myapp',['ngRoute','ngAnimate']);

查閱文件 觀察class的變化 寫css樣式來操控動畫

<style>
span.ng-enter{
  /**/
}
span.ng-enter-active{
  /**/
}

#view.ng-enter{

}
#view.ng-enter-active{

}

<style>
<span ng-if="show"> </span>   
<ng-view id="view"></ng-view>

12、自定義指令中的配置項


  • 指令之name屬性

指令的名字,預設和directive第一個引數相同

  • 指令之priority屬性

指令的執行優先順序,當一個元素身上有兩個指令的時候,優先順序高的先執行, 內建指令中,ng-repeat擁有最高優先順序

  • 指令之terminal屬性

編譯器是否在該指令之後繼續編譯其他指令

  • 指令之template屬性
<!--注意這裡 type 為  text/ng-template 的script標籤-->
<script  type="text/ng-template" id="tab-bar">
<ul>
  <li></li>
  <li></li>
  <li></li>
</ul>
</script>
var myapp = angular.module('myapp',[]);
myapp.directive('tab-bar',[
  function(){
    return {
      restrict:"AE",
      template:tab-bar,  //上面那個script標籤的id
    }
  }
])

指定一個字串或者一個的id 或者templateCache中的某個名字來作為指令的模板

  • 指令之templateUrl屬性

指定一個url地址作為指令的模板

  • 指令之scope屬性

宣告獨立的作用域

例子.一個輪播圖指令,擁有自己獨立的作用域,但是需要從父作用域中獲取需要輪播的圖片地址

<body ng-controller="mainCtrl">
  <lunbo pics="pics" a="">
    <h1>this is a lunbo</h1>
  </lunbo>
</body>
var di = angular.module('di',[]);
di.controller('mainCtrl',[
'$scope',
function($scope){
  $scope.a = 12;
  $scope.b = 13;
  $scope.pics = [
  {title:1},
  {title:2},
  {title:3}
  ]
  $scope.addPic = function(){
    $scope.pics.push({title:4});
  }
}
])

di.directive('lunbo', [
function(){
  return {
    restrict:'AE',
    replace:true,
    transclude:true,
    template:'<div>  <div ng-transclude></div> <ul> <li ng-repeat="v in pics  track by $index">  </li> </ul> </div>',
    scope:{
      a:'@',
      pics:'=',
      addPic:'&'
      },
      controller:function($scope){
        console.log($scope);
      }
    }
  }
]);
  • 指令之controller屬性

生命獨立的controller

  • 指令之require屬性

設定要注入當前指令連結函式中的其他指令的控制器

  • 指令之restrict 屬性

指令在頁面中的使用方式

  • 指令之replace屬性

指令以元素的方式書寫的時候是否替換標籤

  • 指令之transclude屬性

指令中能不能巢狀包含其他Html元素

  • 指令之compile屬性

定義編譯函式,編譯函式會操作原始DOM,而且會在沒有提供link設定的情況下建立連結函式

  • 指令之link屬性

在指令編譯的最後階段會呼叫一次,通常在這裡註冊事件,操作dom

如果指令了compile,則link不生效

13、利用templateCache來快取頁面


//會在app啟動的時候執行一次
myapp.run(function($templateCache){
  $templateCache.put('cache','<h3>內容來源於快取!</h3>');
})
myapp.directive('tsTplcache', [function(){
  // Runs during compile
  return {
    restrict:'EAC',
    templateUrl:'cache',
    replace:true
  };
}]);

14、其他


  • ng-bind 解決網路不好的情下重新整理頁面會看到“的問題

  • 一次繫結問題 “

  • apply watch 解決一些監測問題

    socpe. wacth()儘量少用

    scope. apply()用在link函式中去啟動angular髒檢查機制,保障資料的同步

    scope. apply()用在link函式中去啟動angular髒檢查機制,保障資料的同步

    scope. apply()用在link函式中去啟動angular髒檢查機制,保障資料的同步

  • 其他問題

    使用了過濾器之後 ng-repeat 中的 $index 形同虛設

    需要在資料中使用id來標識一條唯一的資料

15、背後的原理


  • angular中的mvvm模式

M(model) V(view) C(controller)

這裡寫圖片描述

Model代表資料最原始的樣子和邏輯以及對資料的操作

在web頁面中,大部分model都是來自Ajax伺服器返回的資料或者全域性配置物件. angular中的Service正是封裝和處理這些與Model相關的業務邏輯的最佳方式。

View 是資料最終會呈現的樣子

在angular中 普通的html結構 和 元件型指令就是 view

Controller負責model物件的初始化.

在angular中 controller 將呼叫一個或多個Service來獲取模型資料。 並把他放在$scope上,controller也負責提供那些寫在view上的裝飾性指令所你呼叫的函式等。

在angular中因為ControllerView之間通過 $scope 的資料雙向繫結關係。一般angular團隊不把自己稱為一個MVC框架,而是 MVVM (model-view-view-model)

  • 作用域就像javascript的函式作用域,是層層巢狀的

  • $scope.$apply 可以啟動髒檢查機制,會在內部呼叫 digest scope能還是更新頁面顯示。大部分情況下我們不需要手動呼叫它是因為在angular的各個服務,控制器中都自動對他進行了呼叫。如果用原生的方式寫個setTimeOut去改變 scopeview調 apply.在link函式中也是如此。