iT邦幫忙

DAY 12
0

我在前端 ng 時系列 第 12

初談 ui-router

ui-router is routing framework for AngularJS。

ui-router 不是 AngularJS 原生的 router module,$router 才是。

ui-router 跟 $router 的差別在於 ui-route 組織在 state,而 $router 是組織在 url。
( stete 是 ui-router 定義網站指定頁面的狀態。例如:登入頁,state: 'singIn')

打個比方,你有個 <a> tag 連結到登入頁。

ui-route 的寫法:

 <a ui-sref=“main.signIn"></a> // base on state name 

$route 的寫法:

<a href=“main/signIn” ></a> // base on url 

signIn 的 link 需要出現在很多頁面上。
假使,有一天需求變更。需要把 singIn 的 uri 變成 /signIn (前面 main/ 拿掉)。
使用 AngularJS $route 就需要確保每頁 singIn url 都有更新成 <a href=“/signIn”></a> (多個動作)
可是 ui-route 只需要在定義 state name 的地方把定義的 url 換成新的就好了。(一個動作)

接下來進入 ui-router 的介紹吧!


ui-sref directive:
ui-sref directive 讓綁定 element 變成到指定 state 的連結。
假如 element 是 <a> tag 的話,還會自動產生 href attribute 在 <a> tag上面。

先看範例 http://plnkr.co/edit/NajjDAov6bWJuct28yxQ?p=preview

var app = angular.module('myExample', ['ui.router']);
app.config( function( $stateProvider, $urlRouterProvider ) {   
    $urlRouterProvider.otherwise('/home');
   // 定義 $state
    $stateProvider
        .state('home', {
            url: '/home',
            template: '<div>我在主頁</div>'
        })
        .state('about', {
            url: '/about/:id',
            template: '<div>我在介紹 {{id}}</div>',
            controller: function ($scope, $stateParams) {
                $scope.id = $stateParams.id;
            }
        });
       
});






  <div ng-controller="myCtrl">
      <!-- ui-sref 會幫忙產生對應的 href -->
      <a ui-sref="home" ui-sref-active="active">主頁</a>
     
      <!-- 可以 pass parameters -->
      <a ui-sref="about({'id':1})" ui-sref-active="active">介紹1</a>
     
      <!-- 也可以直接定義 href 的方式,只是就沒用到優秀的 ui-router state 特性-->
      <a href="#/about/2">介紹2</a>
     
      <!-- bind ngClick + $state.go 也可以 work, 只是這樣不會自動產生 href -->
      <a ng-click="$state.go('about', {'id': 3})">介紹3</a>
     
      <!-- 不用 a tag 也可以 work, 可是就不會自動產生 href -->
      <span ui-sref="about({'id':4})" ui-sref-active="active">介紹4</span>
  </div>

由於 <a> tag + ui-sref 會自動幫忙產生 href attribute,方便使用者在連接用另開分頁 (ctrl-clicking) 形式打開。
建議除非想要在轉換 state 前做些準備事情,要不然採取 <a> tag + ui-sref 的方式就行。

ui-sref-active=“[class name]” :
假如相鄰的 ui-sref 定義的 state 跟當下的 state 一樣,就會在 element add 或 remove class。
ui-sref-avtive-eq=“[class name]" :
會判斷是完全一模一樣的 state 才會幫忙加 class。

ui-sref-active 跟 ui-sref-avtive-eq 的差別就是前者用 $state.include() 判斷,後者用 ==。


resolve function:

resolve function 是在 state 還沒有進入 controller 跟 render template 前會呼叫的 function。
適合用來準備下一個 state 頁面的顯示資料。
如果準備資料發生錯誤,會維持在當下的 state ,不會跳到下一個 state 。

$stateProvider.state('about', {
            url: '/about/:id',
            template: '<div>我在介紹 {{id}}</div><div>{{myAbout}}</div>',
            // 一定要是 object 形式
            resolve: {
              'aboutData': function () {
                  return '我是要進介紹頁的文字'
              }
            },
          // 在 controller inject resolve state 的 name, 就可以確保 data 在進 controller 前是準備好的
             // aboutData 是可以拿取 resolve data 的方式
             // 就算沒有 inject resolve function name, resolve function 還是會確保在 enter controller 前跑完
            controller: function ($scope, $stateParams, aboutData) {
                $scope.id = $stateParams.id;
                $scope.myAbout = aboutData;
            }

可以搭配 AngularJS 的 $q 來使用。當資料錯誤時,呼叫 $q.reject 會使得 state 回到上一個 state 中。

            // 一定要是 object 形式, 可有複數
            resolve: {
              'aboutData': function () {
                  return '我是要進介紹頁的文字'
              },
              'myData': function ($q, $timeout, $stateParams) {
                var d = $q.defer();
                $timeout(function () {
                    if ($stateParams.id !== 1) {
                     // 錯誤發生, 預設保留在 $state.$current 
                      d.reject();
                    } else {
                      d.resolve('myData');
                    }
                }, 100);
                return d.promise;
              }
            }

範例 http://plnkr.co/edit/4faEi0LvUgtYAMihRA74?p=preview


上一篇
ng-filter 的五四三
下一篇
ui-router - 巢狀頁面
系列文
我在前端 ng 時30

尚未有邦友留言

立即登入留言