AngularJS學習筆記

1. 介紹

AngularJS是一款由Google公司開發維護的前端MVC框架,其克服了HTML在構建應用上的諸多不足,從而降低了開發成本提升了開發效率。

1.1 特點

AngularJS與jQuery有什么區別?

jQuery更準確來說只一個類庫(類庫指的是一系列函數的集合),是以DOM做為驅動。
而AngularJS則一個框架(諸多類庫的集合)是以數據和邏輯做為驅動。

框架對開發的流程和模式做了約束,開發者遵照約束進行開發,更注重的實際的業務邏輯。

AngularJS有著諸多特性,最為核心的是:模塊化雙向數據綁定、語義化標簽、依賴注入等。

1.2 MVC

MVC是一種開發模式,把網頁分成模型(Model)、視圖(View)、控制器(Controller)3部分構成。

模型(Model)用來處理數據(讀取/設置),一般指操作數據庫。
視圖(View)用來展示數據,比如通過HTML展示。
控制器(Controller)用做連接模型和視圖的橋梁。

MVC更多應用在后端開發程序里,后被引入到前端開發中,由于受到前端技術的限制便有了一些細節的調整,進而出現了很多MVC的衍生版(子集)如MVVM、MVW、MVP、MV*等。

2. AngularJS的模塊化

使用AngularJS構建應用(App)時是以模塊化(Module)的方式組織的,即將整個應用劃分成若干模塊,每個模塊都有各自的職責,最終組合成一個整體。采用模塊化的組織方式,可以最大程度的實現代碼的復用。

2.1 使用AngularJS的HTML基本結構

2.1.1 定義應用

通過為任一HTML標簽添加ng-app屬性,可以指定一個應用,表示此標簽所包裹的內容都屬于應用(App)的一部分。

<!-- 為html標簽添加ng-app表明整個文檔都是應用 -->
<!-- ng-app屬性可以不賦值,但是要關聯到相應模塊時則必須賦值 -->
<html lang="en" ng-app='App'>

2.1.2 定義模塊

AngularJS提供了一個全局對象angular,在此全局對象下存在若干的方法,其中angular.module()方法用來定義一個模塊。

// 通過module方法定義模塊
// 有兩個參數
// 第一個:表示模塊的名稱
// 第二個:表示此模塊依賴的其他模塊
var app = angular.module( 'app', [] );

2.1.3 定義控制器

控制器(Controller)作為連接模型(Model)和視圖(View)的橋梁存在,所以當我們定義好了控制器以后也就定義好了模型和視圖。

// app是一個模塊實例對象
// 通過這個實例對象定義控制器
// 傳入兩個參數
// 第1個:定義控制器的名稱
// 第2個:一個數組,數組的最后一項是函數,其余是字符串,寫明此控制器的依賴關系
app.controller('StarController', ['$scope', function($scope){
    $scope.students = [
        {name: '周杰倫', gender: '男', age: 39},
        {name: '劉德華', gender: '男', age: 60},
        {name: '孫燕姿', gender: '女', age: 36},
        {name: '王力宏', gender: '男', age: 38},
        {name: '陳小春', gender: '男', age: 42},
    ]
}]);

2.1.4 在視圖中關聯控制器

模型(Model)數據是要展示到視圖(View)上的,所以需要將控制器(Controller)關聯到視圖(View)上,通過為HTML標簽添加ng-controller屬性并賦值相應的控制器(Controller)的名稱,就確立了關聯關系。

<!-- 添加ng-controller屬性,并賦值為相應的控制器名稱 -->
<table ng-controller='StarController'>
    <tr>
        <th>姓名</th>
        <th>性別</th>
        <th>年齡</th>
    </tr>
    <tr ng-repeat='student in students'>
        <td>{{student.name}}</td>
        <td>{{student.gender}}</td>
        <td>{{student.age}}</td>
    </tr>
</table>

2.1.5 整個HTML文檔的結構

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>AngularJS的基本結構</title>
</head>
<body ng-app='app'>
    <table ng-controller='StarController'>
        <tr>
            <th>姓名</th>
            <th>性別</th>
            <th>年齡</th>
        </tr>
        <tr ng-repeat='student in students'>
            <td>{{student.name}}</td>
            <td>{{student.gender}}</td>
            <td>{{student.age}}</td>
        </tr>
    </table>
    <script src="./libs/angular.min.js"></script>
    <script>
        var app = angular.module('app', []);
        app.controller('StarController', ['$scope', function($scope){
            $scope.students = [
                {name: '周杰倫', gender: '男', age: 39},
                {name: '劉德華', gender: '男', age: 60},
                {name: '孫燕姿', gender: '女', age: 36},
                {name: '王力宏', gender: '男', age: 38},
                {name: '陳小春', gender: '男', age: 42},
            ]
        }]);        
    </script>
</body>
</html>
效果

3.指令

3.1 常用內置指令

ng-app 指定應用根元素,至少有一個元素指定了此屬性。不能互相嵌套。

ng-controller 指定控制器

ng-show 控制元素是否顯示,true顯示、false不顯示

ng-hide 控制元素是否隱藏,true隱藏、false不隱藏

ng-if 控制元素是否“存在”,true存在、false不存在(DOM元素存在與否)。

ng-src 增強圖片路徑。如果圖片路徑是src = {{path}}這種形式,并且模型寫在文檔下面,瀏覽器從上至下依次解析代碼到這里時,還沒有解析到模型,當快速刷新網頁時,就會顯示圖片沒有請求到。如果是ng-src={{path}},執行到這里會強制先解析模型中的path,就不會出現未請求到的問題,并且解決了重復請求的問題。

ng-href 增強地址

ng-class 控制類名。它的值可以有兩種形式。ng-class = {{active}}ng-class = {{active : true}},boolen值控制該類名是否存在。

ng-include 引入模板。可以加載一個外部文件。應用時,可以把一些公共部分抽離成一個獨立文件,然后用ng-include = 'src'引入。在沒用AngularJS之前,用的是<?php include(demo.html) ?>。但是,要注意的是,ng-include的地址要是同域的,這是因為,js本身讀取不了本地文件,需要借助請求的方式,并且這種請求不能是跨域的。

ng-disabled 表單禁用。值為boolen值。ng-disabled = true表單禁用。

ng-readonly 表單只讀

ng-checked 單/復選框表單選中,值為boolen值。checked是一個無值屬性,ng-checked = true時,就會存在checked這個屬性。

ng-selected 下拉框表單選中。selected也是一個無值屬性,ng-selected = true時,選中。

ng-repeat 遍歷

3.2 自定義指令

AngularJS允許根據實際業務需要自定義指令,通過angular全局對象下的directive方法實現。

<body ng-app="App">
    <div haoxiang></div>
    <haoxiang></haoxiang>
    <div class="haoxiang"></div>
    <!-- Angular 只認識帶著directive的注釋 -->
    <!-- directive:haoxiang -->
    <script src="./libs/angular.min.js"></script>
    <script>
        var App = angular.module('App', []);

        // 自定義指令
        // App.directive()方法來實現自定義指令
        // 第一個參數,指令名稱
        // 第二個參數,是一個回調函數,在回調函數中實現指令邏輯
        App.directive('haoxiang', function () {
            // 在此實現指令的邏輯
            // 返回一個對象
            // 對象里的內容是固定的
            return {
                // A 是單詞 attribute 首字母,將指令當屬性來用,帶有haoxiang這個屬性的元素就加載下面的模板
                // E 是單詞 element   首字母,將指令當標簽來用,haoxiang標簽就加載下面的模板
                // C 是單詞 class     首字母,將指令當類來用,擁有haoxiang這個類名的元素就加載下面的模板
                // M 是單詞 mark      首字母,將指令將注釋來用
                restrict: 'ECMA',
                replace: true,
                // 定義模板
                template: '<div><h1>Hello AngularJS!</h1>',
                // 要求所有html模板中的元素,在同一個根元素下
                template: '<div><h1>Hello AngularJS!</h1><a href="#">百度</a></div>',
                // 下面這種寫法就是錯的,因為兩個元素不在一個根元素下
                template: '<h1>Hello AngularJS!</h1><a href="#">百度</a>',
                // 當模板內容太多,可以把模板放在獨立的html文檔中
                // 注意:使用這種方式,要放在服務器環境下,保證同域名
                // 同樣,這個html文檔中的各個元素也要在同一個根目錄下
                templateUrl: './Hello.html',
                // 也可以添加一些方法,比較復雜,這里不做介紹
                link: function () {
                    // 
                },
                compile: function () {
                    // 
                }
            }
        });
    </script>
</body>

4.數據綁定

AngularJS是以數據做為驅動的MVC框架,所有模型(Model)里的數據經由控制器(Controller)展示到視圖(View)中。

所謂數據綁定指的就是將模型(Model)中的數據與相應的視圖(View)進行關聯,分為單向綁定和雙向綁定兩種方式。

4.1 單向綁定

單向數據綁定是指將模型(Model)數據,按著寫好的視圖(View)模板生成HTML標簽,然后追加到DOM中顯示。

4.2 雙向綁定

雙向綁定則可以實現模型(Model)數據和視圖(View)模板的雙向傳遞。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>數據綁定</title>
</head>
<body ng-app='App'>
    <div class="box" ng-controller="DemoCtrl">
        <form action="">
            <input type="text" ng-model="msg">
            <input type="button" value="顯示" ng-click="show()">
        </form>
        <p>您輸入的是:{{msg}}</p>
    </div>
    <script src="./libs/angular.min.js"></script>
    <script>
        var App = angular.module('App', []);
        App.controller('DemoCtrl', ['$scope', function ($scope) {
            $scope.show = function () {
                alert($scope.msg);
            }
        }]);
    </script>
</body>
</html>

4.3 相關指令

{{}} 和 ng-bind
在AngularJS中通過{{}}或者ng-bind指令來實現模型(Model)數據向視圖模板(View)的綁定,模型數據通過一個內置服務$scope來提供,這個$scope是一個空對象,通過為這個對象添加屬性或者方法便可以在相應的視圖(View)模板里被訪問。

{{}}ng-bind的簡寫形式,但是它們還有區別。
第1個區別。ng-bind不能綁定多個數據,如ng-bind = 'name age'這種寫法是錯誤的。可以寫成{{name}}{{age}}。通過ng-bind-template可以綁定多個數據。
第2個區別。通過{{}}綁定數據時會有“閃爍”現象,ng-bind不會有閃爍現象。{{}}使用方便,為標簽添加ng-cloak并將script標簽移到上面可以解決“閃爍”現象。原理:頁面載入時,載入到引入angular的script標簽時,會自動在頁面中添加style,為添加了ng-cloak的標簽設置display=none,隱藏了添加了ng-cloak的標簽,解析完寫了模型的script后再將其顯示。

ng-model
通過為表單元素添加ng-model指令實現視圖(View)模板向模型(Model)數據的綁定。

ng-init
通過ng-init可以初始化模型(Model)也就是$scope。

<body ng-app="App">
    <div ng-controller="DemoCtrl" ng-init="title='學習內容'; info='Angular'">
        <h1>{{title}}{{info}}</h1>
    </div>
    <script src="./libs/angular.min.js"></script>
    <script>
        var App = angular.module('App', []);
        App.controller('DemoCtrl', ['$scope', function ($scope) {

        }])
    </script>
</body>

事件處理
AngularJS對事件也進行了擴展,無需顯式的獲取DOM元素便可以添加事件,易用性變的更強。通過在原有事件名稱基礎上添加ng-做為前綴,然后以屬性的形式添加到相應的HTML標簽上即可。如ng-click、ng-dblclick、ng-blur等。

<body ng-app='App'>
    <div class="box" ng-controller="DemoCtrl">
        <li ng-click="single()">單擊事件</li>
        <li ng-dblclick="double()">雙擊事件</li>
        <li ng-mouseover="xuanting()">懸停事件</li>
        <li ng-mouseout="likai()">離開事件</li>
    </div>

    <script src="./libs/angular.min.js"></script>
    <script>
        var App = angular.module('App', []);

        App.controller('DemoCtrl', ['$scope', function ($scope) {
            $scope.single = function () {
                alert('單擊事件');
            }

            $scope.double = function () {
                alert('雙擊事件');
            }

            $scope.xuanting = function () {
                console.log('鼠標來了');
            }

            $scope.likai = function () {
                console.log('鼠標走了');
            }
        }]);
    </script>
</body>

ng-repeat
通過ng-repeat可以將數組或對象數據迭代到視圖模板中,ng-switch on配合ng-switch-when可以對數據進行篩選。

<body ng-app="App">
    <div ng-controller="DemoCtrl">
        <ul>
            <!-- 兩種寫法 -->
            <li ng-repeat="item in list" ng-bind="item"></li>
            <li ng-repeat="item in list">{{item}}</li>
        </ul>
        <ul>
            <li ng-repeat="(key, val) in list">
                {{key}}:{{val}}
            </li>
        </ul>       
        <table>
            <tr ng-repeat="(key, val) in obj">
                <td>{{key}}</td>
                <td>{{val}}</td>
            </tr>
        </table>

        <!-- 例如只有當值為css才顯示 -->
        <ul>
            <!-- 寫不寫on都可以 -->
            <li ng-repeat='item in list' ng-switch on='item'>
                <span ng-switch-when='css'>{{item}}</span>
            </li>

            <li ng-repeat="item in list" ng-switch="item">
                <a href="javascript:;" ng-switch-when="js">{{item}}</a>
            </li>
        </ul>
    </div>
    <script src="./libs/angular.min.js"></script>
    <script>
        var App = angular.module('App', []);
        App.controller('DemoCtrl', ['$scope', function ($scope) {
            $scope.list = ['html', 'css', 'js'];
            $scope.obj = {
                name: '小明',
                age: 18,
                sex: '男',
                hobby: '吹牛'
            }
        }]);
    </script>
</body>

一個Tab欄切換小demo

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Tab 標簽</title>
    <style>

        body {
            margin: 0;
            padding: 0;
            background-color: #F7F7F7;
        }
    
        .tabs {
            width: 400px;
            margin: 30px auto;
            background-color: #FFF;
            border: 1px solid #C0DCC0;
            box-sizing: border-box;
        }

        .tabs nav {
            height: 40px;
            text-align: center;
            line-height: 40px;
            overflow: hidden;
            background-color: #C0DCC0;
            display: flex;
        }

        nav a {
            display: block;
            width: 100px;
            border-right: 1px solid #FFF;
            color: #000;
            text-decoration: none;
        }

        nav a:last-child {
            border-right: 0 none;
        }

        nav a.active {
            background-color: #9BAF9B;
        }

        .cont {
            overflow: hidden;
        }

        .cont ol {
            line-height: 30px;
        }

    </style>
</head>
<body ng-app="Tabs">

    <div class="tabs" ng-controller="TabCtrl">
        <nav>
            <a href="javascript:;" ng-class="{active: active == 'local'}" ng-click="change('local')">國內新聞</a>
            <a href="javascript:;" ng-class="{active: active == 'global'}" ng-click="change('global')">國際新聞</a>
            <a href="javascript:;" ng-class="{active: active == 'sports'}" ng-click="change('sports')">體育新聞</a>
            <a href="javascript:;" ng-class="{active: active == 'funny'}" ng-click="change('funny')">娛樂新聞</a>
        </nav>
        <div ng-switch on="active">
            <section class="cont" ng-switch-when="local">
                <ol>
                    <li>國內新聞</li>
                </ol>
            </section>
            <section class="cont" ng-switch-when="global">
                <ol>
                    <li>國際新聞</li>
                </ol>
            </section>
            <section class="cont" ng-switch-when="sports">
                <ol>
                    <li>體育新聞</li>
                </ol>
            </section>
            <section class="cont" ng-switch-when="funny">
                <ol>
                    <li>娛樂新聞</li>
                </ol>
            </section>
        </div>
    </div>
    <script src="../libs/angular.min.js"></script>
    <script>
        var Tabs = angular.module('Tabs', []);
        Tabs.controller('TabCtrl', ['$scope', function ($scope) {
            // 定義初始狀態
            $scope.active = 'local';
            $scope.change = function (key) {
                $scope.active = key;
            }
        }]);
    </script>
</body>
</html>

5.作用域

通常AngularJS中應用(App)是由若干個視圖(View)組合成而成的,而視圖(View)又都是HTML元素,并且HTML元素是可以互相嵌套的,另一方面視圖都隸屬于某個控制器(Controller),進而控制器之間也必然會產生嵌套關系。

每個控制器(Controller)又都對應一個模型(Model)也就是$scope對象,不同層級控制器(Controller)下的$scope便產生了作用域。

可以參考JavaScript中函數的作用域來理解。

5.1 全局作用域(根作用域)

一個AngularJS的應用(App)在啟動時會自動創建一個根作用域$rootScope,這個根作用域在整個應用范圍(ng-app所在標簽以內)都是可以被訪問到的。

5.2 子作用域

通過ng-controller指令可以創建一個子作用域,每當有一個控制器就有一個子作用域,新建的作用域可以訪問其父作用域的數據。

例子

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>AngularJS 作用域</title>
</head>
<!-- ng-app 所屬標簽所在的作用域就是根作用域 -->
<body ng-app="App" ng-init="name='努爾哈赤'">
    <div class="parent" ng-controller="ParentCtrl">
        <dl>
            <dt>{{name}}</dt>
            <dd>1200</dd>
        </dl>
        <div class="child" ng-controller="ChildCtrl">
            <dl>    
                <dt>{{name}}</dt>
                <dd>1100</dd>
            </dl>
            <div class="son" ng-controller="SonCtrl">
                <dl>
                    <dt>{{name}}</dt>
                    <dd>1000</dd>
                </dl>
            </div>
        </div>
    </div>
    <script src="./libs/angular.min.js"></script>
    <script>
        var App = angular.module('App', []);
        App.controller('DemoCtrl', ['$scope', function ($scope) {

        }]);
        // 什么是AngularJS的作用域:當div的嵌套導致控制器的嵌套,被嵌套的控制器可以訪問到父級控制器中的數據
        // 就像函數作用域一樣

        // 父
        App.controller('ParentCtrl', ['$scope', function ($scope) {

            $scope.name = '順治';
        }]);

        // 子
        App.controller('ChildCtrl', ['$scope', function ($scope) {

            $scope.name = '康熙';
        }]);

        // 孫
        App.controller('SonCtrl', ['$scope', function ($scope) {

            $scope.name = '雍正';
        }]);

        // 根作用域:ng-app 所屬標簽所在的作用域就是根作用域
        // 子作用域:每當有一個控制器,就有一個子作用域
    </script>
</body>
</html>

6.過濾器

在AngularJS中使用過濾器格式化展示數據,在“{{}}”中使用“|”來調用過濾器,使用“:”傳遞參數。

6.1 內置過濾器

  1. currency將數值格式化為貨幣格式
  2. date日期格式化,年(y)、月(M)、日(d)、星期(EEEE/EEE)、時(H/h)、分(m)、秒(s)、毫秒(.sss),也可以組合到一起使用。
  3. filter在給定數組中選擇滿足條件的一個子集,并返回一個新數組,其條件可以是一個字符串、對象、函數
  4. json將Javascrip對象轉成JSON字符串。
  5. limitTo取出字符串或數組的前(正數)幾位或后(負數)幾位
  6. lowercase將文本轉換成小寫格式
  7. uppercase將文本轉換成大寫格式
  8. number數字格式化,可控制小位位數
  9. orderBy對數組進行排序,第2個參數布爾值可控制方向,true倒序

例子

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>AngularJS 過濾器</title>
    <style>
        dl {
            line-height: 40px;
        }
    
        dt {
            font-size: 18px;
            font-weight: bold;
        }

        dd {
            margin: 0;
        }
    </style>
</head>
<body ng-app="App">
    <dl ng-controller="DemoCtrl">
        <dt>使用過濾器將數據處理成一定的格式再進行展示</dt>
        <dd>當前時間為: {{now|date:'yyyy-MM-d h:m:s EEEE'}}</dd>
        <dd>價格: {{price|currency:'¥':3}}</dd>
        <dd>介紹: {{info|uppercase}}</dd>
        <dd>介紹2: {{brief|lowercase}}</dd>
        <!-- 過濾器可以被連續使用 -->
        <dd>介紹3: {{brief|lowercase|uppercase}}</dd>
        <dd>limitTo: {{info|limitTo:4}}</dd>
        <dd>limitTo: {{info|limitTo:-4}}</dd>
        <dd>limitTo: {{list|limitTo:2}}</dd>
        <dd>limitTo: {{list|limitTo:-2}}</dd>
        <dd>number: {{num|number:2}}</dd>
        <dd>number: {{num1|number}}</dd>
        <dd>json: {{list|json}}</dd>
        <dd>json: {{obj|json}}</dd>
        <!-- 正序 -->
        <dd>orderBy: {{list|orderBy}}</dd>
        <!-- 默認第二個參數為false,正序 -->
        <dd>orderBy: {{list|orderBy:'':false}}</dd>
        <!-- 倒序 -->
        <dd>orderBy: {{list|orderBy:'':true}}</dd>
        <!-- 第一個參數指:以誰為排序方式 -->
        <dd>orderBy: {{students|orderBy:'score':true}}</dd>
        <!-- 把包含s的拿出來 -->
        <dd>filter: {{list|filter:'s'}}</dd>
        <!-- 把男的拿出來 -->
        <!-- 注意:{} 后面一定要跟著一個空格,否則會報錯 -->
        <dd>filter: {{students|filter:{sex:'男'} }}</dd>
    </dl>
    <script src="./libs/angular.min.js"></script>
    <script>

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

        App.controller('DemoCtrl', ['$scope', function ($scope) {
            // 當前時間
            $scope.now = new Date();

            $scope.price = 12.345;

            $scope.info = 'my name is brother';

            $scope.brief = 'My age is 18';

            $scope.list = ['html', 'js', 'php', 'css', 'photoshop'];

            // number 過濾器功能是保留幾個小數位  并不能轉換數值 例如'123abc' 不能 轉成 123
            // 但是 字符串'123' 可以轉成 數字123
            $scope.num = '12.345';

            $scope.num1 = '123abc';

            $scope.obj = {
                name: 'jack',
                age: 10
            }

            $scope.students = [
                {name: '小明', sex: '男', age: 18, score: 94},
                {name: '小米', sex: '女', age: 19, score: 92},
                {name: '小雷', sex: '男', age: 16, score: 98},
                {name: '小花', sex: '女', age: 19, score: 91}
            ];
        }]);
    </script>
</body>
</html>

6.2 自定義過濾器

通過模塊對象實例提供的filter方法自定義過濾器。

<body ng-app="App">

    <div class="box" ng-controller="DemoCtrl">
        {{str|uppercase}}
        <!-- AngularJS 在使用"|"調用過濾器時會將前面的數據str當成參數傳遞給下面的自定義函數 -->
        {{str|yell:'我是一個參數':123456}}
        {{str|slice:3}}
        <h1>{{str|capitalize}}</h1>
    </div>

    <script src="./libs/angular.min.js"></script>
    <script>
        var App = angular.module('App', []);

        App.controller('DemoCtrl', ['$scope', function ($scope) {
            $scope.str = 'hello angular!';
        }]);


        // App.filter()可以自定義過濾器
        // 第一個參數 過濾器名稱
        // 第二個參數 回調函數
        App.filter('yell', function () {
            return function (arg, arg2, arg3) {
                // arg 就是 str
                // arg2 就是 '我是一個參數'
                // arg3 就是 123456
                console.log(arg); //hello angular!
                console.log(arg2); //'我是一個參數'
                console.log(arg3); //123456
            }
        });

        // 模擬字符串截取功能
        App.filter('slice', function () {
            return function (input, length) {
                // input 就是需要格式化處理的數據
                // length 表示截取幾個長度
                return input.slice(0, length);
            }
        });

        // 首字母大寫功能
        App.filter('capitalize', function () {
            return function (input) {
                // input 就是需要格式化處理的數據
                console.log(input[0])
                return input[0].toUpperCase() + input.slice(1);
            }
        });

        
    </script>
</body>

7. 依賴注入

AngularJS采用模塊化的方式組織代碼,將一些通用邏輯封裝成一個對象或函數,實現最大程度的復用,這導致了使用者和被使用者之間存在依賴關系。

所謂依賴注入是指在運行時自動查找依賴關系,然后將查找到依賴傳遞給使用者的一種機制。

常見的AngularJS內置服務有$http、$location、$timeout、$rootScope等

依賴注入有兩種方式:推斷式注入和行內注入。

7.1 推斷式注入

沒有明確聲明依賴,AngularJS會將函數參數名稱當成是依賴的名稱。

這種方式會帶來一個問題,當代碼經過壓縮后函數的參數被壓縮,這樣便會造成依賴無法找到。

// 這個控制器依賴$scope, $http服務
// 未明確聲明依賴,這時會自動將函數傳入的參數名當成依賴對待
App.controller('DemoCtrl', function ($scope, $http) {
    
});

7.2 行內注入

以數組形式明確聲明依賴,數組元素都是包含依賴名稱的字符串,數組最后一個元素是依賴注入的目標函數。

推薦使用這種方式聲明依賴

App.controller('DemoCtrl', ['$scope', '$http', function ($scope, $http) {

}]);

8.服務

服務是一個對象或函數,對外提供特定的功能。

8.1 內建服務

8.1.1 $location

$location是對原生Javascript中location對象屬性和方法的封裝。

<script>
    var App = angular.module('App', []);

    // $location服務用來獲取地址信息,與原生BOM對象 location 類似

    App.controller('DemoCtrl', ['$location', '$scope', function ($location, $scope) {

        console.log($location);

        $scope.absUrl = $location.absUrl();

        $scope.host = $location.host();

        $scope.port = $location.port();

        $scope.protocol = $location.protocol();

        // AngularJS在原有基礎上重新定義了地址的組成部分
        // AngularJS認為第1個#后面的?才是請求參數
        $scope.search = $location.search();

        // AngularJS 認為第1個#號不表示錨點
        // 如果再次出現#才認為錨點
        $scope.hash = $location.hash();

        // path:與原生的pathname相對應
        // AngularJS 認為第1個#號開始之后的/之后的部分屬于path,不包含請求參數
        $scope.path = $location.path();

    }]);

    // location.search:地址上 ? 后的數據,表示參數
    // location.hash:地址上 # 后的數據,表示錨點,也叫hash
    // location.pathname:地址從根(/)開始的部分,不包含請求參數

    // AngularJS 實質上是將原生BOM對象的location.hash
    // 進行了封裝,重新定義的了 path hash search
    // 重新定義之后的path hash search,都是從第一個#之后才開始算

</script>

8.1.2 $timeout&$interval

$timeout&$interval對原生Javascript中的setTimeout和setInterval進行了封裝。

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

App.controller('DemoCtrl', ['$scope', '$timeout', '$interval', function ($scope, $timeout, $interval) {

    // 延時執行
    $timeout(function () {
        console.log('延時了3秒')
    }, 3000);

    // 取消延時
    $timeout.cancel();

    // 間歇函數
    $interval(function () {
        console.log(1);
    }, 500);

    // 一秒刷新一下時間
    var timer = $interval(function () {
        $scope.now = new Date();
    }, 1000);

    $scope.stop = function () {
        $interval.cancel(timer);
    }

}]);;

8.1.3 $filter

$filter在控制器中格式化數據。

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

// $filter是過濾器,過濾器可以在視圖中使用{{|}},也可在模型中使用

App.controller('DemoCtrl', ['$scope', '$filter', function ($scope, $filter) {

    // AngularJS 自帶的過濾器有9種

    // $filter是一個函數,傳遞不同的參數會返回不同具體功能的過濾器

    // $filter('date') 其返回值就是一個格式化時間的過濾器
    // $filter('currency') 其返回值就是一個格式化貨幣的過濾器
    // $filter('uppercase')、$filter('limitTo') ....

    // 原始數據
    var now = new Date;
    // 時間過濾器
    var date = $filter('date');
    // 格式化數據
    now = date(now, 'yyyy-MM-dd H:m:s');
    $scope.now = now;

    var list = ['html', 'css', 'js', 'php', 'node'];
    var limitTo = $filter('limitTo');
    list = limitTo(list, 3);
    $scope.list = list;

    // 原始信息
    var content = 'my name is xiaoming';
    // 創建過濾器
    var uppercase = $filter('uppercase');
    // 格式化數據
    $scope.content = uppercase(content);

}]);

8.1.4 $log

$log打印調試信息。

App.controller('DemoCtrl', ['$scope', '$log', function ($scope, $log) {

    // $log 是一個對象

    $log.log('調試信息');

    $log.info('調試信息');

    $log.error('調試信息,錯了嗎?');

    $log.warn('調試信息,警告');

    $log.debug('調試信息');

}]);

8.1.5 $http

$http用于向服務端發起異步請求。

App.controller('DemoCtrl', ['$scope', '$http', function ($scope, $http){
    // 發起異步請求
    $http({
        method: 'post',
        url: 'demo.php',
        data: {name: 'xule', age: 10},
        headers: {'Content-Type': 'application/x-www-form-urlencoded'}
    }),success(function (info){
        // 可以把服務端返回的數據綁定到模型上
        $scope.result = info;
    }),error(function (info)){
    };
}]);

要注意的是,請求方式不同,傳遞的數據格式也不同。

(1)當請求方式為post時,有兩種寫法。

數據為key=val&key1=val1格式時,需要通過Content-Type告知其類型為application/x-www/form-urlencoded。

數據為{key: val, key1: val1}格式時,需要通過Content-Type告知其類型為application/json。但是AngularJS默認使用這種格式,這里的headers可以寫也可以不寫。

$http({
    url: 'example.php',
    method: 'post',
    headers: {
        'Content-Type': 'application/x-www-form-urlencoded'
    },
    data: {'name=ming&age=11'}
});
$http({
    url: 'example.php',
    method: 'post',
    // 這里的headers可以寫也可以不寫,默認就是這種形式
    headers: {
        'Content-Type': 'application/json'
    },
    data: {name: 'ming', age: 11}
});

(2)當請求為get方式,使用params專門傳遞get方式的數據

$http({
    url: 'example.php',
    method: 'get',
    params: {age: 11},
});

如何處理跨域請求呢

通過get方式傳遞一個事先定義好的函數名,這里有固定的寫法:params: {callback: 'JSON_CALLBACK'},JSON_CALLBACK即為"事先定義好的函數名",JSON_CALLBACK是一個占位符,AngularJS 也會像jQuery一樣動態創建一個函數,但是動態創建的函數名不固定,先使用一個占位符JSON_CALLBACK占一個位,當動態函數創建成功后再將這個JSON_CALLBACK進行替換。后臺接收函數名的時候也用JSON_CALLBACK

$http({
    url: ' ',
    params: {callback: 'JSON_CALLBACK'},
    method: 'jsonp'
}).success(function (info) {
    
});             

使用AngularJS的$http服務的跨域獲取天氣信息

這里用的是百度車聯網API中的天氣查詢 - 車聯網API

注意下面兩種傳遞callback的方法,都是可以的。

<!DOCTYPE html>
<html lang="en" ng-app="App">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <!-- 0A5bc3c4fb543c8f9bc54b77bc155724 -->
    <div ng-controller="WeatherController">
        <table>
            <!-- 視圖 -->
            <tr ng-repeat="item in weatherData">
                <td>{{item.date}}</td>
                <td>{{item.temperature}}</td>
                <td>{{item.weather}}</td>
                <td>{{item.wind}}</td>
                <td>![]({{item.dayPictureUrl}})</td>
                <td>![]({{item.nightPictureUrl}})</td>
            </tr>
        </table>
    </div>
    <script src="../libs/angular.min.js"></script>
    <script>
        var App = angular.module('App', []);
        // 定義控制器并聲明依賴
        App.controller('WeatherController', ['$scope', '$http', '$log', function($scope, $http, $log) {
            // 請求數據
            $http({
                method: 'jsonp', 
                url: 'http://api.map.baidu.com/telematics/v3/weather?callback=JSON_CALLBACK',
                params: { // 請求的參數
                    location: '北京',
                    output: 'json',
                    ak: '0A5bc3c4fb543c8f9bc54b77bc155724'
                }
            })
            .success(function (data) {
                $log.log(data); // 成功的回調
                // 請求回的數據放到模型上
                $scope.weatherData = data.results[0].weather_data;
            });

        }])
    </script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body ng-app="App">
    <!-- 0A5bc3c4fb543c8f9bc54b77bc155724 -->
    <div ng-controller="WeatherCtrl">
        <table>
            <tr ng-repeat="weather in weathers">
                <td>{{weather.date}}</td>
                <td>{{weather.temperature}}</td>
                <td>{{weather.weather}}</td>
                <td>{{weather.wind}}</td>
                <td>![]({{weather.dayPictureUrl}})</td>
                <td>![]({{weather.nightPictureUrl}})</td>
            </tr>
        </table>
    </div>
    <script src="../libs/angular.min.js"></script>

    <script>
        var App = angular.module( 'App', [] ) ;
        App.controller('WeatherCtrl', ['$scope', '$http', function ($scope, $http) {
            $http({
                url: 'http://api.map.baidu.com/telematics/v3/weather',
                method: 'jsonp',
                params: {
                    callback: 'JSON_CALLBACK',
                    ak: '0A5bc3c4fb543c8f9bc54b77bc155724',
                    location: '北京',
                    output: 'json'
                }
            }).success(function (info) {
                console.log(info);
                $scope.weathers = info.results[0].weather_data;
            });
        }]);
    </script>
</body>
</html>

8.2 自定義服務

通過上面例子得知,所謂服務是將一些通用性的功能邏輯進行封裝方便使用,AngularJS允許將自定義服務。

8.2.1 factory方法

<script>
    var App = angular.module('App', []);

    // 模塊實例App包含若干方法
    // 使用factory() 來定義服務

    // 第一個參數是服務的名稱
    // 第二個參數是一個數組
    // 自定義服務是可以在原有的AngularJS內置服務基礎之上來定義
    // 自定義的服務其使用和內置服務一樣

    App.factory('sayHello', ['$log', function ($log) {

        // 必須要有一個返回值
        // 其值可以是任意數據類型
        // 但是通常對象或函數更有意義
        
        function sayHello(name) {
            alert('你好' + name);
        }
        return {
            sayHello: sayHello,
            changge: function () {
                console.log('我還會唱歌呢');
            }
        }
    }]);

    // 需求定義一個可以獲取當前時間的服務并格式化好
    App.factory('Time', ['$filter', function ($filter) {

        return {
            // 傳入格式
            now: function (format) {
                // 如果沒傳入格式,有個默認格式
                if(!format) {
                    format = 'yyyy-MM-dd';
                }

                var now = new Date;
                // 參考$filter用法
                return $filter('date')(now, format);
            }
        }
    }]);

    App.controller('DemoCtrl', ['sayHello', 'Time', '$scope', function (sayHello, Time, $scope) {

        sayHello('小明');

        sayHello.sayHello('小明');

        sayHello.changge();

        $scope.now = Time.now('yyyy-MM-dd H:m:s');
        
    }]);
</script>

8.2.2 service方法

特點:不需要return

<body>
    <div ng-controller="DemoCtrl">

        <span>{{now}}</span>
    
    </div>
    <script src="./libs/angular.min.js"></script>
<script>
    var App = angular.module('App', []);

    // 還可以使用service() 來定義服務
    // 第一個參數服務的名稱
    // 第二個參數還是數組
    // 數組是用來解決依賴
    App.service('Time', ['$filter', function ($filter) {

        // 在此完成當前服務的所有業務邏輯
        
        function Time(format) {
            return $filter('date')(new Date, format);
        }
        
        // 不需要使用return返回
        // this指的就是當前服務
        this.now = Time;

    }]);
    
    App.controller('DemoCtrl', ['$scope', 'Time', function ($scope, Time) {
        $scope.now = Time.now('yyyy-MM-dd H:m:s');
    }])
</script>
</body>

8.2.3 value方法定義常量

<body>
    <div ng-controller="DemoCtrl">
        {{author}}
        {{ver}}
    </div>
    <script src="./libs/angular.min.js"></script>
    <script>
        var App = angular.module('App', []);

        // value定義的本質上一個服務
        // 從表現形式上是一個常量
        // 第一個參數為服務名稱 
        // 第二個參數任意[字符串 數值]
        App.value('ver', '1.0');
        App.value('author', 'xiaoming');

        App.controller('DemoCtrl', ['$scope', 'ver', 'author', function ($scope, ver, author) {

            console.log(ver);

            $scope.ver = ver;
            $scope.author = author;

        }])
    </script>
</body>

9.模塊加載

AngularJS模塊可以在被加載和執行之前對其自身進行配置。我們可以在應用的加載階段配置不同的邏輯。

先來看一下Angular的執行過程。

AngularJS執行過程.png

只需要明白一點,我們可以通過配置塊和運行塊可以影響后面的執行。

9.1 配置塊

通過config方法實現對模塊的配置,AngularJS中的服務大部分都對應一個“provider”,用來執行與對應服務相同的功能或對其進行配置。

比如$log、$http、$location都是內置服務,相對應的“provider”分別是$logProvider、$httpProvider、$locationPorvider。

<body ng-app="App">
    <div ng-controller="DemoCtrl">
        <h1>{{info|capilize}}</h1>
    </div>
    <script src="./libs/angular.min.js"></script>
    <script>
        var App = angular.module('App', []);

        // App.config()方法是用來配置內置模塊的
        // 參數是一個數組(可以一次性配置多個)
        // 其具體配置方式為
        // 要想配置某個模塊都需要通過“服務名Provider”
        // 例如 想配置$log 就使用 $logProvider進行配置
        // 例如 想配置$filter 就使用$filterProvider進行配置
        // 例如 想配置$http 就使用$httpProvider進行配置

        // 配置$log的功能
        App.config(['$logProvider', '$filterProvider', function ($logProvider, $filterProvider) {
            // 禁用debug方法
            $logProvider.debugEnabled(false);

            // $filter 默認只有9個(過濾器)方法
            // 這里可以通過配置添加一個首字母大寫功能
            // 第一個參數寫過濾器的名稱
            $filterProvider.register('capilize', function () {
                return function (input) {
                    return input[0].toUpperCase() + input.slice(1);
                }
            });

        }]);

        App.controller('DemoCtrl', ['$log', '$scope', function ($log, $scope) {
            $log.log('調試信息');

            $log.debug('debug還能用嗎');

            $scope.info = 'my name is xiaoming';
        }]);

        // 總結:在AngularJS執行過程中,可以對某些功能進行配置,使用提供的config方法來現
        // 在進行配置時并不是使用原有的服務名稱,而是“服務名稱+Provider”
        // 例如 $log 使用 $logProvider
        App.config(['$logProvider', function ($logProvider) {
            // 通過$logProvider就可以配置$log了
            $logProvider.debugEnabled();
        }]);
    </script>
</body>

9.2 運行塊

服務是模塊形式存在的,對外提供特定功能,一般都是將服務做為依賴注入進去的,然后再進行調用,除了這種方式外我們也可以直接運行相應的服務模塊,AngularJS提供了run方法來實現。

不但如此,run方法還是最先執行的,利用這個特點我們可以將一些需要優先執行的功能通過run方法來運行,比如驗證用戶是否登錄,未登錄則不允許進行任何其它操作。

App.run(['$http', '$rootScope', function ($http, $rootScope) {
    $http({
        method: 'post',
        url: 'example.php'
    }).success(function (info) {
        // 在根作用域上定義date,相當于在ng-init = '' 中定義
        // 如果要在根作用域上定義多個屬性,使用ng-init = '' 會比較麻煩
        // 此時就可以用$rootScope.xxx
        $rootScope.date = info;
    });
}]);

10. 路由

網站在切換各個頁面時,網站主域名后的改變的,就是路由。改變一個路由,就會切換一個頁面。一個應用是由若個視圖組合而成的,根據不同的業務邏輯展示給用戶不同的視圖,路由則是實現這一功能的關鍵。通過監聽路由的改變,可以實現單頁面應用(單頁面應用也是有路由的)。

10.1 單頁面應用(SPA)

SPA(Single Page Application)
單頁面應用就是指將所有的功能通過一個頁面展示。

在PC端也有廣泛的應用,通常情況下使用Ajax異步請求數據,然后實現內容局部刷新,局部刷新的本質是動態生成DOM,新生成的DOM元素并沒有真實存在于文檔中,所以當再次刷新頁面時新添加的DOM元素會“丟失”,通過單頁面應可以很好的解決這個問題。

由于頁面沒變,內容變了??梢允褂肵MLHttpRequest向服務器獲取數據,并將獲取到的數據以DOM操作的方式添加到頁面中去。采用這種方式可以增強用戶體驗,還可以減輕服務器壓力。

10.2 路由

在后端開發中通過URL地址可以實現頁面(視圖)的切換,但是AngularJS是一個純前端MVC框架,在開發單頁面應用時,所有功能都在同一頁面完成,所以無需切換URL地址(即不允許產生跳轉),但Web應用中又經常通過鏈接(a標簽)來更新頁面(視圖),當點擊鏈接時還要阻止其向服務器發起請求,通過錨點(頁內跳轉)可以實現這一點。

實現單頁面應用需要具備:
a、只有一頁面
b、鏈接使用錨點

<body>
    <nav>
        <a href="#login">登錄</a>
        <a href="#register">注冊</a>
    </nav>
    <div class="content">
        
    </div>
    <!-- 點擊登錄出現登錄界面 -->
    <!-- 點擊注冊出現注冊界面 -->
    <script>
        // 根據錨點的變化來決定到底應該顯示哪個界面
        // 如何知道錨點變化了?
        window.onhashchange = function () {
            // 當錨點發生變化后此事件的回調被執行
            var hash = location.hash.slice(1);
            var xhr = new XMLHttpRequest;
            // 將獲取到的錨點的變化值以參數的形式傳給服務端
            xhr.open('get', 'spa.php?hash=' + hash);
            xhr.send();
            xhr.onreadystatechange = function () {
                if(xhr.readyState == 4 && xhr.status == 200) {
                    var content = document.querySelector('.content');
                    content.innerHTML = xhr.responseText;
                }
            }
        }
    </script>
</body>

通過上面的例子發現在單一頁面中可以通過hashchange事件監聽到錨點的變化,進而可以實現為不同的錨點準不同的視圖,單頁面應用就是基于這一原理實現的。

AngularJS對這一實現原理進行了封裝,將錨點的變化封裝成路由(Route),這是與后端路由的根本區別。

在1.2版前路由功能是包含在AngularJS核心代碼當中,之后的版本將路由功能獨立成一個模塊,下載angular-route.js

8.2.1 如何使用路由

(1)引入angular-route.js
(2)實例化模塊(App)時,當成依賴傳進去(模塊名稱叫ngRoute)
(3)配置路由模塊
(4)布局模板。通過ng-view指令布局模板,路由匹配的視圖會被加載渲染到些區域。

<body ng-app="App">
    <nav>
        <a href="#/login">登錄</a>
        <a href="#/register">注冊</a>
        <a href="#/list">講師列表</a>
    </nav>
    <div ng-view></div>
    <!-- AngularJS核心文件 -->
    <script src="./libs/angular.min.js"></script>
    <!-- AngularJS路由插件 -->
    <script src="./libs/angular-route.js"></script>
    <script>
        // 作為依賴傳入
        var App = angular.module('App', ['ngRoute']);
        // 路由一定要經過config方法配置才能用
        App.config(['$routeProvider', function ($routeProvider) {
            // 具體使用when方法進行配置
            $routeProvider.when('/login', {
                // 將界面以字符串形式書寫,不易管理
                // template: '<h1>我是登錄界面</h1>'
                // 將界面內容放到獨立文件中,方便管理
                templateUrl: './views/login.html'
            })
            .when('/register', {
                // 將界面以字符串形式書寫,不易管理
                // template: '<h1>我是注冊界面</h1>'
                // 將界面內容放到獨立文件中,方便管理
                templateUrl: './views/register.html'
            })
            .when('/list', {
                templateUrl: './views/list.tpl',
                controller: 'DemoCtrl'
            })
            .otherwise({
                redirectTo: '/login'
            });
        }]);
        App.controller('DemoCtrl', ['$scope', '$routeParams', function ($scope, $routeParams) {
            console.log($routeParams);
            $scope.list = ['html', 'js', 'css', 'php'];

        }]);
    </script>

8.2.2 路由參數

(1)提供兩個方法匹配路由,分別是whenotherwise,when方法需要兩個參數,otherwise方法做為when方法的補充只需要一個參數,其中when方法可以被多次調用。
(2)第1個參數是一個字符串,代表當前URL中的hash值。
(3)第2個參數是一個對象,配置當前路由的參數,如視圖、控制器等。
1. template 字符串形式的視圖模板
2. templateUrl 引入外部視圖模板
3. controller 視圖模板所屬的控制器
4. redirectTo 跳轉到其它路由
(4)獲取參數,在控制中注入$routeParams可以獲取傳遞的參數

<script src="./libs/angular.min.js"></script>
<script src="./libs/angular-route.js"></script>
<script>
    var App = angular.module('App', ['ngRoute']);
    App.config(['$routeProvider', function ($routeProvider) {
        // ?后面的內容是參數,并不是路由的一部分
        $routeProvider.when('/', {
            template: '<h1>你的參數為:{{params.name}}和{{params.age}}</h1>',
            controller: 'IndexCtrl'
        })
        // 使用:來為路由設置參數
        // :name , :后跟的是一個形參,在地址欄中輸入實參。
        // 而沒加: 的就是固定寫法
        // 比如地址欄可以是/list/haoxiang/18/demo/100形式
        .when('/list/:name/:age/demo/:page', {
            template: '<h1>列表</h1>',
            controller: 'ListCtrl'
        });
    }]);
    App.controller('IndexCtrl', ['$scope', '$http', '$routeParams', function ($scope, $http, $routeParams) {
    
        // $routeParams來獲取地址參數,就是?后的那部分
        console.log($routeParams);
        $scope.params = $routeParams;
    }]);
    // 列表控制器
    App.controller('ListCtrl', ['$scope', '$http', '$routeParams', function ($scope, $http, $routeParams) {
        console.log($routeParams);
    }]);
</script>

9.其他

9.1 在AngularJS中使用jQuery

在沒有引入jQuery的前提下AngularJS實現了簡版的jQuery Lite,通過angular.element不能選擇元素,但可以將一個DOM元素轉成jQuery對象,如果引提前引入了jQuery則angular.element則完全等于jQuery。

// 原生DOM對象
var box = document.querySelector('.box');
var btn = document.querySelector('button');
// 轉成jQuery對象
box = angular.element(box);
btn = angular.element(btn);
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,572評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,071評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 175,409評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,569評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,360評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,895評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,979評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,123評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,643評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,559評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,742評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,250評論 5 356
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,981評論 3 346
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,363評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,622評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,354評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,707評論 2 370

推薦閱讀更多精彩內容

  • 簡介: AngularJS 是一個 JavaScript 框架。它可通過 標簽添加到 HTML 頁面。 Ang...
    JenniferYe閱讀 1,433評論 0 13
  • 1、什么是angularjs AngularJS是一個框架(諸多類庫的集合)以數據和邏輯做為驅動(核心)。 Ang...
    margery閱讀 315評論 0 0
  • 多重視圖和路由 為什么需要路由? 回答這個問題首要要簡單介紹一下單頁面應用。單頁面應用通俗來講就是在瀏覽器中運行的...
    罌粟1995閱讀 361評論 0 0
  • AngularJS是什么 AngularJS的官方文檔這樣介紹它: 完全使用JavaScript編寫的客戶端技術。...
    oWSQo閱讀 1,333評論 0 10
  • 真正的教養是原諒那些做不到你自己所做的有教養行為的人,我想我做的不夠好,我真的很糟糕嗎
    想你itiswritten閱讀 105評論 0 0