前端MVC學習總結(三)——AngularJS服務、路由、內置API、jQueryLite


一、服務

AngularJS功能最基本的組件之一是服務(Service)。服務為你的應用提供基於任務的功能。服務可以被視為重復使用的執行一個或多個相關任務的代碼塊。

AngularJS服務是單例對象,這意味着只有一個實例被創建過,服務使用AngularJS的依賴注入機制來定義和注冊。

可以把服務注入模塊、控制器和其它服務。

1.1、內置服務

常見的內置服務如下:

$http 發送http請求

$resource 創建一個可以RESTful服務器端數據源交互對象

$window 瀏覽器的window元素的jQuery包裝

$document 瀏覽器的document元素的jQuery包裝

$rootScope 根作用域的訪問

$rootElement 根元素的訪問

$cacheFactory 提供鍵/值對放置到對象緩存

$interval 提供對window.setInterval訪問

$timeout 提供對window.setTimeout訪問

$cookies 提供對瀏覽器的cookie的讀寫訪問

$animate 提供動畫鈎子來同時鏈接到以CSS和JavaScript為基礎的動畫

1.1.1、瀏覽器Window服務($window)

引用瀏覽器的window對象。默認瀏覽器的window是全局的根對象。

示例代碼:

<!DOCTYPE html>
<!--指定angular管理的范圍-->
<html ng-app="app01">
    <head>
        <meta charset="UTF-8">
        <title>服務</title>
    </head>
    <body>
        <!--指定控制器的作用范圍-->
        <form ng-controller="Controller1" name="form1">
        </form>
        <!--引入angularjs框架-->
        <script src="js/angular146/angular.min.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            //定義模塊,指定依賴項為空
            var app01 = angular.module("app01", []);

            //定義控制器,指定控制器的名稱,$scope是全局對象
            app01.controller("Controller1", ['$scope','$window',function($scope,$win) {
                $win.alert("調用window服務的alert方法");
            }]);
        </script>
    </body>
</html>

運行結果:

1.1.2、發送http請求服務 ($http)

$http服務從AngularJS代碼直接與Web服務器進行交互,底層是通過AJAX實現,與jQuery中$.ajax類似

通過$http封裝后的方法:

delete(url,[config]) 發送謂詞為delete的異步請求

get(url,[config]) 發送謂詞為get的異步請求

head(url,[config])  發送謂詞為head的異步請求

jsonp(url,[config]) 發送通過jsonp實現跨域的同步請求的請求

post(url,data,[config]) 發送謂詞為post的異步請求

put(url,data[config]) 發送謂詞為put的異步請求
基本用法:
$http({method: 'GET', url: '/someUrl'}).
success(function(data, status, headers, config) {
}).
error(function(data, status, headers, config) {
});

詳細的配置如下:

這里使用NodeJS+Express作為后台服務,完成一個簡單的汽車管理功能:

cars.js

var express = require('express');
var router = express.Router();
var _= require('lodash');

var cars=[];
cars.push({id:201701,name:"BMW",price:190,speed:"210km/h",color:"白色"});
cars.push({id:201702,name:"BYD",price:25,speed:"160km/h",color:"紅色"});
cars.push({id:201703,name:"Benz",price:300,speed:"215km/h",color:"藍色"});
cars.push({id:201704,name:"Honda",price:190,speed:"170km/h",color:"黑色"});
cars.push({id:201705,name:"QQ",price:130,speed:"210km/h",color:"白色"});

/* Get */
/*獲得所有汽車*/
/*url /cars/*/
router.get('/', function(req, res, next) {
    res.json(cars);
});

/*Get*/
/*獲得汽車通過id*/
/*url:/cars/:id  */
router.get('/:id', function(req, res, next) {
     //從路徑中映射參數,轉換成數字
      var id=parseInt(req.params.id);
      var car=_.find(cars,{id:id});
      res.json(car);
});

/*Post*/
/*添加汽車*/
/*url:/cars/car  */
router.post('/car', function(req, res, next) {
      console.log("收到請求");
      var car=req.body;  //從請求正文中獲得json對象
      car.id=_.last(cars).id+1;  //將編號修改為最后一輛車的編號+1
      cars.push(car);  //將汽車對象添加到集合中
      res.json(car);  //將添加成功的車以json的形式返回
});

/*Put*/
/*修改汽車*/
/*url:/cars/car  */
router.put('/car', function(req, res, next) {
      var car=req.body;  //從請求正文中獲得json對象
      console.log(req.body);
      var index=_.findIndex(cars,{id:parseInt(car.id)});  //根據id獲得車在集合中的下標
      
      cars[index]=car;  //替換原對象
      //res.json(car);  //將修改后的車以json的形式返回
      res.send({status:"success", message:"更新成功!"});  
});

/*Delete*/
/*刪除汽車*/
/*url:/cars/:id  */
router.delete('/id/:id', function(req, res, next) {
      //獲得url中的編號參數
      var id=parseInt(req.params.id);
      var index=_.findIndex(cars,{id:id});  //根據id獲得車在集合中的下標
      cars.splice(index,1);   //在cars數組中刪除下標從index開始的1條數據
      res.json(cars);  
});

module.exports = router;

app.js

var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');

var index = require('./routes/index');
var users = require('./routes/users');
var pdts = require('./routes/product');
var task = require('./routes/task');
var cars = require('./routes/cars');

var app = express();

//指定視圖引擎為ejs
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');

// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.all('*', function(req, res, next) { 
    res.header("Access-Control-Allow-Origin", "*");  
    res.header("Access-Control-Allow-Headers", "content-type");  
    res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");  
    res.header("X-Powered-By",' 3.2.1')  
    res.header("Content-Type", "application/json;charset=utf-8");  
    next();  
});  

app.use('/', index);
app.use('/users', users);
app.use('/pdt', pdts);
app.use("/task",task);
app.use("/cars",cars);

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  var err = new Error('Not Found');
  err.status = 404;
  next(err);
});

// error handler
app.use(function(err, req, res, next) {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.render('error');
});

module.exports = app;

www

#!/usr/bin/env node

/**
 * 依賴模塊,導入
 */

var app = require('../app');
var debug = require('debug')('nodejsexpress:server');
var http = require('http');

/**
 * 從上下文環境中獲得監聽端口,如果空則3000
 */

var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);

/**
 * 創建Web服務器
 */

var server = http.createServer(app);

/**
 * 開始監聽
 */

server.listen(port);
server.on('error', onError);  //指定發生錯誤時的事件
server.on('listening', onListening);  //當監聽成功時的回調

/**
 * 規范化端口
 */

function normalizePort(val) {
  var port = parseInt(val, 10);

  if (isNaN(port)) {
    // named pipe
    return val;
  }

  if (port >= 0) {
    // port number
    return port;
  }

  return false;
}

/**
 *錯誤事件監聽
 */

function onError(error) {
  if (error.syscall !== 'listen') {
    throw error;
  }

  var bind = typeof port === 'string'
    ? 'Pipe ' + port
    : 'Port ' + port;

  //錯誤處理
  switch (error.code) {
    case 'EACCES':
      console.error(bind + ' requires elevated privileges');
      process.exit(1);  //結束程序
      break;
    case 'EADDRINUSE':
      console.error(bind + ' is already in use');
      process.exit(1);
      break;
    default:
      throw error;
  }
}

/**
 * 當用戶訪問服務器成功時的回調
 */

function onListening() {
  var addr = server.address();
  var bind = typeof addr === 'string'
    ? 'pipe ' + addr
    : 'port ' + addr.port;
  debug('Listening on ' + bind);
}

示例代碼:

<!DOCTYPE html>
<!--指定angular管理的范圍-->
<html ng-app="carApp">

    <head>
        <meta charset="UTF-8">
        <title>服務</title>
        <style>
            * {
                margin: 0;
                padding: 0;
                font-family: microsoft yahei;
                font-size: 14px;
            }
            
            body {
                padding-top: 20px;
            }
            
            .main {
                width: 90%;
                margin: 0 auto;
                border: 1px solid #777;
                padding: 20px;
            }
            
            .main .title {
                font-size: 20px;
                font-weight: normal;
                border-bottom: 1px solid #ccc;
                margin-bottom: 15px;
                padding-bottom: 5px;
                color: blue;
            }
            
            .main .title span {
                display: inline-block;
                font-size: 20px;
                background: blue;
                color: #fff;
                padding: 0 8px;
                background: blue;
            }
            
            a {
                color: blue;
                text-decoration: none;
            }
            
            a:hover {
                color: orangered;
            }
            
            .tab td,
            .tab,
            .tab th {
                border: 1px solid #777;
                border-collapse: collapse;
            }
            
            .tab td,
            .tab th {
                line-height: 26px;
                height: 26px;
                padding-left: 5px;
            }
            
            .abtn {
                display: inline-block;
                height: 20px;
                line-height: 20px;
                background: blue;
                color: #fff;
                padding: 0 5px;
            }
            
            .btn {
                height: 20px;
                line-height: 20px;
                background: blue;
                color: #fff;
                padding: 0 8px;
                border: 0;
            }
            
            .abtn:hover,
            .btn:hover {
                background: orangered;
                color: #fff;
            }
            
            p {
                padding: 5px 0;
            }
            
            fieldset {
                margin-top: 10px;
                border: 1px solid #ccc;
                padding: 5px 10px;
            }
            
            fieldset legend {
                margin-left: 10px;
                font-size: 16px;
            }
        </style>
    </head>

    <body>
        <!--指定控制器的作用范圍-->
        <form ng-controller="CarController" class="main">
            <h2 class="title"><span>汽車管理</span></h2>
            <table border="1" width="100%" class="tab">
                <tr>
                    <th>序列</th>
                    <th>編號</th>
                    <th>名稱</th>
                    <th>價格</th>
                    <th>顏色</th>
                    <th>速度</th>
                    <th>操作</th>
                </tr>
                <tr ng-repeat="c in cars">
                    <td>{{$index+1}}</td>
                    <td>{{c.id}}</td>
                    <td>{{c.name}}</td>
                    <td>{{c.price}}</td>
                    <td>{{c.color}}</td>
                    <td>{{c.speed}}</td>
                    <td>
                        <a href="#" ng-click="del(c.id)">刪除</a>
                        <a href="#" ng-click="edit(c)">編輯</a>
                    </td>
                </tr>
            </table>
            <fieldset>
                <legend>汽車詳細</legend>
                <p>
                    <label for="id">編號</label>
                    <input ng-model="car.id" id="id" ng-readonly="true" />
                </p>
                <p>
                    <label for="name">名稱</label>
                    <input ng-model="car.name" id="name" />
                </p>
                <p>
                    <label for="price">價格</label>
                    <input ng-model="car.price" id="price" />
                </p>
                <p>
                    <label for="color">顏色</label>
                    <input ng-model="car.color" id="color" />
                </p>
                <p>
                    <label for="color">速度</label>
                    <input ng-model="car.speed" id="speed" />
                </p>
                <button ng-click="save()" class="btn">保存</button>
                <button ng-click="clear()" class="btn">清空</button>
            </fieldset>
        </form>

        <!--引入angularjs框架-->
        <script src="js/angular146/angular.min.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            //定義模塊,指定依賴項為空
            var carApp = angular.module("carApp", []);

            //定義控制器,指定控制器的名稱,$scope是全局對象
            carApp.controller("CarController", ['$scope', '$http', function($scope, $http) {
                $scope.cars = [];
                $scope.save = function() {
                    $http({
                        url:"http://127.0.0.1:3000/cars/car",
                        data:$scope.car,
                        method: $scope.car.id?"PUT":"POST"
                        })
                        .success(function(data, status, headers, config) {
                            if($scope.car.id){
                               alert("修改成功");
                             }else{
                                 $scope.cars.push(data);
                             }
                        })
                        .error(function(data, status, headers, config) {
                            alert(status);
                        });
                }
                
                $scope.edit=function(c){
                    $scope.car=c;
                }
                $scope.clear=function(){
                    $scope.car={};
                }
            
                $http.get("http://127.0.0.1:3000/cars")
                    .success(function(data, status, headers, config) {
                        $scope.cars = data;
                    })
                    .error(function(data, status, headers, config) {
                        alert(status);
                    });

                $scope.del = function(id) {
                    $http.delete("http://127.0.0.1:3000/cars/id/" + id)
                        .success(function(data, status, headers, config) {
                            $scope.cars = data;
                        })
                        .error(function(data, status, headers, config) {
                            alert(status);
                        });
                }
            }]);
        </script>
    </body>

</html>

運行結果:

問題:如果后台服務不是Restful,不接收application/json的參數,則需要修改。Angular的post和put請求Content-Type: application/json默認情況下,jQuery傳輸數據使用Content-Type: x-www-form-urlencodedand和類似於"foo=bar&baz=moe"的序列,然而AngularJS,傳輸數據使用Content-Type: application/json和{ "foo": "bar", "baz": "moe" }這樣的json序列。請求時修改請求頭部內容:

headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' }

$httpParamSerializerJQLike 序列化參數,這個服務需要單獨依賴。

示例:

結果:

1.1.3、AngularJS Crome插件

AngularJS Batarang是一個顯示AngularJS的scope 層次的Chrome插件,有效的快速查看一個page 中有多少Scope能夠幫助我們快速方便調試AngularJS程序。

1.2、自定義服務

AngularJS在內置服務中提供了大量的功能,不過這些服務不一定能滿足你的需求,你可以通過自定義服務解決。可以將服務看作一個或多個相關任務的一塊可重用代碼。

創建自定義服務有4種主要類型:value,constant,factory,service

1.2.1、創建value服務

定義單個值的簡單服務,模塊的配置階段是不可以使用的。
module.value('key',{color:'blue',value:'17'})

1.2.2、創建constant服務

也value服務一樣,不過在模塊的配置階段是可以使和的。

module.value(“key”,”value”);

1.2.3、創建factory服務

提供了把功能實現到服務中的能力。

也可以把其它服務注入到factory中。

1.2.4、創建Service服務

factory是普通function,而service是一個構造器(constructor),這樣Angular在調用service時會用new關鍵字,而調用factory時只是調用普通的function,所以factory可以返回任何東西,而service可以不返回

示例代碼:

<!DOCTYPE html>
<!--指定angular管理的范圍-->
<html ng-app="app01">
    <head>
        <meta charset="UTF-8">
        <title>服務</title>
    </head>
    <body>
        <!--指定控制器的作用范圍-->
        <form ng-controller="Controller1" name="form1">
            <p>
                半徑:<input ng-model="r" ng-init="r=1"/>
            </p>
            <p>
                周長:{{circleLength}}
            </p>
            <p>
                面積:{{circleArea}}
            </p>
        </form>
        <!--引入angularjs框架-->
        <script src="js/angular146/angular.min.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            //定義模塊,指定依賴項為空
            var app01 = angular.module("app01", []);
            
            //value服務
            app01.value("i",100);
            
            //constant服務
            app01.constant("PI",3.14);
            
            //factory服務
            app01.factory("getArea",['i','PI',function(i,PI){
                return function(radius){
                    return PI*(radius+i)*(radius+i);
                };
            }])
            
            function circleMethod(i,PI,getArea){
                this.getLength=function(radius){
                    return 2*PI*radius;
                };
                this.getSize=function(radius){
                    return getArea(radius);
                }
            }
            //service服務
            app01.service("circleService",circleMethod);
            
            //定義控制器,指定控制器的名稱,$scope是全局對象
            app01.controller("Controller1", function($scope,circleService) {
                $scope.$watch("r",function(){
                    $scope.circleLength=circleService.getLength($scope.r);
                    $scope.circleArea=circleService.getSize($scope.r);
                });
            });
        </script>
    </body>
</html>

運行結果:

二、路由

單頁Web應用由於沒有后端URL資源定位的支持,需要自己實現URL資源定位。angularjs使用瀏覽器URL "#" 后的字符串來定位資源,區分不同的功能模塊。
路由並非在angularjs核心文件內,你需要另外加入一段腳本 “angular-route.min.js”需要注意的是在創建 “app” 對象是需要填寫對 ngRoute 依賴

示例代碼:

routeTest.html 單頁程序的首頁

<!DOCTYPE html>
<html ng-app="app">

    <head>
        <meta charset="utf-8">
        <title>路由展示</title>
        <style>
            a {
                color: #333;
                text-decoration: none;
            }
            
            a:hover {
                color: orangered;
            }
        </style>
    </head>

    <body>
        <p>
            <a href="#/">返回列表</a>
            <a href="#/t1">當前時間</a>
            <hr />
        </p>
        <div ng-view></div>
        <script src="js/angular146/angular.min.js" type="text/javascript" charset="utf-8"></script>
        <script src="js/angular146/angular-route.min.js" type="text/javascript" charset="utf-8"></script>
        <script id="t1" type="text/ng-template">
            當前時間是:{{currentDate}}
        </script>
        <script type="text/javascript">
            var app = angular.module("app", ['ngRoute']);
            app.config(function($routeProvider) {
                $routeProvider.when('/', {
                    controller: 'listController',
                    templateUrl: 'list.html'
                });
                $routeProvider.when('/t1', {
                    controller: 't1Controller',
                    templateUrl: 't1'
                });
                $routeProvider.when('/detail/:id', {
                    controller: 'detailController',
                    templateUrl: 'detail.html'
                });
                $routeProvider.otherwise({
                    redirectTo: '/'
                });
            });
            app.service("dataService", function() {
                this.list = [{
                    id: 1,
                    title: '谷歌',
                    url: 'http://www.google.com'
                }, {
                    id: 2,
                    title: '百度',
                    url: 'http://www.baidu.com'
                }, {
                    id: 3,
                    title: '必應',
                    url: 'http://www.bing.com'
                }, {
                    id: 4,
                    title: '搜狗',
                    url: 'http://www.sogou.com'
                }, {
                    id: 5,
                    title: '雅虎',
                    url: 'http://www.yahoo.cn'
                }];
                this.getEntity = function(id) {
                    var result = null;
                    angular.forEach(this.list, function(obj, index) {
                        if(obj.id == id) {
                            result = obj;
                        }
                    });
                    return result;
                }
            });
            app.controller("listController", function($scope, dataService) {
                
                $scope.items = dataService.list;
            });
            app.controller("detailController", function($scope, dataService, $routeParams) {
                
                $scope.obj = dataService.getEntity($routeParams.id);
            });
            app.controller("t1Controller", function($scope) {
                $scope.currentDate = new Date().toLocaleString();
            });
        </script>
    </body>

</html>

列表頁 list.html

<ul ng-repeat="item in items">
    <li>
        <a href="#/detail/{{item.id}}">{{item.title}}</a>
    </li>
</ul>

詳細頁 detail.html:

<fieldset>
    <legend>詳細信息</legend>
    <p>
        編號:{{obj.id}}
    </p>
    <p>
        名稱:{{obj.title}}
    </p>
    <p>
        網址: <a href="{{obj.url}}">{{obj.url}}</a>
    </p>
</fieldset>

運行結果:

三、內置API

3.1、數據轉換

示例:

默認情況JavaScript中對象是傳引用的:

                var tom={name:"tom",age:18,height:198};
                var tomClone=tom;
                
                tomClone.name="superTom";
                
                console.log(tom);
                console.log(tomClone);

結果:

修改后的示例:

                var tom={name:"tom",age:18,height:198};
                var tomClone=tom;
                var tome={}
                angular.copy(tom,tome);
                
                tomClone.name="superTom";
                
                console.log(tom);
                console.log(tomClone);
                console.log(tome);

修改后的結果:

3.2、JSON相關API

3.3、數據比較API

四、jQuery Lite

jQuery Lite只是jQuery的一個簡化版本,它直接內置於AngularJS中。

支持的jQuery方法如下,但有些方法在功能上並非完全一樣。

addClass after append attr bind children clone
contents css data detach empty eq find hasClass
html text on off one parent prepend prop ready
remove removeAttr removeClass removeData replaceWith toggleClass triggerHandler unbind
val wrap
附加事件方法:$destory,controller(name),injector,Scope,isolateScope,inheritedData()

如果需要使用jQuery完整版本的額外功能,那么可以在加載AngularJS庫之前引入jQuery庫。
<script src=jquery.min.js>
<script src=angular.min.js>
在自定義指令中link:function(scope,elem,attrs,controller) elem is a jQuery Lite對象

使用時一定要記得將DOM對象轉換成jQuery Lite對象

示例代碼:

<!DOCTYPE html>
<!--指定angular管理的范圍-->
<html ng-app="app01">
    <head>
        <meta charset="UTF-8">
        <title>jQueryLite</title>
    </head>
    <body>
        <!--指定控制器的作用范圍-->
        <form ng-controller="Controller1" name="form1">
            <div id="div1" style="height:100px;background: lightgreen;">jQueryLite</div>
        </form>
        <!--引入angularjs框架-->
        <script src="js/angular146/angular.min.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            //定義模塊,指定依賴項為空
            var app01 = angular.module("app01", []);

            //定義控制器,指定控制器的名稱,$scope是全局對象
            app01.controller("Controller1", ['$scope','$window',function($scope,$win) {
                
                var div1=document.querySelector("#div1");
                var adiv1=angular.element(div1);
                adiv1.on("click",function(){
                    adiv1.css({"background":"lightblue"}).html("Hello "+adiv1.html());
                    adiv1.off();
                });
                
            }]);
        </script>
    </body>
</html>

運行結果:

五、zeptojs

zeptojs是一輕量版的jQuery,擁有多數的jQuery功能,但體積要小很多,gzip后只有約9.6k。

官網:http://zeptojs.com/

倉庫:https://github.com/madrobby/zepto

安裝:npm install zepto

瀏覽器支持:

  • Safari 6+ (Mac)
  • Chrome 30+ (Windows, Mac, Android, iOS, Linux, Chrome OS)
  • Firefox 24+ (Windows, Mac, Android, Linux, Firefox OS)
  • iOS 5+ Safari
  • Android 2.3+ Browser
  • Internet Explorer 10+ (Windows, Windows Phone)

WebAPI域

1、新建4.5版以上的WebAPI項目

2、安裝Microsoft.AspNet.WebApi.Cors

Install-Package Microsoft.AspNet.WebApi.Cors

3、修改app_start目錄下的WebApiConfig.cs文件,增加如下代碼:

            //第1*表示域 如www.abc.com
            //第2*表示允許的頭部
            //第3*表示方法(謂詞)
            config.EnableCors(new EnableCorsAttribute("*", "*", "*"));

4、如果只想控制某一個控制器,則可以使用注解,特性。

    [EnableCors("*","*","*")]
    public class ValuesController : ApiController

六、示例下載

后台服務:https://git.coding.net/zhangguo5/NodeJSExpress.git

前端腳本:https://github.com/zhangguo5/Angular03.git


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM