zoukankan      html  css  js  c++  java
  • AngularJS学习笔记(一)

    前言

    几个月之前了解过一点Angular,主要是通过phonecat应用程序了解一些入门东西,但是当被问及什么是Angular或者你对Angular的理解时,只记得一个MVVM双向数据绑定,显然这是不能令人满意的。现在重新来过吧。
    ps:该文档只是见证自己学习Angular的过程。所用版本为1.4.3。另外向大家推荐个windows下各 API离线查找工具Velocity,官网:http://velocity.silverlakesoftware.com/,真的不是一般地好用。

    AngularJS简介

    AngularJS是一个为动态WEB应用设计的结构框架,创新点在于,利用数据绑定依赖注入,使你不用再写大量的代码。AngularJS的一些出众之处在于:

    • 构建一个CRUD应用可能用到的全部内容包括:数据绑定、基本模板标识符、表单验证、路由、深度链接、组件重用、依赖注入
    • 测试方面包括:单元测试、端到端测试、模拟和自动化则是框架
    • 具有目录布局和测试脚本的种子应用作为起点

    而Angular信奉的是,当组建视图同时又要写软件逻辑时,声明式的代码会比命令式的代码好的多。

    基本概念

    首先举个例子:

    <!doctype html>
    <html lang="en" ng-app="myApp">
    <head>
        <meta charset="UTF-8">
        <title>myApp</title>
        <style>
            #test {
                width: 100px;
                height: 100px;
                background-color: red;
                border: 1px solid #ccc;
            }
        </style>
        <script src="js/jquery-1.7.1.js"></script>
        <script src="js/angular.min.js"></script>
    </head>
    <body ng-controller="myCtrl">
        <div id="test" ng-click="click()">Come ON!</div>
        <p>{{width}} * {{height}}</p>
        <p>Width: <input type="text" ng-model="width"/></p>
        <p>Height: <input type="text" ng-model="height"/></p>
        <script>
            "use strict";
            var myApp = angular.module("myApp", []);
            myApp.controller('myCtrl', ['$scope', function($scope) {
                var oDiv = angular.element('#test');
                $scope.width = oDiv.width();
                $scope.height = oDiv.height();
    
                $scope.click = function() {
                    $scope.width = parseInt($scope.width) + 10;
                    $scope.height = parseInt($scope.height) + 10;
                };
    
                $scope.$watch('width', function(to, from) {
                    oDiv.width(to);
                });
    
                $scope.$watch('height', function(to, from) {
                    oDiv.height(to);
                });
            }]);
        </script>
    </body>
    </html>

    从代码中可以看出,在HTML中引入了一些以ng开头的标记,这些就是angular(一下简称ng)声明式的代码。

    • 使用ng-app声明ng的初始化工作,同时定义了ng应用的作用域,ng的初始化一般绑定在DOMContentLoaded事件中,可以使用angular.bootstap(element,modules,config);手动引导ng应用程序。
    • ng-controller声明控制器,控制器里可以写相应的代码逻辑,修改相应的$scope,进行model到view的数据绑定工作。
    • ng-click绑定click事件,事件在controller中声明,绑定到$scope.
    • ng模板解析:默认使用{{}}
    • ng-model:ng的双向数据绑定声明

    依赖注入

    ng通过在函数参数中做手脚来完成“依赖声明”的功能。['$scope', 'dep1', 'dep2', function($scope, dep1, dep2) {}]像AMD声明一样,该函数依赖于$scope,dep1,dep2,然后依次作为参数传递进去。也可以使用另外一种声明方式,利用ng中的函数隐藏属性$inject(不推荐):

    var MyController = function($scope, greeter) {}
    MyController.$inject = ['$scope', 'greeter'];
    someModule.controller('MyController', MyController);

    在处理时,ng通过函数对象的toString()方法将该函数定义的代码转为字符串表现形式,然后利用正则表达式过滤出相应的参数,通过参数名获取资源,最后把资源作为参数调用定义的函数。
    因此最好采用上述两种方法来显示声明所需的依赖,防止代码压缩过程中压缩相应的函数参数而报错。

    作用域

    每个ng应用都有一个根作用域($rootScope),有多个子作用域。因为一些指令会声明新的子作用域,这些作用域的结构关系和其绑定到相应的DOM结构是对应的。
    属性查找:当ng查找某个模板中的某个数据时,会按照作用域链一直向上查找,直至找到或查至根作用域$rootrScope为至(独立作用域除外)。

    <body ng-controller="parentCtrl">
        <div ng-controller="childCtrl">
            <p>hello {{name || "world"}}!</p>
        </div>
    </body>

    事件冒泡:我们可以在scopes上模拟DOM事件类型的事件冒泡,该事件可以被广播到子作用域或者触发到父作用域。

    <div ng-controller="EventController">
        Root scope <tt>MyEvent</tt> count: {{count}}
        <ul>
            <li ng-repeat="i in [1]" ng-controller="EventController">
                <button ng-click="$emit('MyEvent')">$emit('MyEvent')</button>
                <button ng-click="$broadcast('MyEvent')">$broadcast('MyEvent')</button>
                <br>
                Middle scope <tt>MyEvent</tt> count: {{count}}
                <ul>
                    <li ng-repeat="item in [1, 2]" ng-controller="EventController">
                        Leaf scope <tt>MyEvent</tt> count: {{count}}
                    </li>
                </ul>
            </li>
        </ul>
    </div>
        <script>
            angular.module('myApp', [])
                    .controller('EventController', ['$scope', function($scope) {
                        $scope.count = 0;
                        $scope.$on('MyEvent', function() {
                            $scope.count++;
                        });
                    }]);
        </script>

    另外,我们还可以调用$watch()检测某个属性改变。

    模板与数据绑定

    ng中的主要特点之一就是双向数据绑定。

    数据->模板:

    可以直接使用ng的默认模板标记{{name}},则可以直接绑定一个作用域内的变量。当然也可以更改使用自定义的标记//name//

    <script>
        myApp.config(function($interpolateProvider) {
            $interpolateProvider.startSymbol('//');
            $interpolateProvider.endSymbol('//');
        });
    </script>

    模板:

    ng有自己的一套强大的模板命令:
    1.ng-include直接引入模板内容
    <div ng-include="'template.html'"></div>
    ng-include内容必须是字符串,需多加个引号。
    template.html主要有两种定义方式:
    (1)script标签中定义:type属性值为“text/ng-template”,id为ng-include属性值

    <script type="text/ng-template" id="template.html">
       <p>This is the content of the template</p>
    </script>

    (2)外部html文件中定义:该html文件名为ng-include的属性值

    Content of template.html

    2.内容控制
    (1)ng-cloak
    该指令绑定内容不显示,直到ng解析相关指令后才显示解析后的内容,避免相关内容解析前后出现跳转现象。
    (2)ng-show/ng-hide
    根据表达式的值来改变绑定该命令的DOM的display属性,相关CSS类已经在ng文件中提前定义,且使用了!important提升权重。

    点我: <input type="checkbox" ng-model="checked">
    <div>
        显示:
        <div ng-show="checked">
            选中时显示。
        </div>
    </div>
    <div>
        隐藏:
        <div ng-hide="checked">
            选中时隐藏。
        </div>
    </div>

    (3)ng-if
    不同于ng-show改变DOM的display属性来显示隐藏节点,ng-if根据表达式的布尔值判断:false则从文档中移除该DOM节点,true则向文档中添加该DOM节点。
    (4)ng-switch
    根据值的匹配情况来显示相应的节点:
    ng-init直接在模板中进行赋值,与作用域无关。

    <div ng-init="a=1">
            <div ng-switch on="a">
                <div ng-switch-when="1">1</div>
                <div ng-switch-when="2">2</div>
                <div ng-switch-default>other</div>
            </div>
        </div>

    (5)ng-repeat
    遍历对象或数组:

    <div ng-init="list = [{name: 'AAA'}, {name: 'BBB'}, {name: 'CCC'}]">
            <ul ng-repeat="member in list">
                <li>{{$index}}</li>
                <li>{{$first}}</li>
                <li>{{$middle}}</li>
                <li>{{$last}}</li>
                <li>{{$odd}}</li>
                <li>{{$even}}</li>
                <li>{{member.name}}</li>
            </ul>
        </div>

    额外变量:
    $index 当前索引
    $first 是否为首元素
    $middle 是否为中间元素
    $last 是否为尾元素
    $odd 当前索引是否为奇数
    $even 当前索引是否为偶数
    遍历对象使用(key, value) in obj.
    另外,默认待遍历的数组中不能有重复值,因为数组元素与相应的DOM元素是一对一的关系。如需要使用:

    <ul ng-repeat="n in [10,10,10,10] track by $index">
            {{n}}
        </ul>

    (6)其它

    • ng-src src属性
    • ng-href href属性
    • ng-checked 选中状态
    • ng-selected 被选择状态
    • ng-disabled 禁用状态
    • ng-multiple 多选状态
    • ng-readonly 只读状态

    3.样式
    (1)ng-style
    使用对象字面量的形式来赋值:

    <input type="button" value="set color" ng-click="myStyle={color:'red'}">
    <input type="button" value="set background" ng-click="myStyle={'background-color':'blue'}">
    <input type="button" value="clear" ng-click="myStyle={}">
    <br/>
    <span ng-style="myStyle">Sample Text</span>
    <pre>myStyle={{myStyle}}</pre>

    (2)ng-class
    直接通过字符串绑定CSS中预定义的类

    <!doctype html>
    <html lang="en" ng-app>
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
        <script src="js/angular.min.js"></script>
        <style>
            .strike {
                text-decoration: line-through;
            }
            .bold {
                font-weight: bold;
            }
            .red {
                color: red;
            }
        </style>
    </head>
    <body>
    <p ng-class="style">Using String Syntax</p>
    <input type="text" ng-model="style"
           placeholder="Type: bold strike red" aria-label="Type: bold strike red">
    </body>
    </html>

    4.事件绑定:
    模板中的事件绑定预定义了一些常用的事件绑定指令,可以直接传递相关的处理程序且直观地在DOM中声明。

    • ng-blur
    • ng-change
    • ng-click
    • ng-dblclick
    • ng-focus
    • ng-keydown
    • ng-keypress
    • ng-keyup
    • ng-mousedown
    • ng-mouseenter
    • ng-mouseleave
    • ng-mousemove
    • ng-mouseover
    • ng-mouseup
      使用$event可以给相应的事件处理函数传递事件对象本身
    <input ng-keyup="show($event)">
        <p>event keyCode: {{ keyCode }}</p>
        <p>event altKey: {{ altKey }}</p>
        <script>
            angular.module('myApp',[])
                    .controller('myCtrl', function($scope) {
                        $scope.show = function($event) {
                            $scope.keyCode = $event.keyCode;
                            $scope.altKey = $event.altKey;
                        }
                    });
        </script>

    5.表单
    HTML中form是一个核心控件,是网页与用户进行交流的主要方式之一。而ng对form进行了封装”ng-form”,区别是HTML中的form不能嵌套,而ng-form可以嵌套。而ng-form的目的就是为了统一控制,而不是为了取代form标签。

    form中的一些控件可以预先通过ng-controller中的$scope绑定一些状态。

    <!doctype html>
    <html lang="en" ng-app="myApp">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
        <script src="js/angular.min.js"></script>
    </head>
    <script>
        angular.module('myApp', [])
                .controller('FormController', ['$scope', function($scope) {
                    $scope.userType = 'guest';
                }]);
    </script>
    <style>
        .my-form {
            -webkit-transition:all linear 0.5s;
            transition:all linear 0.5s;
            background: transparent;
        }
        .my-form.ng-invalid {
            background: red;
        }
    </style>
    <body>
    <form name="myForm" ng-controller="FormController" class="my-form">
        userType: <input name="input" ng-model="userType" required >
        <span class="error" ng-show="myForm.input.$error.required">Required!</span><br>
        age: <input name="input_b" ng-model="age" required pattern="d+">
        <span class="error" ng-show="myForm.input_b.$error.required">Required!</span>
        <span class="error" ng-show="myForm.input_b.$error.pattern">Pattern!</span><br>
        <code>userType = {{userType}}</code><br>
        <code>myForm.input.$valid = {{myForm.input.$valid}}</code><br>
        <code>myForm.input.$error = {{myForm.input.$error}}</code><br>
        <code>myForm.$valid = {{myForm.$valid}}</code><br>
        <code>myForm.$error.required = {{!!myForm.$error.required}}</code><br>
    </form>
    </body>
    </html>

    ng给form提前定义了一些CSS类:

    • ng-valid 当表单验证全部通过时使用
    • ng-invalid 表单中有未通过验证的控件时使用
    • ng-pristine 当表单为被修改之前使用
    • ng-dirty 当表单被修改之后使用
    • ng-submitted 当表单被提交之后使用

    form对象有一些属性:

    • $pristine 表单是否未被动过
    • $dirty 表单是否被动过
    • $valid 表单是否通过验证
    • $invalid 表单是否未通过验证
    • $error 表单的错误对象

    其中$error是一个hash对象,引用表单控件中未通过验证的键值对。属性是验证失败信息,值是对应的实例列表。另外,该失败对象是按一定的验证逻辑所取,例如上例中的age输入框,先判定required,在判定pattern。$error对象可能的属性有:email/max/maxlength/min/minlength/number/pattern/required/url/date/time/week/month.
    同时,我们也能在form中的具体某个input框中查看相应的错误,格式为formName.inputName.$error.但是,input控件的相关属性是ng-required/ng-pattern等,经测试发现,仅ng-maxlength,ng-max,ng-min与HTML5中相关属性有区别:ng-maxlength=’12’可以输入超过12个字符,但超过相关属性为true,而maxlength则最多只能输入12个字符,超过默认丢弃,相关错误属性永不为true.
    (1)checkbox/radio
    可以为checkbox分别绑定ng-true-value/ng-false-value的值,为radio绑定value值。而这些值与视图中的相关控件是否选中相对应。

    checkbox: <input type="checkbox" name="box" ng-model="check" ng-true-value="'China'" ng-false-value="'Beijing'" />
        <span>check = {{check}}</span>
        <hr />
        radio: <input type="radio" name="checkRadio" ng-model="checkRadio" value="China" />
        radio: <input type="radio" name="checkRadio" ng-model="checkRadio" value="Beijing" /><br>
        <span>radio = {{checkRadio}}</span>

    (2)textarea
    包含input框中相应属性,仅多了ng-trim指令。
    (3)select
    select控件中,有个用于呈现下拉选项的指令ng-options主要用于select模板中绑定的是非字符串。主要用法见下例:

    <!doctype html>
    <html lang="en" ng-app="myApp">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
        <script src="js/angular.min.js"></script>
    </head>
    <body>
        <div ng-controller="myCtrl">
            <h3>参数是数组情况下:</h3>
            <label>Color (可以指定value为null的option)
                <select ng-model="myColor1" ng-options="color.name for color in colors">
                    <option value="">——Choose Color——</option>
                </select>
                <span>选择颜色:{{myColor1}}</span>
            </label><br />
    
            <label>Color(区分显示和值)
                <select ng-model="myColor2" ng-options="color.name as color.shade for color in colors">
                </select>
                <span>选择颜色:{{myColor2}}</span>
            </label><br />
    
            <label>Color(以shade值分组)
                <select ng-model="myColor3" ng-options="color.name group by color.shade for color in colors">
                </select>
                <span>选择颜色:{{myColor3}}</span>
            </label><br />
    
            <label>Color (以shade分组,且有附加条件)
                <select ng-model="myColor4" ng-options="color.name group by color.shade disable when color.notAnOption for color in colors">
                </select>
                <span>选择颜色:{{myColor4}}</span>
            </label>
    
            <h3>参数是对象情况下:</h3>
            <label>Color (以shade分组,且有附加条件)
                <select ng-model="ordinalNumber1" ng-options="value.name  for (key, value) in ordinal">
                </select>
                <span>所选列:{{ordinalNumber1}}</span>
            </label><br />
    
            <label>Color(区分显示和值)
                <select ng-model="ordinalNumber2" ng-options="value.value as value.name for (key, value) in ordinal">
                </select>
                <span>所选列:{{ordinalNumber2}}</span>
            </label><br />
    
            <label>Color(以shade值分组)
                <select ng-model="ordinalNumber3" ng-options="value.name group by value.group for (key, value) in ordinal">
                </select>
                <span>所选列:{{ordinalNumber3}}</span>
            </label><br />
    
            <label>Color (以shade分组,且有附加条件)
                <select ng-model="ordinalNumber4" ng-options="value.value group by value.group disable when value.notAnOption for (key, value) in ordinal">
                </select>
                <span>所选列:{{ordinalNumber4}}</span>
            </label>
        </div>
    
        <script>
            angular.module('myApp', []).controller('myCtrl', ['$scope', function($scope) {
                $scope.colors = [
                    {name:'black', shade:'dark'},
                    {name:'white', shade:'light', notAnOption: true},
                    {name:'red', shade:'dark'},
                    {name:'blue', shade:'dark', notAnOption: true},
                    {name:'yellow', shade:'light', notAnOption: false}
                ];
    
                $scope.ordinal = {
                    first: {
                        name: "1st",
                        value: "NO.1",
                        group: "1-3"
                    },
                    second: {
                        name: "2nd",
                        value: "NO.2",
                        group: "1-3",
                        notAnOption: true
                    },
                    third: {
                        name: "3nd",
                        value: "NO.3",
                        group: "1-3",
                        notAnOption: true
                    },
                    fourth: {
                        name: "4th",
                        value: "NO.4",
                        group: "4-5"
                    },
                    fifth: {
                        name: "5th",
                        value: "NO.5",
                        group: "4-5",
                        notAnOption: false
                    }
                };
            }]);
        </script>
    </body>
    </html>

    通常情况下,ng-repeat也可用在option元素中,但ng-repeat会为每个遍历的实例创造一个新的作用域,而使用ng-options则具有节省内存,响应更快捷的优点。

    模板->数据:

    ng中模板到数据的绑定主要是通过ng-model来实现。

    <p>hello {{name || "World"}}!</p>
    <hr/>
    <input type="text" ng-model="name"/>

    当我们在input框中输入内容,会发现模板中内容也相应改变。实际上,ng中的双向数据绑定主要是通过ng-model来实现。

    过滤

    ng默认提供了一些可以直接使用的过滤指令

    • currency 货币过滤指令
    • date 时间过滤指令
    • filter 数组过滤指令
    • json 将js对象转换为json字符串
    • limitTo 截取字符串/数组/数字的一部分
    • lowercase 字符串转小写
    • number 格式化数字
    • orderBy 数组排序
    • uppercase 字符串转大写
    • linky 找出文本输入中的连接然后格式化

    模板中使用

    我们可以在模板中使用过滤命令,使用方法类似与linux系统中的管道命令{{expression | filter1:arg1:arg2:... | filter2:arg}}即我们可以在一个语句后面使用多个过滤命令,依次用”|”分割开即可,也可以在一个过滤命令后面传递多个参数,依次用“:”分割开即可。

    <span>{{1437272917693 | date:"MM/dd/yyyy 'at' h:mma"}}</span><br>
    <span>{{ ["AAAAA","AAAA","AAA","AA","A","BBB","BB"] | filter:'A' | limitTo: 2 }}</span><br>

    JS中使用

    JS中使用过滤命令有两种方式:
    (1)<filterName>Filter方式:
    在依赖声明中明确声明需要使用filterName的过滤指令,然后就可以在内部向该指令函数传递参数,返回处理后的数据:

    angular.module('myApp', [])
    .controller('filterCtrl', ['filterFilter', 'dateFilter', 'numberFilter', 'currencyFilter', '$scope',
                function(myFilter, dateFilter, numberFilter, currencyFilter, $scope) {
                    $scope.array = contacts;
                    $scope.filteredArray = myFilter(this.array, 'a');
                    $scope.date = dateFilter(1437272917693, 'mediumDate');
                    $scope.number = numberFilter(1437272917693,2);
                    $scope.money = currencyFilter(100.1234,'¥',2);
                }]);

    (2)$filter方式
    依赖声明中引入$filter,然后我们就可以在内部向该函数传入我们想要使用的过滤指令名,返回对应的过滤指令函数。较方式1简单:

    angular.module('myApp', [])
                    .controller('myCtrl', ['$scope', '$filter', function($scope, $filter) {
                        $scope.filteredText = $filter('uppercase')('China');
                        $scope.number = $filter('number')(123456789.1123);
                    }]);

    自定义过滤命令

    如果感觉ng默认提供的几种过滤指令满足不了需求,我们可以自定义指令。通过你的module中的filter工厂函数就可以自定义一个新的指令。

    angular.module('myApp', [])
                .filter('reverse', function() {
                    return function(input, uppercase) {
                        input = input || '';
                        var out = "";
                        for (var i = 0; i < input.length; i++) {
                            out = input.charAt(i) + out;
                        }
                        // 可传入参数uppercase
                        if (uppercase) {
                            out = out.toUpperCase();
                        }
                        return out;
                    };
                })

    向filter工厂函数传入命令名,初始化函数,返回一个过滤函数,过滤函数第一个参数是待过滤的内容,其余参数依次输入。仅当该过滤指令的输入内容改变时,ng才会执行该指令。
    另外,自定义的过滤函数应该全部是无状态的,那些有状态的指令无法被ng优化,经常导致表现问题。而如果真的需要维持状态的过滤命令,可指定该过滤函数的$stateful属性,这样每次模板中内容改变该过滤函数都会执行一次。

    angular.module('myStatefulFilterApp', [])
    .filter('decorate', ['decoration', function(decoration) {
    
      function decorateFilter(input) {
        return decoration.symbol + input + decoration.symbol;
      }
      decorateFilter.$stateful = true;
    
      return decorateFilter;
    }])

    另外,自定义的过滤函数只能在模板中使用。

    AJAX

    与其它框架一样,ng也提供了类似的一套AJAX封装,内部通过XMLHttpRequest对象或JSONP方式。

    $HTTP

    $HTTP提供基本的操作服务,传入一个config配置对象,设置一些参数,返回一个可以注册成功、失败回调函数的promise对象。$http常用的配置有:

    • method 请求方法
    • url 请求路径
    • params GET请求的参数
    • data 请求报文(POST请求的参数)
    • headers 定义请求报头
    • cache GET请求的缓存
    • timeout 过期时间
    • responseType 响应类型

    另外对于一些请求方式,有一些简写:

    • $http.get(url, [config])
    • $http.delete(url, [config])
    • $http.head(url, [config])
    • $http.jsonp(url, [config])
    • $http.post(url, data, [config])
    • $http.put(url, data, [config])
    $http({method: $scope.method, url: $scope.url}).
            success(function(data, status) {
              $scope.status = status;
              $scope.data = data;
            }).
            error(function(data, status) {
              $scope.data = data || "Request failed";
              $scope.status = status;
          });

    $http属性:

    • pendingRequests 当前请求队列状态,主要用于测试
    • defaults 请求的全局配置

    异步回调

    ng的异步回调函数服务$q为AJAX的异步回调提供服务。
    (1)$q用法

    • $q(resolveFn, errorFn) 注册并返回一个promise对象
    • $q.defer() 返回一个deferred实例
    • $q.reject(reason) 包装一个错误
    • $q.when(value) 返回一个promise对象
    • $q.resolve(value) 与when方法一样,为了与ES6保持一致性
    • $q.all(promises) 将多个promise对象合并成一个promise对象

    (2)deferred对象:通过$q.defer()构建

    • resolve(value) 成功回调
    • reject(reason) 失败回调
    • notify(value) 更新promise的执行状态
    • promise属性 返回一个promise对象

    (3)promise

    • then(successCallback, errorCallback, notifyCallback) 分别注册成功,失败,通知的回调函数
    • catch(errorCallback) 相当于then(null, errorCallback) 注册失败回调函数
    • finally(callback, notifyCallback)
    angular.module('myApp', []).controller('myCtrl', ['$q', function($q) {
                function success(message) {
                    console.log("OK! " + message);
                }
    
                function error(message) {
                    console.log("error! " + message);
                }
    
                function notify(message) {
                    console.log('notify! ' + message);
                }
                var defer = $q.defer(),
                        promise = defer.promise;
                promise.then(success, error, notify);
    
    //            defer.resolve('resolve');
    //            defer.reject('reject');
                defer.notify('notify');

    其它部分,明天继续。。。

    参考内容

    http://www.zouyesheng.com/angular.html
    http://www.cnblogs.com/lcllao/archive/2012/10/18/2728787.html

  • 相关阅读:
    201521123053《Java程序设计》第十周学习总结
    201521123003《Java程序设计》第9周学习总结
    201521123053《Java程序设计》第八周学习总结

    201521123053《Java课程设计》第七周学习总结
    201521123053《Java设计与程序》第六周学习总结
    201521123053 《Java程序设计》第5周学习总结
    例子
    201521123053《Java程序设计》第四周总结
    201521123049 《JAVA程序设计》 第11周学习总结
  • 原文地址:https://www.cnblogs.com/qingguo/p/5686290.html
Copyright © 2011-2022 走看看