Skip to content

angularjs

遇见王斌 edited this page Jan 4, 2020 · 2 revisions

angularjs[1.6.8]

路由、模板交给 angular 处理

以下实践记录中

  • 新加的记录后面加着##
  • 修改的记录后面加着#*

1 简介

1.1 基础

菜鸟教程

指令

AngularJS 指令是扩展的 HTML 属性,带有前缀 ng-

关于 ng-model 和 ng-bind 以及 {{}}

  • ng-bind 是从 $scope -> view 的单向绑定
  • ng-modle 是 $scope <-> view 的双向绑定

在 AngularJS 中显示模型中的数据有两种方式:

表达式
<p>{{text}}</p>

使用基于属性的指令,ng-bind:
<p ng-bind="text"></p>

主要区别在于,使用花括号语法时,在 AngularJS 使用数据替换模板中的花括号时,第一个加载的页面,通常是应用中的 index.html,其未被渲染的模板可能会被用户看到。而使用第二站方法的视图不会遇到这种问题。

原因是,浏览器需要首先加载 index.html 页面,渲染它,然后 AngularJS 才能把它解析成你期望看到的内容。

service

在 AngularJS 中,服务是一个函数或对象,可在你的 AngularJS 应用中使用。

  • $location 地址服务
  • $http
  • $timeout 超时器
  • $interval 定时器

$http

<script>
var app = angular.module('myApp', []);
app.controller('siteCtrl', function($scope, $http) {
  $http.get("https://www.runoob.com/try/angularjs/data/sites.php")
  .success(function (response) {$scope.names = response.sites;});
});
</script>

AngularJS HTML DOM

  • ng-disabled 禁用
  • ng-show 是否显示
  • ng-hide 是否隐藏

事件

  • ng-click 点击时触发某个事件

文件包含

  • ng-include="'file.html'"

隐式和显式依赖注入

    1. 隐式注入:不需要开发人员干预,angularJS 自动根据参数的名称识别和注入数据
    1. 显式注入:开发人员通过字符串描述,告诉 angular 需要注入的对象名称

在之前学习 AngularJS 的过程中,用到了隐式依赖注入,比如:

<script type="text/javascript">
    angular.module('app', [])
    .controller('Controller1', function($scope) {
        $scope.something = 'hello world';
    });
</script>

依赖注入 $scope。这么写有个弊端,在发布的时候,往往要压缩 JavaScript 代码,压缩时,会替换掉变量名。比如 $scope 会替换成长度更小的 a,但是 $scope 这个名字又是不能改动的,否则会无法识别。所以这种隐式的依赖注入方法不好。

AngularJS 提倡用以下这种方法:

<script type="text/javascript">
    angular.module('app', [])
    .controller('Controller1', ['$scope', function(parm){
        parm.something = 'hello world';
    }]);
</script>

这种方法是显式的依赖注入,把 $scope 当作一个字符串,则压缩时不会被替换掉,随便命名一个参数 parm,在函数体中运用时同名即可。

不仅是 controller,其它需要依赖注入的地方都提倡用显式的方法。

var myApp = angular.module('myApp', [], function () {

})
    // 隐式的依赖注入
    // .factory('CustomeService', function ($window) {
    //     console.log($window);
    // })
    // 显示的依赖注入
    .factory('CustomService',['$window',function (a) {//a 参数就是 $window
        console.log(a);
    }])
    // 隐式的依赖注入
    .controller('secondController', function ($scope, CustomService) {
    })
// // 显式的依赖注入(推荐使用)
// .controller('secondController', ['$scope', '$filter', function (a, b) {
//     console.log(b('json')([1, 2, 3, 4, 5]));
// }])


function otherController(a) {
    console.log(a);
}
otherController.$inject = ['$scope']; // 此处的 $scope 就是上面的参数 a

1.2 MVVM

MVVM 核心:Model(模型),View(UI),ViewModel(视图模型)

Model:数据展现的对象模型
View:页面 UI
ViewModel:实现 Model 和 View 的双向绑定(ViewModel 的含义就是 "Model of View",视图的模型)

它们的工作模型应该是:Model<=>ViewModel<=>View

数据双向绑定

在 Model 中变量和方法 $scope.variable & $scope.function()
在 View 界面中不会出现 $scope 字符,直接写在 {{expression}},会输出对应的 variable 或者 function() 的值,而表达式中的 variable 和 function() 是 $scope 的属性或者方法

1.3 下载

angularjs 下载

或者百度静态资源库

  • angular.min.js
  • angular-route.min.js----------- 路由
  • angular-resource.min.js-------- 与后端 restful 接口进行交互

2 配置

2.1 template 输出网页

2.1.1 django url 配置

例子:project/zabbix_manager_web/urls.py

from django.conf.urls import url,include
from django.contrib import admin

from django.views.generic import TemplateView ##

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^api/', include('api.urls')),
    url(r'^$', TemplateView.as_view(template_name='index.html')),##
]

2.1.2 设置 template 目录

例子:project/zabbix_manager_web/settings.py

在 settings.py 设置默认搜索 project 目录下的 templates 目录,并在 project 目录下创建 templates 目录

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [BASE_DIR+"/templates"], #*
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

2.1.3 编写 html 文件

例子:project/templates/index.html

<html>
<body>
meetbill
</body>
</html>

2.1.4 查看运行效果

#python manage.py runserver 0.0.0.0:8888

2.2 前端文件引入 angularjs

2.2.1 设置静态文件目录

例子:project/zabbix_manager_web/settings.py 末尾添加如下,并在 project 目录下创建 static 目录

STATICFILES_DIRS = ( BASE_DIR + '/static',  )

2.2.2 前端文件引入 angularjs

(1) 将 angular 文件下载到 project/static/js/angular/angular.min.js

(2) 编写 controller 文件 project/static/js/angular/controller.js

var app = angular.module("myApp", []);
app.config(
    function($interpolateProvider) {
        $interpolateProvider.startSymbol('[[');
        $interpolateProvider.endSymbol(']]');
    })
    .config(['$httpProvider', function($httpProvider) {
        $httpProvider.defaults.xsrfCookieName = 'csrftoken';
        $httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';
}]);
app.controller("myCtrl", function($scope) {
    $scope.name = "wangbin";
});

(3) 编写 html 文件 project/templates/index.html

<html>
<head>
<meta charset="utf-8">
<script src="/static/js/angular/angular.min.js"></script>
<script src="/static/js/angular/controller.js"></script>
</head>
<body>

<div ng-app="myApp" ng-controller="myCtrl">
    <p>名字 : <input type="text" ng-model="name"></p>
    <h1>Hello [[ name ]]</h1>
</div>

</body>
</html>

2.2.3 查看运行效果

#python manage.py runserver 0.0.0.0:8888

2.3 routeProvider 多视图

2.3.1 前端文件引入 angularjs-route

(1) 编写 html 文件 project/templates/index.html

  • 增加 angular-route js 文件
  • 增加 ng-view 标签
<!DOCTYPE html>
<html  ng-app="myApp">
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="static/mylib/bootstrap/css/bootstrap.min.css">
<script type="text/javascript" src="static/mylib/angular/angular.min.js"></script>
<script type="text/javascript" src="static/mylib/angular/angular-route.min.js"></script>
<script type="text/javascript" src="static/js/controller.js"></script>
<script type="text/javascript" src="static/js/directives.js"></script>
</head>
<body>
<div class="container">
    <div ng-view></div>
</div>

<script type="text/javascript" src="static/mylib/jquery/jquery.min.js"></script>
<script type="text/javascript" src="static/mylib/bootstrap/js/bootstrap.min.js"></script>
</body>
</html>

2.3.2 修改 js 文件

编写 controller 文件 project/static/js/angular/controller.js

var app = angular.module('myApp', ['ngRoute']);

app.controller('RootCtrl', ['$scope', function($scope){
    $scope.title = "Home Page";
}]);
app.controller('CatsCtrl', ['$scope', function($scope){
    $scope.title = "Cats Page";
}]);

app.config(
    function($interpolateProvider) {
        $interpolateProvider.startSymbol('[[');
        $interpolateProvider.endSymbol(']]');
});
app.config(['$httpProvider', function($httpProvider) {
        $httpProvider.defaults.xsrfCookieName = 'csrftoken';
        $httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';
}]);
app.config(['$routeProvider', function($routeProvider){
    $routeProvider
        .when('/main', {
            controller : 'RootCtrl',
            template : '<h1>xxxxxxxxxxxxxx[[title]]</h1>'
        })
        .when('/cats', {
            controller : 'CatsCtrl',
            template : '<h1>kkkkkkkkkkkkkkkkk[[title]]</h1>'
        })
        .otherwise({
            redirectTo : '/main'
        });
}]);

2.3.3 查看运行效果

#python manage.py runserver 0.0.0.0:8888

浏览器访问 http://IP:8888/#!/main 查看运行效果,同时可以切换至http://IP:8888/#!/cats查看其他视图

2.4 routeProvider 使用 templateUrl 进行多视图

2.4.1 routeProvider 配置 templateUrl 原理

【2018 年 1 月 4 日】

根据 django 的 STATIC_URL 设置进行配置多视图 html

如:
比如我的一个 html 文件的本地地址为 /home/mysite/common_static/partials/main.html
Django 中的设置如:STATIC_URL = '/static/'

浏览器上输入: http://192.168.1.2:8000/static/partials/main.html 那么就相当与访问 /home/mysite/common_static/partials/main.html

故而:在 2.3 的基础上,将 template 修改为 templateUrl 同时配置对应的 html 文件位置即可,即 'static/partials/main.html'

2.4.1 routeProvider 配置 templateUrl 原理

【2018 年 1 月 4 日】

根据 django 的 STATIC_URL 设置进行配置多视图 html

如:
比如我的一个 html 文件的本地地址为 /home/mysite/common_static/partials/main.html
Django 中的设置如:STATIC_URL = '/static/'

浏览器上输入: http://192.168.1.2:8000/static/partials/main.html 那么就相当与访问 /home/mysite/common_static/partials/main.html

故而:在 2.3 的基础上,将 template 修改为 templateUrl 同时配置对应的 html 文件位置即可,即 'static/partials/main.html'

2.5 AngularJS 指令实现导航菜单与主页面分离同时实现切换功能

2.5.1 新增指令 navbar

这个指令是导航栏

编写指令文件 project/static/js/angular/directives.js

var directives = angular.module('cloudview.directives', []);
directives.directive('navbar', function(){
    return {
        restrict: 'A',
        transclude: true,
        scope: {},
        template: '<div class="navbar navbar-inverse navbar-fixed-top">\
                <div class="container">\
                    <a class="navbar-brand" href="#!/main">CloudView</a>\
                    <div class="navbar-collapse collapse">\
                        <ul class="nav navbar-nav">\
                            <li ng-class="{ active:\'main\'== $root.currentItem }"><a href="#!/main">首页</a></li>\
                            <li ng-class="{ active:\'service\'== $root.currentItem }"><a href="#!/service">服务管理</a></li>\
                            <li ng-class="{ active:\'utils\'== $root.currentItem }"><a href="#!/utils">系统工具</a></li>\
                        </ul>\
                        <ul class="nav navbar-nav navbar-right">\
                            <li ng-class="{ active:\'setting\'== $root.currentItem }"><a href="#!/setting">设置</a></li>\
                            <li class="divider-vertical"></li>\
                            <li ng-class="{ active:\'setting\'== $root.currentItem }"><a href="#!/logout">退出</a></li>\
                        </ul>\
                    </div>\
                </div>\
            </div>',
        replace: true
    };
});

html 中使用此指令

<div navbar ></div>

导航栏使用 logo

<div class="navbar-header">
    <a class="navbar-brand" href="#">
        <img alt="Brand" style="max-width:100px;margin-top:-7px;" src="...">
    </a>
</div>

解决悬浮层(悬浮 header、footer)会遮挡住内容的方法

导航栏使用 navbar-fixed-top 悬浮在最上层并置顶时,会发现导航栏会遮盖页面上面的部分

可以使用如下方法:(修改 templates/index.html)增加 style="margin-top:50px;"

<body>
<div class="container" style="margin-top:50px;">
	<div ng-view></div>
</div>
</body>

50px 为 navbar 的默认高度

2.5.2 实现导航菜单点击切换选中时高亮状态

通过 controller 中的 $rootScope.currentItem 与 特定菜单进行比较,以确定此菜单状态

tscope 设置的变量在所有 controller 里面都是可以直接用{{$root. 变量名}}来显示的,当然也可以赋值给 $scope.

3 注意

django 模板默认使用的是{{}},AngularJS 默认也是{{}},两者冲突了,代码里 app.config 将 AngularJS 规则改为 [[]],解决了冲突

4 angualr js 笔记

4.1 基础

ng-app 指令定义一个 AngularJS 应用程序。
ng-model 指令把元素值(比如输入域的值)绑定到应用程序。
ng-bind 指令把应用程序数据绑定到 HTML 视图。

AngularJS 应用组成如下:

  • View(视图), 即 HTML。
  • Model(模型), 当前视图中可用的数据。
  • Controller(控制器), 即 JavaScript 函数,可以添加或修改属性。

scope 是模型。scope 是一个 JavaScript 对象,带有属性和方法,这些属性和方法可以在视图和控制器中使用。

4.2 多视图

用 routeProvider 将视图分解成布局和模板视图,并且根据用户当前访问的 URL 来展示对应的视图。

从 1.2 版本开始,AngularJS 将 ngRoutes 从核心代码中剥离出来成为独立的模块。我们需要安装并引用它,才能够在 AngularJS 应用中正常地使用路由功能
  • angular-route.js。
$routeProvider.when(url,{
    template:string, // 在 ng-view 中插入简单的 html 内容
    templateUrl:string, // 在 ng-view 中插入 html 模版文件
    controller:string,function / array, // 在当前模版上执行的 controller 函数
    controllerAs:string, // 为 controller 指定别名
    redirectTo:string,function, // 重定向的地址
    resolve:object<key,function> // 指定当前 controller 所依赖的其他模块
});

4.3 调试

console.log('click');
$log.log('value=='+$scope.mob);
$log.info('value=='+$scope.mob);
$log.warn('value=='+$scope.mob);
$log.error('value=='+$scope.mob);
$log.debug('value=='+$scope.mob);

4.4 变量

4.4.1 location

url = http://qiaole.sinaapp.com?#name=cccccc

$location.absUrl();
// http://qiaole.sinaapp.com?#name=cccccc

$location.host();
// qiaole.sinaapp.com

$location.port();
// 80

$location.protocol();
// http

$location.url();
// ?#name=cccccc

// 获取 url 参数
$location.search().name;
// or
$location.search()['name'];

4.4.2 resource

不同的方式通过 resource 获取数据

html

<div ng-app="app">
  <div ng-controller="PromiseCtrl">
      <h2>$resource().get()</h2>
      <h3>Example 1 : The data directly returned by $resource().get()</h3>
      <p>{{example1}}</p>
      <h3>Example 2 : Success callback with $promise and then()</h3>
      <p>{{example2}}</p>
      <h3>Example 3 : Error callback with $promise and then()</h3>
      <p>{{example3}}</p>
      <h3>Example 4 : Success callback inside the get()</h3>
      <p>{{example4}}</p>
      <h3>Example 5 : Error callback inside the get()</h3>
      <p>{{example5}}</p>
  </div>
</div>

js

angular.module('app', [ 'ngResource' ]).controller('PromiseCtrl', [ '$scope', '$resource', function($scope, $resource) {
    var resource = $resource('/echo/json/:fakeOptionalParameter');

    $scope.example1 = resource.get();

    resource.get().$promise.then(function(value) {
        $scope.example2 = value;
    });

    resource.get({
        fakeOptionalParameter : '/error'
    }).$promise.then(null, function(value) {
        $scope.example3 = value.status;
    });

    resource.get(function(value) {
        $scope.example4 = value;
    });

    resource.get({
        fakeOptionalParameter : '/error'
    }, function(value) {
    }, function(httpResponse) {
        $scope.example5 = httpResponse.status;
    });
} ]);

输出

$resource().get()
Example 1 : The data directly returned by $resource().get()
{}

Example 2 : Success callback with $promise and then()
{}

Example 3 : Error callback with $promise and then()
404

Example 4 : Success callback inside the get()
{}

Example 5 : Error callback inside the get()
404

4.5 tab 页与 get 参数

bootstrap 使用 data-* 属性切换标签页

bootstrap 的标签页切换可以通过以下链接进行查看

https://github.com/meetbill/pine/wiki/bootstrap_learn

bootstrap 的标签页:

  • 优点:编写简单
  • 缺点:无法通过特定 url 在页面上展示对应的 tab 页面

标签页与 url 参数联动

controller.js 的对应 controller 中增加如下信息,其中

  • location.search() 可以获取到 url 参数信息
   $scope.sec = $location.search().sec
    if ($scope.sec == null) {
        $scope.sec = 'config'
        $location.search("sec","config")
    }
    $scope.change_sec=function (sec) {
        $location.search("sec",sec)
    };
    console.log($scope.sec);

标签页处代码如下,这样就可以根据获取到的参数信息默认高亮某个 tab,以及进行点击切换时进行更新 URL 参数

    <ul class="nav nav-tabs">
        <li ng-class="{active: sec  == 'config'}" ><a  ng-click="change_sec('config')" data-toggle="tab" data-target="#config">配置检查</a></li>
        <li ng-class="{active: sec  == 'status'}" ><a  ng-click="change_sec('status')" data-toggle="tab" data-target="#status">运行状态</a></li>
    </ul>

标签对应的内容如下:

<div class="tab-content">
        <div class="tab-pane" ng-class="{active: sec  == 'config'}" id="config">
            <h4>配置检查</h4>
        </div>
         <div class="tab-pane" ng-class="{active: sec  == 'status'}" id="status">
            <h4>运行状态</h4>
        </div>
</div>

5 常用指令

5.1 使用 ng-repeat-start 指令合并单元格

<!DOCTYPE html>
<html lang="en" ng-app="myapp">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script src="https://cdn.bootcss.com/angular.js/1.6.4/angular.min.js"></script>
</head>
<body>
    <table ng-controller="repeatController" border="1">
        <thead>
            <td>年级</td>
            <td>姓名</td>
            <td>年龄</td>
        </thead>
        <tbody>
            <tr ng-repeat-start="group in list">
                <td rowspan="{{group.item.length}}">{{group.nian}}</td>
                <td>{{group.item[0].name}}</td>
                <td>{{group.item[0].age}}</td>
            </tr>
            <tr ng-repeat-end ng-repeat="single in group.item" ng-hide="$first">
                <td>{{single.name}}</td>
                <td>{{single.age}}</td>
            </tr>
        </tbody>
    </table>


    <script>
        var data = [
            {
                "nian": "一年级",
                "item": [
                    {
                        "name": "张三",
                        "age": "23"
                    },
                    {
                        "name": "张三",
                        "age": "23"
                    }
                ]
            },
            {
                "nian": "二年级",
                "item": [
                    {
                        "name": "张三",
                        "age": "23"
                    },
                    {
                        "name": "张三",
                        "age": "23"
                    }
                ]
            },
            {
                "nian": "三年级",
                "item": [
                    {
                        "name": "张三",
                        "age": "23"
                    },
                    {
                        "name": "张三",
                        "age": "23"
                    }
                ]
            }
        ];
        repeatController = function ($scope){
            $scope.list = data;
        }
        repeatController.$inject = ['$scope'];
        angular.module('myapp',[]).controller('repeatController',repeatController);
    </script>
</body>
</html>

其中 $first 是去掉循环中的第一个元素,因为上面已经有了第一个元素了,不设置此项将会排版错误和第一个元素显示两行

5.2 AngularJS 设置 img (ng-src 和 src 区别)

AngularJS 使用 ng-src 替换了 src

<img ng-src="{{imageUrl}}">

错误写法

<img src="http://www.coderlady.com/avatar/{{hash}}"/>

正确写法

<img ng-src="http://www.coderlady.com/avatar/{{hash}}"/>

这是因为在加载页面的时候,在 Angular 加载完成之前,浏览器会试图从 http://www.coderlady.com/avatar/{{hash}} 加载图片,当然这会失败. 一旦 Angular 加载完成以后,浏览器就会明白{{hash}}变量需要被具体值代替,比如 logo.png. 然后就会到正确的 http://www.coderlady.com/avatar/logo.png 去加载图片。这显然就要执行两次操作。

ng-src 就解决了这个问题,因为它会等 Angular 加载完成以后,才会到正确的地址去加载数据。

PS:butterfly-fe 的右上角用户头像,就可以使用 ng-src 进行获取头像

6 常见问题

6.1 controller 不能写成全局

angularjs 1.2 和 1.3controller 写法不一样

1.2 controller 可以写成 function OrderListCtrl($scope){
$scope.xxx=ooo;

}

1.3 要这样写 ngApp.controller(“OrderListCrl”,function($scope){
$scope.xxx=ooo;

});

6.2 输出字典中的 key

在 html 展示的时候

"(key,value) in dict" 即可输出 key
"xxx in dict" 时,xxx 默认是 value

7 常见错误说明

  • [$injector:unpr] 注入错误
  • [$injector:modulerr] 模块注入错误
Clone this wiki locally