Angular

Angular

 

前言

简介

Angular简称

四个特性

优点

初尝试

常用介绍

指令

说明

ng-app

ng-bind

ng-repeat

ng-class

ng-show/ng-hide/ng-if:true/false

ng-href/ng-src

ng-switch

ng-checked/ng-disabled/ng-readonly/ng-selected

常用事件指令

自定义指令

控制器

表达式

闪烁问题

表达式可承载的内容

双向数据绑定

$scope

 

 

前言

单一页面程序【SPA】体会:现在请你打开网易云的官网https://music.163.com,播放一首你最喜欢的歌曲,然后点击一下”我的音乐“,不知道这个过程你是否会想到这个问题:唉?我都点击一个资源了,页面并没有跳转也没有任何刷新的迹象,页面的头部没有改变,更重要的是你最喜欢的歌依旧没有任何停顿的在播放。不用我说你可能觉得这很简单,这不就是用ajax去做的吗?这有什么难的!没错,这个过程确实是用ajax去做的,那你该问这个Angular有个毛关系?关系不关系我们接着看!如果你足够细心,会发现当你点击“我的音乐”时,浏览器是没有刷新的,但是浏览器的地址栏却发生了一些细微的变化,在地址栏中出现了像是锚点的东西,不过我们的锚点不是常常指向一个dom元素的id吗?细看这个锚点后面的东西有些像一个路径,下面我们来扯一扯window对象的一个锚点切换事件你大概就略有所悟了。

<script>
    (function (window) {
        // 每当锚点改变触发以下事件
        window.addEventListener('hashchange', function (e) {
            console.log(e);
            console.log(window.location);
            var hash = window.location.hash;
            
            // 网易锚点后的链接
            switch (hash) {
                case '#/my/':
                    // ajax do somethings
                    break;
                case '#/friend':
                    // ajax do somethings
                    break;
                case '#/download':
                    // ajax do somethings
                    break;
            }
        })
    })(window)
</script>

说白了,还是使用ajax去请求后台,只不过是换了一种方式,使用锚点的方式触发了。

 

 

简介

来自百度百科的介绍:https://baike.baidu.com/item/SPA/17536313

中文官网:https://www.angular.cn/

API:https://docs.angularjs.org/api

一个测试不同技术的模板:https://github.com/tastejs/todomvc-app-template

 

Angular简称

ng

 

四个特性

 MVC

 模块化

 自动化双向数据绑定

 指令系统

 

优点

 Angular最大程度的减少了页面上的DOM操作;

 让JavaScript中专注业务逻辑的代码;

 通过简单的指令结合页面结构与逻辑数据;

 通过自定义指令实现组件化编程;

 代码结构更合理;

 维护成本更低;

 Angular解放了传统JavaScript中频繁的DOM操作;

 

初尝试

官网地址:https://docs.angularjs.org/tutorial/step_00

插件:AngularJS Batarang自己去goole商店下载,可用来查看Angular一些数据渲染

 

首先:所有需要ng管理的代码必须被包裹在一个有ng-app指令的元素中,ng-app是ng的入口,表示当前元素的所有指令都会被angular管理(对每一个指令进行分析和操作)。

<body>
<!--所有需要ng管理的代码必须被包裹在一个有ng-app指令的元素中,ng-app是ng的入口,
表示当前元素的所有指令都会被angular管理(对每一个指令进行分析和操作)-->
<div ng-app ng-init="_name='毛毛'"> <!--ng-init表示初始化一个默认值-->
    <!--在ng中定义一个模型-->
    <input type="text" ng-model="name">
    <!--在ng中使用定义的模型-->
    <p>你好,{{name}}</p>
</div>
<script src="../node_modules/angular/angular.js"></script>
</body>

 

代码解析:

 当网页加载完毕,AngularJS自动开始执行;

 HTML页面中ng-xxx的属性称之为指令(Directive);

 ng-app指令告诉AngularJS,<div>元素是AngularJS程序管理的边界;

 ng-model:是双向数据绑定的指令,效果就是将当前元素的value属性和模型中的name建立绑定关系。

 {{name}}表达式就是把应用程序变量name绑定到某个段落的innerHTML

Angular

 

 

<!--如果ng-app中有模块名,则表示我这个div将由myApp这个模块管理,否则由angular管理-->
<!--ng-controller中指明我这个模块将由AppController控制-->
<div ng-app="myApp" ng-controller="AppController">
    <!--在ng中定义一个模型-->
    <input type="text" ng-model="user.name">
    <!--在ng中使用定义的模型-->
    <p>你好,{{user.name}}</p>
    <button ng-click="show()">点击</button>
</div>
<script src="../node_modules/angular/angular.js"></script>
<script>
    (function () {
        var myApp = angular.module("myApp",[]);// 第二个参数数组表示可能引用的模块
        // 存在不能混淆压缩的问题
        myApp.controller("AppController",function($scope) { // $scope这个参数名称固定!代表上图中存储区块对象
            $scope.user = {};
            $scope.user.name = '毛毛';
            $scope.show = function() {
                console.log($scope.user.name);
            }
        });
    })()
</script>

 

注册控制器存在的问题:在上面说了$scope是一个固定写死的参数,一旦更改名称,angular将不能识别注入!这就存在一个问题就是js压缩问题,我们都知道生产环境中可以使用未压缩的js文件,但是上线常常使用标识符混淆的压缩方式压缩代码,一旦使用标识符混淆,$scope就会被改变,angular又不能注入了。angular为了解决这个问题,声明了一种标准的写法:

// 标准写法:
myApp.controller("AppController",['$scope',function(a) { // 字符串'$scope'固定写法
            a.user = {};
            a.user.name = '毛毛';
            a.show = function() {
                console.log(a.user.name);
            }
        }]);

 

使用数组的方式,要求数组的最后一个元素是一个function,之前的元素对应该function中的参数,由于数组中存储的function参数是字符串类型而不是一个变量,就不会存在混淆压缩被替换的问题。

 

 

常用介绍

指令

说明

 ng-xxx的属性本身并不是标准中定义的属性,很多情况下语法检验(W3C)是无法通过的

 HTML5允许扩展的(自制的)属性,以data-开头,在AngularJS中可以使用data-ng-xx来让网页对HTML5有效,这和直接在元素中使用ng-xx效果相同

 

ng-app

标记范围尽可能小,为了性能

最好只出现一个ng-app,如果出现多个ng-app就需要手动引导,或模块带入方式实现

 

 

ng-bind

在下面讲到表达式的时候,在表达式中存在一个闪烁问题,解决这个问题我们还可以使用ng-bind中绑定数据,而不是直接在标签文本内部使用。

你可以在其中绑定一些基本的数据,但是并不建议你去绑定html,因为这将带来不安全的操作,可能存在一些脚本攻击【假如你绑定的是某个用户评论的内容,该内容是一段js脚本用来获取你本地cookie信息模拟你登陆,窃取一些东西】。所以默认的你在ng-bind中所有的文本标签<,>将会被替换为<>,防止你绑定的数据是一个脚本。如果你非要去绑定一个标签内容,并想呈现标签的效果,你就要使用ng-bind-html,使用该标签你要求你使用angular提供的一种校验库sanitize,用以校验你绑定的内容是否安全。【即使这样,还是不推荐你去绑定html】

<body ng-app ng-init="h='shif'">
    <p>{{h}}</p>
    <p ng-bind="h"></p><!--不会出现闪烁问题-->
    <script src="../../node_modules/angular/angular.js"></script>
</body>
<body ng-app="myApp" ng-init="exam='<h1>shif</h1>'">
    <p ng-bind-html="exam"></p>
    <script src="../../node_modules/angular/angular.js"></script>
    <script src="../../node_modules/angular-sanitize/angular-sanitize.js"></script>
    <script>
        (function () {
            var myApp = angular.module("myApp",["ngSanitize"])
        })();
    </script>
</body>

 

ng-repeat

用来遍历一个数组重复创建当前元素。

<body ng-app="myApp">
<ul ng-controller="ULController">
    <li ng-repeat="item in data">
        <span>id:{{$id}}</span>
        <span>index:{{$index}}</span>
        <span>first:{{$first}}</span>
        <span>last:{{$last}}</span>
        <span>middle:{{$middle}}</span>
        <span>even:{{$even}}</span>
        <span>odd:{{$odd}}</span>
        <span>{{item.name}}</span>
    </li>
</ul>
<script src="../../node_modules/angular/angular.js"></script>
<script>
    (function () {
        angular.module('myApp', []).controller('ULController', ['$scope', function ($scope) {
            $scope.data = [{name: '毛毛'}, {name: '吉吉'}, {name: '咪咪'}, {name: '可可'}];
        }])
    })();
</script>

 

如果遍历的元素存在重复的,则需要track by 一个不重复的量:

<li ng-repeat="item in data track by $index">

 

ng-class

ng-class中可以写入一个对象,如下例中对象的key值表示现有的css样式属性名,对象的value为true或者false,表示是否起作用。ng-class还可以绑定model。

<style>
        .red {
            color: red;
        }

        .green {
            color: yellow;
        }
    </style>
</head>
<body ng-app="myApp" ng-init="nnm='red'">
<div ng-controller="ULController">
    <ul>
        <li ng-repeat="item in data"><!--隔行换色-->
            <span class="{{$even?'red':'green'}}">{{item.name}}</span>
        </li>
    </ul>
    <ul>
        <li ng-repeat="item in data"><!--隔行换色-->
            <span ng-class="{red:$even,green:$odd}">{{item.name}}</span>
        </li>
    </ul>
    <span ng-class="nnm">{{ 10+20 }}</span> <!--还可以绑定一个模型-->
</div>

<script src="../../node_modules/angular/angular.js"></script>
<script>
    (function () {
        angular.module('myApp', []).controller('ULController', ['$scope', function ($scope) {
            $scope.data = [{name: '毛毛'}, {name: '吉吉'}, {name: '咪咪'}, {name: '可可'}];
        }])
    })();
</script>

 

ng-show/ng-hide/ng-if:true/false

ng-show:决定是否显示

ng-hide:决定是否隐藏

ng-if:决定是否显示[不显示就删除]

<body ng-app="myApp" ng-init="nnm='red'">
<div ng-controller="ULController">
    <div class="hong" ng-show="show"></div>
    <div class="hong" ng-hide="show"></div>
    <div class="hong" ng-if="if"></div>
</div>

<script src="../../node_modules/angular/angular.js"></script>
<script>
    (function () {
        angular.module('myApp', []).controller('ULController', ['$scope', function ($scope) {
            $scope.show = true;
            $scope.hide = false;
            $scope.if = false;
        }])
    })();
</script>

 

ng-href/ng-src

ng-href/ng-src指令用于解决当链接类型的数据绑定时造成的加载BUG

<body ng-app ng-init="url = '../images/123.png'">
<img src="{{url}}" alt=""> // 在angular没起作用之前就开始发送了请求,所有控制台会报一个错
<img ng-src="{{url}}" alt="">

<script src="../../node_modules/angular/angular.js"></script>
</body>

 

ng-switch

<div ng-app="myApp" ng-controller="AppController">
    <div ng-repeat="item in exam">
        <div ng-switch="item.name">
            <p ng-switch-when="Liu">刘</p>
            <p ng-switch-when="Li">李</p>
            <p ng-switch-when="Wang">王</p>
            <p ng-switch-default>赵</p>
        </div>
    </div>
</div>
<script src="../../node_modules/angular/angular.js"></script>
<script>
    (function () {
        angular.module('myApp',[]).controller('AppController',['$scope',function ($scope) {
            $scope.exam = [{name:'Li'},{name:'Liu'},{name:'Zhao'},{name:'Wang'}]
        }]);
    })();
</script>

 

ng-checked/ng-disabled/ng-readonly/ng-selected

ng-checked:单选/复选是否选中

ng-disable:是否禁用

ng-readonly:是否只读

ng-selected:是否选中

<!-- 双向绑定的,任意一个选中则全部选中 -->
<input type="checkbox" ng-model="checked"><br/>
<input type="checkbox" ng-model="checked">
<input type="checkbox" ng-model="checked">
<input type="checkbox" ng-model="checked">

 

<!-- ng-model双向绑定的,ng-checked时模型到视图的绑定(单项),第一个选中全选中,其他选中只选中自己 -->
<input type="checkbox" ng-model="checked"><br/>
<input type="checkbox" ng-checked="checked">
<input type="checkbox" ng-checked="checked">
<input type="checkbox" ng-checked="checked">

 

常用事件指令

ng-blur:失去焦点

ng-change:发生改变

ng-copy:拷贝完成

ng-click:单击

ng-dbclick:双击

ng-focus:得到焦点

ng-blur:失去焦点

ng-submit:表单提交

 

自定义指令

<head>
    <meta charset="UTF-8">
    <title>自定义指令</title>
    <link rel="stylesheet" href="../../node_modules/bootstrap/dist/css/bootstrap.css">
</head>
<body ng-app="myApp" ng-init="nnm='red'">
<div ng-controller="ULController">
    <breadcrumb data="{{data}}"></breadcrumb>
</div>

<script src="../../node_modules/angular/angular.js"></script>
<script>
    (function () {
        var myApp = angular.module('myApp', []);
        myApp.controller('ULController', ['$scope', function ($scope) {
            $scope.data = ['blogs','home','doc','index'];
        }]);
        /*自定义指令*/
        myApp.directive('breadcrumb',[function () {
            return {
                scope:{
                    // data:'@' // 不能直接引用到该元素的data属性,因为直接拿到的是一个字符串,不是对象
                },
                // template:'<h1>xasx</h1>',
                templateUrl:'./template.html',// 模板的地址
                replace:true, // 是否是以替代的方式替换之前元素
                link:function (scope,element,attributes) {
                    scope.data = JSON.parse(attributes.data);
                    // console.log(scope.data);
                }
            }
        }])
    })();
</script>

 

上代码引用的template.html:

<nav aria-label="breadcrumb">
    <ol class="breadcrumb">
        <li class="breadcrumb-item" ng-repeat="item in data track by $index">
            <a href="#" ng-if="$last == false ? true:false">{{item}}</a>
            <span ng-if="$last">{{item}}</span>
        </li>
    </ol>
</nav>

 

控制器

控制器的三大作用:

暴露数据

暴露行为

监视数据变化

<body ng-app="Login"><!--这是angular管理的一个模块-->
<table border="1" ng-controller="LoginController"><!--该模块的这一部分dom由LoginController控制-->
    <tr>
        <td>用户名:</td>
        <td><input type="text" ng-model="user.name"></td><!--双向绑定$scope中的数据模型-->
    </tr>
    <tr>
        <td>密码:</td>
        <td><input type="password" ng-model="user.password"></td><!--双向绑定$scope中的数据模型-->
    </tr>
    <tr>
        <td></td>
        <td><input type="button" value="登陆" ng-click="login()"></td><!--绑定$scope中的方法-->
    </tr>
    <tr>
        <td colspan="2">{{message}}</td>
    </tr>
</table>
<script src="../node_modules/angular/angular.js"></script>
<script>
    var loginApp = angular.module("Login",[]);
    loginApp.controller("LoginController",['$scope',function ($scope) {
        // 数据
        $scope.user = {
            name:'',
            password:'',
        };

        $scope.message = '';

        // 行为数据
        $scope.login = function() {
            // ajax do somethings
            console.log($scope.user);
        };

        // 监视数据的行为,第一个参数为要监视的模型,第二个参数为一个function
        $scope.$watch('user.name',function (now,old) { // now表示模型的当前值,old表示模型的上一次值
            console.log(now,old);
            if(now) {
                if (now.length < 7) {
                    $scope.message = '输入的用户名不合法!';
                } else {
                    $scope.message = '';
                }
            }else {
                $scope.message = '请输入用户名!';
            }
        })
    }])
</script>

 

表达式

表达式是单向数据绑定的。

 

闪烁问题

<body>
<div ng-app ng-init="_name='毛毛'">
    <input type="text" ng-model="_name">
    <p class="ng-cloak">你好,{{_name}}</p>
</div>
<script src="../node_modules/angular/angular.js"></script>
</body>

 

依旧是最开始的例子,在goole里测试由于goole的缓存可能看不到,这个例子在火狐里面你就会发现,每次刷新时页面先出现“你好,{{_name}}”,然后又迅速的变成了“你好,毛毛”,查其原因,当然是由浏览器解析dom的顺序导致的,由于我们是在后面导出angular的,所以浏览器按照顺序解析会先出现“你好,{{_name}}”,然后当解析到angularJS时才将表达式里的内容替换掉的。当你把angularJS文件的引用放到最开始,就不会出现这个问题(如果你刷新的速度足够快,还是会出现闪烁问题)。

Angular为了解决这个问题提供了一个属性标签ng-cloak,将存在表达式的标签上添加该属性,并且还要把angularJS文件的引用放在前面才行。

当然还有另外一种解决方案使用css方式去控制,我们依旧使用angularJS提供的指令标签ng-cloak,然后写一段css代码:

<head>
    <meta charset="UTF-8">
    <title>Angular</title>
    <style>
        [ng-cloak] {
            display: none;
        }
    </style>
</head>
<body>
<div ng-app ng-init="_name='毛毛'">
    <input type="text" ng-model="_name">
    <p ng-cloak>你好,{{_name}}</p>
</div>
<script src="../node_modules/angular/angular.js"></script>
</body>

 

使用属性选择器先将该元素隐藏,等加载angularJS时,由angularJS渲染表达式,最后将标签显现出来。

表达式可承载的内容

 //数字

{{ 100 + 100 }}

 //字符串

{{ 'hello' + 'world' }}

 //对象

{{ user.name }}

 数组

{{ data[0] }}

 //三元表达式

{{ flag == true ? data[1] : data[2] }}

 

双向数据绑定

两个方向的数据自动同步:

-模型($scope)发生变化自动同步到视图上

-视图上的数据发生变化过后自动同步到模型上

 

 

$scope

$scope(上下文模型)

 视图和控制器之间的桥梁

 用于在视图和控制器之间传递数据

 利用$scope暴露数据模型

 

上一篇:自定义注解给属性加密


下一篇:Wpf(Storyboard)动画简单实例