AngularJS双向数据绑定

一、概念

AngularJS中,只关心数据,数据的变化会自动引起视图的变化。并且视图是局部刷新的,不是整个页面刷新的,AngularJS会自动识别哪里用到了这个更新的数据,即脏数据检查。

我们可以把控制器中的数据表现在视图上,也可以更新视图来改变控制器中的数据。

最简单的更新视图的方法就是表单元素,AngularJS中提出了two-way databinding双向数据绑定的技术,让视图和控制器中的数据实时双向绑定。

<!DOCTYPE html>
<html lang="en" ng-app="myapp">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script type="text/javascript" src="../libs/angular.js/1.3.2/angular.js"></script>
</head>
<body>
    <div ng-controller="MainController as mc">
        <h1>{{ mc.name }}</h1>
        <!-- 只有表单元素才允许使用ng-model指令 -->
        <input type="text" ng-model="mc.name">
    </div>
    <script type="text/javascript">
        var myapp = angular.module("myapp",[]);

        //第二个参数是数组,表示依赖注入
        myapp.controller("MainController", [function () {
            this.name = "我爱中国";
        }]);
    </script>
</body>
</html>

效果图如下:

小结:

所有表单控件都可以使用ng-model指令来与控制器中的某一个值进行双向数据绑定,指的是:

① 当控制器中的值变化时,控件中的值也跟着变化

② 当控件中的值变化时,控制器中的值也跟着变化

二、案例1:调色板

代码如下: 

<!DOCTYPE html>
<html lang="en" ng-app="myapp">
<head>
    <meta charset="UTF-8">
    <title>调色板</title>
    <style type="text/css">
        .box {
            width: 200px;
            height: 200px;
            border: 1px solid #333;
        }
    </style>
    <script type="text/javascript" src="../libs/angular.js/1.3.2/angular.js"></script>
</head>
<!-- 实例化控制器MainController,起个别名mc -->
<body ng-controller="MainController as mc">
    <h2>{{ mc.name }}</h2>
    <div class="box" ng-style="mc.color()"></div>
    R:<input type="range" min="0" max="255" ng-model="mc.r">
    <input type="text" ng-model="mc.r"> <br/>

    G:<input type="range" min="0" max="255" ng-model="mc.g">
    <input type="text" ng-model="mc.g"><br/>

    B:<input type="range" min="0" max="255" ng-model="mc.b">
    <input type="text" ng-model="mc.b">
    <script type="text/javascript">
        var myapp = angular.module("myapp", []);

        myapp.controller("MainController", [function () {
            this.name = "我的调色板";
            this.r = 100;
            this.g = 100;
            this.b = 100;
            //这样写,不会生效,需要改成函数的形式,同时ng-style="mc.color"改为ng-style="mc.color()",这是angularjs规定的
            // this.color = {
            //     "background-color": "rgb(" + this.r + ", 100, 100)"
            // };
            this.color = function () {
                return {
                    "background-color": "rgb(" + this.r + ", " + this.g + ", " + this.b + ")"
                };
            };
        }]);
    </script>
</body>
</html>

运行效果:

 这里, 如果把type="text"替换为type="number",滑动块时,会出现如下错误:

 

 如何解决?

 

小结:

  a. 我们的程序没有一行关于DOM的,因为关于DOM的语句已经暗含到HTML标签上面的“指令”上面了.

  b. 这个例子里面,学习了一个内置指令(事实上AngularJS对HTML的升级就是体现在发明了很多内置指令上)ng-style:

    ng-style指令表示给HTML元素加上动态样式(从控制器中读取值的样式),此时感觉是历史的倒退,因为好不容易把HTML和CSS分开,AngularJS又给合上了。

  c. 如果控制器中的某一个值,由其他值决定,并且希望其他值改变的时候,这个值也能改变,此时要写成函数return的形式。

   

   

三、案例2:模拟微博发布

 需求:发微博限制140字,能够实时提醒用户写了多少字,例如,75/140字。当超过140字的时候数字变红,同时发布按钮不能点击。

 分析:AngularJS的世界不能操作DOM,一切都要控制数据。Angular、React、Vue等等都是不直接操作DOM,去jQuery化。

<!DOCTYPE html>
<html lang="en" ng-app="myapp">
<head>
    <meta charset="UTF-8">
    <title>模拟微博发布</title>
    <script type="text/javascript" src="../libs/angular.js/1.3.2/angular.js"></script>
</head>
<!--实例化控制器MainController-->
<body ng-controller="MainController as mc">
    <h3>{{ mc.name }}</h3>
    <p>
        <textarea cols="30" rows="10" ng-model="mc.txt"></textarea>
        <!--<span ng-style="{'color': 'red'}">{{ mc.txt.length }}/140字</span>-->
        <span ng-style="mc.getColor()">{{ mc.txt.length }}/140字</span>
    </p>
    <p>
        <input type="button" value="发布" ng-disabled="mc.txt.length > 140 || mc.txt.length == 0"/>
        <input type="button" value="清空" ng-click="mc.reset()" ng-disabled="mc.txt.length == 0"/>
    </p>

    <script>
        var myapp = angular.module("myapp", []);

        myapp.controller("MainController", [function () {
            this.name = "微博发布";

            //这里也可以不定义
            this.txt = "";

            //颜色
            var self = this;
            this.getColor = function () {
               return self.txt.length > 140 ? { "color" : "red" } : { "color" : "#333" }
            };

            //清空
            this.reset = function () {
              this.txt = "";
            };
        }]);
    </script>
</body>
</html>

效果如下图:

小结:

  a.  ng-disabled指令:可以让disabled属性变得“智能”、“动态化”,可以根据值来决定它的true或false,此时ng-disabled中可以写表达式,例如本例中的mc.txt.length > 140或者写函数。

  b. 本例中涉及到的数据只有文本这个东西(mc.txt),其他的字数提示、字数提示的颜色、发布按钮是否禁用等等 都是根据它的length来决定的。

四、案例3:模拟表格 

需求:不使用AJAX与服务器交互,假设数据已经取到浏览器本地,需要呈现在页面上。

<!DOCTYPE html>
<html lang="en" ng-app="myapp">
<head>
    <meta charset="UTF-8">
    <title>模拟表格</title>
    <style type="text/css">
        .table_wrap {
            width: 600px;
            margin: 0 auto;
        }
        table, tr, th, td {
            border-bottom: 1px solid #333;
            border-collapse: collapse;
        }
        th, td {
            width: 20%;
            line-height: 150%;
        }
        tr:nth-child(2n) {
            background-color: #eee;
        }
    </style>
    <script type="text/javascript" src="../libs/angular.js/1.3.2/angular.js"></script>
</head>
<body ng-controller="MainController as mc">
    <div class="table_wrap">
        <table width="600">
            <tr>
                <th>学号</th>
                <th>姓名</th>
                <th>语文成绩</th>
                <th>数学成绩</th>
                <th>英语成绩</th>
            </tr>
            <tr ng-repeat="item in mc.data">
                <td>{{ item.sid }}</td>
                <td>{{ item.name }}</td>
                <td>{{ item.yuwen }}</td>
                <td>{{ item.shuxue }}</td>
                <td>{{ item.yingyu }}</td>
            </tr>
        </table>
    </div>
    <script>
        var myapp = angular.module("myapp", []);

        //定义控制器
        myapp.controller("MainController", [function () {
            //定义数据:数组
            this.data = [
                {"sid": 1001, "name": "小明", "yuwen": 99, "shuxue": 100, "yingyu":98},
                {"sid": 1002, "name": "小洪", "yuwen": 99, "shuxue": 100, "yingyu":98},
                {"sid": 1003, "name": "小亮", "yuwen": 99, "shuxue": 100, "yingyu":98},
                {"sid": 1004, "name": "小蓝", "yuwen": 99, "shuxue": 100, "yingyu":98}
            ];
        }]);
    </script>
</body>
</html>

使用ng-repeat指令来重复一个HTML标签,语法如下:
  <div ng-repeat="变量名 in 数组数据"></div>

此时,这个变量将按顺序自动去迭代数组数据中的每一项。

效果如下图:

WebStorm小技巧:按住alt键   鼠标选择一列,然后输入文字就会编辑多行,这个功能很赞,比较实用

接下来,我们在网页上实现增、删、排序功能,实现如下效果:

涉及js数组的添加、删除、排序方法

代码如下:

<!DOCTYPE html>
<html lang="en" ng-app="myapp">
<head>
    <meta charset="UTF-8">
    <title>模拟表格</title>
    <style type="text/css">
        .table_wrap {
            width: 600px;
            margin: 0 auto;
        }
        table, tr, th, td {
            border-bottom: 1px solid #333;
            border-collapse: collapse;
        }
        th, td {
            width: 20%;
            line-height: 150%;
        }
        tr:nth-child(2n) {
            background-color: #eee;
        }

        .form_box {
            background-color: skyblue;
            padding: 10px;
            width: 400px;
        }
    </style>
    <script type="text/javascript" src="../libs/angular.js/1.3.2/angular.js"></script>
</head>
<body ng-controller="MainController as mc">
    <div class="table_wrap">
        <table width="600">
            <tr>
                <th ng-click="mc.changeSort('sid')">学号<span ng-show="mc.sortBy == 'sid'">{{ mc.sign() }}</span></th>
                <th ng-click="mc.changeSort('name')">姓名<span ng-show="mc.sortBy == 'name'">{{ mc.sign() }}</span></th>
                <th ng-click="mc.changeSort('yuwen')">语文<span ng-show="mc.sortBy == 'yuwen'">{{ mc.sign() }}</span></th>
                <th ng-click="mc.changeSort('shuxue')">数学<span ng-show="mc.sortBy == 'shuxue'">{{ mc.sign() }}</span></th>
                <th ng-click="mc.changeSort('yingyu')">英语<span ng-show="mc.sortBy == 'yingyu'">{{ mc.sign() }}</span></th>
                <th>操作</th>
            </tr>
            <tr ng-repeat="item in mc.data">
                <td>{{ item.sid }}</td>
                <td>{{ item.name }}</td>
                <td>{{ item.yuwen }}</td>
                <td>{{ item.shuxue }}</td>
                <td>{{ item.yingyu }}</td>
                <td><input type="button" value="删除" ng-click="mc.remove(item.sid)"></td>
            </tr>
        </table>
    </div>
    <div class="form_box">
        <p>
            结果:{{ mc.formobj }}
        </p>
        <p>
            学号:<input type="text" ng-model="mc.formobj.sid"/>
        </p>
        <p>
            姓名:<input type="text" ng-model="mc.formobj.name"/>
        </p>
        <p>
            语文:<input type="text" ng-model="mc.formobj.yuwen"/>
        </p>
        <p>
            数学:<input type="text" ng-model="mc.formobj.shuxue"/>
        </p>
        <p>
            英语:<input type="text" ng-model="mc.formobj.yingyu"/>
        </p>
        <p><input type="button" value="添加" ng-click="mc.add()"></p>
    </div>
    <script>
        var myapp = angular.module("myapp", []);

        //定义控制器
        myapp.controller("MainController", [function () {
            //定义数据:数组
            this.data = [
                {"sid": 1001, "name": "小明", "yuwen": 99, "shuxue": 100, "yingyu":98},
                {"sid": 1002, "name": "小洪", "yuwen": 99, "shuxue": 100, "yingyu":98},
                {"sid": 1003, "name": "小亮", "yuwen": 99, "shuxue": 100, "yingyu":98},
                {"sid": 1004, "name": "小蓝", "yuwen": 99, "shuxue": 100, "yingyu":98}
            ];
            //定义表单对象
            this.formobj = {};

            //添加
            let self = this;
            this.add = function () {
                self.data.push(self.formobj);
            };

            //删除
            this.remove = function (sid) {
                self.data.forEach(function (value, key, ownerArr) {
                    if(value.sid == sid){
                        self.data.splice(key, 1);
                    }
                });
            }

            //排序字段
            this.sortBy = 'name';
            //排序方式 asc=true 升序 asc=false降序
            this.asc = true;

            //排序符号
            this.sign = function () {
                return self.asc == true ? "" : "";
            };

            this.changeSort = function (sortBy) {
                if(sortBy == self.sortBy) {
                    self.asc = !self.asc;
                } else {
                    self.sortBy = sortBy;
                }

                //排序
                self.data.sort(function (a, b) {
                    if(a[self.sortBy] > b[self.sortBy]) {
                        return self.asc ? 1 : -1;
                    } else {
                        return self.asc ? -1 : 1;
                    }
                });
            }
        }]);
    </script>
</body>
</html>

 

五、案例4:省市县联动

 

posted @ 2021-02-01 17:39  外星鸟  阅读(306)  评论(0)    收藏  举报