继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

《用AngularJS开发下一代Web应用》读书笔记②:AngularJS应用骨架

PIPIONE
关注TA
已关注
手记 921
粉丝 147
获赞 701

调用Angular

  • 使用Angular首先要做两件事:

  1. 加载angular.js库

  2. 使用ng-app指令告诉Angular应该管理DOM中哪一部分

鉴于天朝在网络世界中修筑了万里长城,推荐使用国内的CDN缓存代码库(cdn.css.net网站中提供各种CDN的搜索)

<script 
    src="https://cdn.css.net/files/angular.all/1.2.18/angular-all.min.js"></script>
  • ng-app指令告诉Angular应该盖页面的哪一块,即Angular的模块。

<!-- 如果是构建纯Angular应用,可以写在`<html>`元素中 --><html ng-app>
    ···</html>

或者

<html>    <!-- 如果应用已经使用了类似JSP、Rails的其他技术,也可以写在要管理的DOM元素中 -->
    <div  ng-app>
        ···    </div></html>

Model View Controller

  • 第一章提到Angular框架是通过MVC风格来设计web应用的,使之具有很强的灵活性。MVC包括:

    • 模型(Model)用来容纳数据,代表应用当前的状态;

    • 视图(View)用来展示数据;

    • 控制器(Controller)来管理模型和视图之间的关系;

  • 我们可以通过$scope对象的属性来创建数据模型,可以只用基本数据类型来存储数据,也可以用一个JavaScript类来存储数据。

  • 定义Angular的正确方式应该是,先定义Angular模块,然后把控制器定义为模块的一个方法。 通过模块机制可以帮助我们把代码从全局命名空间中隔离开来。

<!doctype html><!-- 通过ng-app设置Angular管理的范围  --><html ng-app='myApp'>
    <head>
        <!-- 引入Angular的文件 -->
        <script src="https://cdn.css.net/files/angular.all/1.2.18/angular-all.min.js"></script>
    </head>
    <!-- 通过ng-controller声明控制器-->
    <body ng-controller='TextController'>
        <!-- 通过双花括号定义双向绑定的数据 -->
        <p>{{hello}} {{TextObj.message}}!</p>
        <script type="text/javascript">
            //通过angular.module()方法声明模块,第一个参数是模块名,第二个参数是需要依赖的模块(这里是空数组)
            var myAppModule = angular.module('myApp',[]);            //通过module.controller()方法声明控制器,参数是控制器方法的具体实现
            myAppModule.controller('TextController',function($scope){                //变量
                var hello = 'hello';                //对象
                var TextObj = {
                    message : "World"   
                };  
                //赋值给$scope
                $scope.TextObj = TextObj;
                $scope.hello = hello;
            });        </script>
    </body></html>

模板和数据绑定

<div ng-repeat='item in items'>
    <span>{{item.title}}</span></div>
  • 如上代码所示,Angular的模板是HTML片段,而items数组是数据模型,通过ng-repeat指令Angular框架会遍历items数组的每一项,并给<div>元素生成一份拷贝,延展出HTML内容。

  • 在实际应用中,items数组往往是通过请求服务端的数据结果。

  • 一个Angular应用的基本运作流程如下:
    ① 用户请求Angualr应用起始页;
    ② 浏览器向服务器发起HTTP连接,加载起始页.html页面(页面中包含模板);
    ③ 开始解析页面,加载Angualr框架到页面,DOM构建完毕后开始查找ng-app指令,根据这个指令来定义Angular的模板边界;
    ④ Angular框架的初始化工作:注册监听器、执行一些DOM操作、从服务器获取初始化数据。初始化工作完毕后,模板被转换成DOM视图;
    ⑤ 连接到服务器,加载需要展示给用户看的其他数据;

显示文本
  • 将JS变量的文本值显示到UI中,除了使用双花括号之外,还可以使用'ng-bind'指令。两种形式的输出内容是相同的。

  • 使用使用双花括号的方式,可以让模板代码阅读起来更自然,但有一个问题,就是在Angular使用数据替换这些花括号之前,未被渲染好的模板可能会被用户看到。造成这种现象的原因是,浏览器需要先加载并渲染HTML页面,Angular才开始初始化工作。

表单输入
  • 对所有标准的表单元素,Angualr框架都支持,并且操作起来非常方便,只需要将ng-model属性声明到要操作的元素即可。

  • 案例:Angular操作复选框

<from ng-controller='SomeController'>    <!-- 通过ng-model将控件值绑定到youCheckedIt变量中 -->
    <input type="checkbox" ng-model='youCheckedIt' /></from>
  • 我们还可以通过ng-change指令监听控件的改变

  • 案例:自动获取十倍的数字计算控件

<from ng-controller='StartUpController'>
    Starting: <input type="text" ng-model='funding.startingEstimate' />
    Remomendation:{{funding.needed}}</from><script type="text/javascript">
    var myAppModule = angular.module('myApp',[]);
    myAppModule.controller('StartUpController',function($scope){
        $scope.funding = {startingEstimate : 0};
        $scope.computeNeeded = function(){
            $scope.funding.needed = $scope.funding.startingEstimate * 10;
        };
    });</script>
  • ng-change指令只能监听页面控件的变化,如果是接收到服务器返回的信息,需要刷新数据模型,该怎么办呢?

  • $watch()函数用来监听一个表达式,当表达式发送改变时会调用一个回调函数

myAppModule.controller('StartUpController',function($scope){
    $scope.funding = {startingEstimate : 0};
    $scope.computeNeeded = function(){
        $scope.funding.needed = $scope.funding.startingEstimate * 10;
    };    //添加$watch
    $scope.watch('funding.startingEstimate',computeNeeded);
});
  • Angular支持通过ng-submit指令监听表单提交动作。

<from ng-controller='SomeController' ng-submit='requestFnding()'>
  ···</from>
  • Angular提供一系列类似浏览器原生事件属性的指令,比如ng-clickng-dbclick

浅谈非入侵式JavaScript
  • 非入侵式JavaScript代码主要可以从以下两点来解读:

    • JavaScript的兼容性问题,需要根据在不同浏览器编写不同的代码;

    • 不同类库集成进来引发的全局命名冲突问题;

    • 不同的事件监听器绑定数据结构和行为,让代码变得难以理解和维护,扩展性差;

  • 一开始我们会把事件处理器定义在元素上,然后为这些元素赋ID值,获取元素的引用。或者,也可以通过一个统一的处理器来管理这些事件,但大多数应用,最后还是会把代码弄得乱七八糟。

  • 而Angular是通过ng-eventhandler="expression"来处理,这里的eventhandler可以被替换成clickmousedown等原生的JS事件。

  • 虽然也还是将事件绑定通过元素属性进行声明,但是具有以下特点:

    • Angular帮助开发者屏蔽浏览器的差异性;

    • 通过Angular控制器的作用域范围避免扰乱全局命名空间的秩序;

    • 没有在任何地方引用DOM或者DOM事件,所有定位元素和处理事件监听都在Angular内部完成;

    • 传统的JavaScript程序的页面逻辑和DOM是强耦合的,给单元测试增加了复杂性,而Angular则不会有这些问题;

列表、表格以及其他迭代类型
  • ng-repeat指令可以遍历数据模型,并动态构建DOM节点,可算是Angular最常用的指令之一了。

  • 案例:学生花名册系统

<!DOCTYPE html><!-- 1.通过ng-app设置Angular管理的范围 --><html ng-app='myApp'>
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <!-- 2.引入Angular的文件 -->
    <script src="http://cdn.static.runoob.com/libs/angular.js/1.4.6/angular.min.js"></script>
    <body>
        <ul ng-controller='StudentListController'>
            <li ng-repeat='student in students'>
                <a href="javascript:void(0);">{{$index+1}}.{{student.name}}</a>
            </li>
        </ul>
        <button ng-click='addStudent()'>Add</button>
        <script type="text/javascript">
            //伪数据
            var students = [
                {name : 'Mary Contrary',id:1},
                {name : 'Jack Spart',id:2},
                {name : 'Jill Hill',id:3},
                {name : 'William Liang',id:4},
                {name : 'Yoki Chen',id:5}
            ];            var myApp = angular.module('myApp',[]);
            myApp.controller('StudentListController',function($scope){
                $scope.students = students;
                $scope.addStudent = function(){
                    $scope.students.splice(1,0,{name:'test',id:6});
                }
            });        </script>
    </body></html>
  • ng-repeat指令中还可以通过$index返回当前引用元素的序号,通过$first$middle以及$last返回布尔值,判断当前元素是否为首个元素、是否为中间元素以及末尾元素。

显示和隐藏
  • Angualr通过ng-showng-hide指令显示和隐藏元素,当ng-show在表达式为true时显示元素,false时隐藏元素,ng-hide则恰好相反。

<!DOCTYPE html><!-- 1.通过ng-app设置Angular管理的范围 --><html ng-app='myApp'>
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <!-- 2.引入Angular的文件 -->
    <script src="http://cdn.static.runoob.com/libs/angular.js/1.4.6/angular.min.js"></script>
    <body>
        <div ng-controller='SwichMenuController'>
            <button ng-click='toggleMenu()'>Add</button>    
            <ul ng-show='menuState.show'>
            </ul>   
        </div>
        <script type="text/javascript">
            var myApp = angular.module('myApp',[]);
            myApp.controller('SwichMenuController',function($scope){
                $scope.menuState.show = false;
                $scope.toggleMenu = function(){
                    $scope.menuState.show = !$scope.menuState.show;
                }
            });        </script>
    </body></html>
CSS类和样式
  • Angular可以动态设置CSS类和样式,通过双花括号进行数据绑定。

  • 案例:动态修改颜色

<!DOCTYPE html><html ng-app='myApp'>
    <head>
        <meta charset="UTF-8">
        <title></title>
        <style type="text/css">
            .menu-disabled-true{ color:gray }        </style>
    </head>
    <script src="http://cdn.static.runoob.com/libs/angular.js/1.4.6/angular.min.js"></script>
    <body>
        <div ng-controller='StudentListController'>
            <ul>
                <li class="menu-disabled-{{isDisabled}}" ng-click='stun()'></li>
            </ul>   
        </div>
        <script type="text/javascript">
            var myApp = angular.module('myApp',[]);
            myApp.controller('SwichMenuController',function($scope){
                $scope.isDisabled = false;
                $scope.stun = function(){
                    $scope.isDisabled = true;
                }
            });        </script>
    </body></html>
  • Angular框架同样适用于内联样式,比如style="{{someexpression}}",这种方式具有很大的灵活性。

  • 除此之外,Angular框架还提供ng-classng-style指令,接受一个表达式。

  • 案例:通过ng-class显示错误和警告信息

<!DOCTYPE html><html ng-app='myApp'>
    <head>
        <meta charset="UTF-8">
        <title></title>
        <style type="text/css">
            .error{background-color: red;}            .warrning{background-color: yellow;}        </style>
    </head>
    <script src="http://cdn.static.runoob.com/libs/angular.js/1.4.6/angular.min.js"></script>
    <body>
        <div ng-controller='HeaderController'>
            <div ng-class='{error:isError,warning:isWarning}'>
                {{messageText}}            </div>
        </div>
        <button ng-click='showError()'>Simulate Error</button>
        <button ng-click='showWarning()'>Simulate Warning</button>
        <script type="text/javascript">
            var myApp = angular.module('myApp',[]);
            myApp.controller('HeaderController',function($scope){
                $scope.isError = false;
                $scope.isWarning = false;
                
                $scope.showError = function(){
                    $scope.messageText = 'This is an Error';
                    $scope.isError = true;
                    $scope.isWarning = false;
                };
                
                $scope.showWarning = function(){
                    $scope.messageText = 'This is an Warning';
                    $scope.isWarning = true;
                    $scope.isError = false;
                };
            });        </script>
    </body></html>
反思src和href属性
  • Angular通过ng-srcng-href指令动态设置超链接和图片属性

<img ng-src='/images/cats/{{favoriteCat}}'><a ng-href='/shop/category={{numberOfBalloons}}'>some text</a>
表达式
  • Angular在模板中使用表达式是为了在模板、业务逻辑和数据之间建立联系,避免让业务逻辑渗透到模板中。

  • angular的表达式可以进行简单的数据运算(+、-、*、/、%),进行比较运算(==、!=、>、<、>=、<=),执行布尔逻辑(&&、||、!),以及位运算(^、&、|)。

  • 但是我们应该清晰地区分视图和控制器之间的职责,尽量不要类似运算符的业务逻辑操作放到模板中。

  • 表达式是通过Angular内置的解析器执行的,但是不支持循环结构(for、while)、流程控制操作(if-else、throw)以及修改数据的操作符(++、--),请在控制器中执行或者通过指令执行。

区分UI和控制器和职责
  • 控制器有三种职责:

    • 为数据模型设置初始状态;

    • 通过$scope对象把数据模型和函数暴露给函数;

    • 监视模型其余部分的变化,并采取相应的动作;

  • 为了让控制器保持小巧和可管理的状态,我们建议为视图中的每一块功能区域创建一个控制器。

  • Angular中把控制器绑定到DOM节点上主要有两种方式:

  1. 在模板中通过ng-controller属性声明;

  2. 通过路由把控制器绑定到DOM模板片段;

同时,开发者还可以创建嵌套的控制器,使它们可以通过继承树的结构来共享数据模型和函数,让应用的代码保持简介,容易维护。

<!-- ChildController的$scope对象可以访问ParentController的$scope对象上所有的属性 --><div ng-controller='ParentController'>
    <div ng-controller='ChildController'></div></div>
利用$scope暴露模型数据
  • Angular利用向控制器传递$scope对象的机制,可以把模型数据暴露给视图。可以把$scope当成一个上下文环境,而在这个环境中,数据模型的变化变得可以观察,甚至还可以通过模板自身创建数据模型。

<!-- ① 可以直接在模板表达式中定义变量 --><button ng-click='count=3'>Set Count to Three</button><!-- ② 也可以通过构造器函数定义变量 --><div ng-controller='CountController'>
   <button ng-click='setCount()'>Set Count to Three</button></div><script type="text/javascript">function CountController($scope){
   $scope.setCount = function(){
        $scope.count = 3;
   };
}</script>
使用$watch监控数据模型的变化
  • $scope$watch函数可以实现,当数据模型发生变化时,及时得到通知。

  • 函数签名:$watch(watchFn,watchAction,deepWatch)

  • watchFn是一个字符串,可以是Angular表达式或者对象名,它代表数据模型的当前值。值得注意的是,这个字符串所代表的对象会被轮训检查多次,所以务必要保证它不会产生其他的副作用。

  • watchAction是当数据模型发生变化时调用的函数或者表达式,其函数签名是 function(newValue,oldValue.scope)

  • deepWatch是个可选的boolean值,带包是否检查数据模型的每个属性。如果想要监控数组中的元素,或者的对象中所有的属性变化,可以使用这个参数。

  • 同时,$watch()执行后还会返回一个函数,当你不再需要接收变更通知时,可以执行这个返回的函数,以销毁整个监听器。

//监听someProperty属性值的变化var dereg = $scope.$watch('someModel.someProperty',callbackOnChange());
dereg();    //销毁
watch()中的性能注意事项
  • 实际上,Angular在实现watch()方法时,会把所有被监控的属性都拷贝一份,然后拿来和当前的值进行比较,检查是否有变化。

  • 这样的运行机制会造成性能损耗,推荐通过一个Chrome调试插件(Batatrang)来检测,看看那些数据绑定的操作比较昂贵。

  • 有两种方式可以监控多个属性或者对象:


  1. 通过“+”号连接这些属性;

$scope.$watch('things.a+things.b',callMe(...));

2. 将要监控的属性放到一个数组或者对象中,并将`deepWatch`参数设置成true;

$scope.$watch('things',callMe(...),true);

### 使用Module(模块)组织依赖关系- 在开发中经常会遇到的难题是 __如何把代码组织在合理的功能范围内?__ - MVC的处理方式,是将控制器看做一个解耦的方法,把正确的数据模型暴露给视图模板。但其他用来支撑我们应用的代码该怎么办?要把它们写在控制器函数里面吗?这么做会使控制器变成一个垃圾场,使得控制器的代码变得难以理解,无法维护。
- `模块机制`解决了上诉问题,它把那些负责提供特殊服务的代码称为`依赖服务`,它专门来组织应用中各个功能区块的依赖关系,甚至可以自动进行依赖注入。
- 案例:当控制器需要从服务器获取商品列表时,通常情况我们会把相关的处理通通写到一个方法中

function ItemsViewController($scope){
var items = [];
//1.向服务器发起请求
//2.解析响应并放到Items对象
//3.将Items数组设置到$scope上,以便视图能够显示
$scope.items = items;
}

- 这种做法虽然可行,但却存在很多问题:
    * 功能代码无法重用:同样的代码片段,如果其他控制器也需要从服务端获取商品列表时,却只能重写一遍,这会给代码维护工作造成很大的负担;
    * 混淆控制器与与获取数据功能之间的代码边界:获取数据功能如果需要加上一些,例如服务器认证、解析数据等因素时,代码的复杂性将变得不可控制;
    * 难以进行单元测试:进行测试的工作变得复杂,甚至可能需要真正启动一个服务器来返回模拟数据进行测试,使得测试工作难以把控;
  通过模块化和Angular内置的依赖注入功能,可以这样写:

//创建模块
var myApp = angular.module('shoppingModule',[]);
//设置服务工厂
shoppingModule.factory('Items',function(){
var items = {};
items.query = function(){
//这里返回虚拟数据,真实的场景是从服务器拉取数据
return [
{name : 'Mary Contrary',id:1},
{name : 'Jack Spart',id:2},
{name : 'Jill Hill',id:3},
{name : 'William Liang',id:4},
{name : 'Yoki Chen',id:5}
];
};
return items;
});
//调用
function ShoppingController($scope,Items){
$scope.items = items.query();
}

  我们把`Items`对象定义成一个服务,把`$scope`对象和`Items`服务作为参数传递进去。
  > 提示:传递Angular在创建控制器时,是通过参数名匹配来注入所需要的服务的,比如`ShoppingController($scope,Items)`中查找`Items`服务。由于是以字符串的形式查找依赖关系的,所以控制器的参数是没有顺序的。

- 服务在Angular当中都是单例的对象,它们用来执行不要的任务,支撑应用的功能。开发者通过创建自定义的服务,共享在控制器之间,实现代码的复用。
- Angular内置了很多服务,例如`location`服务,用来和浏览器的地址栏做交互;还有`router`服务,用来根据URL地址的变化切换视图;以及`http`服务,用来和服务器进行交互等等;
- 根据Angular的API,有三种创建服务的函数:
  * __`provider(name,Object OR constructor())`__ :`name`是服务的名字,后面接一个对象或者构造函数。如果是Object的话,对象当中必须返回一个名为`$get()`的函数,否则Angular会认为传递的是一个构造函数,通过调用改构造函数返回服务的实例;
  * __`factory(name,$getFunction())`__ :和`provider()`函数相似,服务名后面接一个构造函数,当调用这个函数时,会返回服务的实例;
  * __`service(name,constructor())`__ :和`constructor`参数类似,Angular调用它来创建服务实例;
> 需要注意的是:Angular内置服务通常以符号开头,为了避免命名冲突,定义服务名时应当避免以$符号打头。

- 服务自身可以相互依赖,也可以通过`Module`接口定义模块之间的依赖关系。比如:A模块要引用SnazzyUIWidgets和SuperDataSync模块

var appMod = angular.module('app',['SnazzyUIWidgets','SuperDataSync']);

### 使用过滤器格式数据- 合理化地在应用界面中显示数字、日期以及金额对于用户体验来说是很重要的,但这些字符串的格式化处理对逻辑来说是没有意义的。
- Angular通过过滤器来格式化数据,其语法是:`{{expression | filterName : parameter1 : ...parameterN }}`- `expression`可以是任意的Angular表达式,`filter`是需要使用的过滤器名称,过滤器通过管道符号`|`来绑定,过滤器的参数之间使用冒号`:`分隔。
- 案例:Angular内置了众多过滤器帮助我们格式化数据,同时也可以创建自定义的过滤器

//大小写转换
{{ "lower cap string" | uppercase }}   //结果:LOWER CAP STRING
{{ "TANK is GOOD" | lowercase }}     //结果:tank is good
//JSON格式化
{{ {foo: "bar", baz: 23} | json }}  //结果:{ "foo": "bar", "baz": 23 }
//时间或日期格式化
{{ 1304375948024 | date:"yyyy-MM-dd hh:mm:ss" }}  //结果:2011-05-03 06:39:08
//数字格式化
{{ 1.234567 | number:1 }}  //结果:1.2
//金额格式化
{{ 250 | currency:"人民币: ¥ " }}    //结果:“人民币: ¥ 250.00 ”
//排序格式化
{
{ [{"age": 20,"id": 10,"name": "iphone"},
{"age": 12,"id": 11,"name": "sunm xing"},
{"age": 44,"id": 12,"name": "test abc"}
] | orderBy:'id':true }}    //根id降序排
//查找格式化
{
{ [{"age": 20,"id": 10,"name": "iphone"},
{"age": 12,"id": 11,"name": "sunm xing"},
{"age": 44,"id": 12,"name": "test abc"}
]  | filter:'s'}}  //查找含有有s的行
//字符串截取的格式化
{{ "i love tank" | limitTo:6 }}      //结果:i love
{{ "i love tank" | limitTo:-4 }}     //结果:tank

### 使用路由和$location切换视图- 虽然从技术角度来说,Ajax应用是单页面应用,但很多时候处于各种原因,我们需要切换跳转页面,而Angular的`$router`服务负责应对这样的场景。
- 路由服务机制是这样定义的:当浏览器指向特定的URL时,Angular会加载显示一个模板,并实例化一个控制器为此模板提供内容。
- 开发者可以通过`$routerProvider`服务的函数来创建路由,把需要创建的路由当做一个配置项传递给这些函数。

//创建模块
var someModule = angular.module('someModule',[...module dependencies...]);
someModule.config(function($routerProvider){
//通过$routerProvider定义url对应的跳转动作所需要的模板和控制器
$routerProvider.
when('url',{controller:aController,templateUrl:'/path/to/tempate'}).
othenwise('badUrl',{controller:notFoundController,templateUrl:'/path/to/tempate'});
});

### 与服务器交互- Angular提供的`$http`服务使得与服务器交互更加容易。它支持HTTP、JSONP和CORS方式。它还包含了安全性支持,避免JSON格式的脆弱性和XSRF。

function ShoppingController($scope,$http){
$http.get('/products').success(function(data,status,headers.config){
$scope.items = data;
});
};

### 使用指令修改DOM- Angular指令扩展了HTML的语法,通过自定义的元素或者属性,把行为和DOM转换关联到一起。通过Angular可以创建可复用的UI组件。
- Angular指令创建语法:(directiveFn是一个工厂函数,用来定义指令的特性)

var app = angular.module('myapp',[]);
app.directive(name,fn);

- 案例:定义ts-hello指令,向DOM中输出“Hello,Angular Directive!”

<!DOCTYPE html>
<html ng-app="DirectiveTestApp">
<head>
<meta charset="UTF-8">
<title>AngularJS Directive</title>
<style></style>
</head>
<script src="http://cdn.static.runoob.com/libs/angular.js/1.4.6/angular.min.js"></script>
<body>
<div ng-controller="SomeController">
<ts-hello></ts-hello>
<div ts-hello></div>
<div class="ts-hello"></div>
<div data-ts-hello></div>
</div>
</body>
<script type="text/javascript">
var app = angular.module('DirectiveTestApp', []);
app.directive("tsHello",function(){
return {
restrict : 'EAC',
template : '<h5>Hello,Angular Directive!</h5>'
}
});
</script>
</html>

### 校验用户输入- 在表单校验上,Angular允许开发者为表单的元素定义一个个发的状态,只有当所有元素都是合法状态时,才允许提交表单。
- 案例:一个用户注册页面,要求必须输入用户名和邮箱,使用H5的required属性

<!DOCTYPE html>
<html ng-app="myApp">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<h1>Sign Up</h1>
<form name="addUserForm" ng-controller="AddUserController">
<div ng-show="message">{{message}}</div>
First name : <input name="firstName" required/>
Last name : <input name="lastName" required/>
Email : <input name="email" required type="email"/>
Age : <input name="age" required type="number"/>
<button ng-click="addUser()" ng-disabled="!addUserForm.$valid">Submit</button>
</form>
<script src="http://cdn.static.runoob.com/libs/angular.js/1.4.6/angular.min.js"></script>
<script type="text/javascript">
var myApp = angular.module('myApp',[]);
myApp.controller('AddUserController',function($scope){
$scope.message = '';
$scope.AddUser = function(){
alert("add user success!");
}
});
</script>
</body>
</html>



作者:梁同学de自言自语
链接:https://www.jianshu.com/p/1542d2354cea


打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP