Giter Site home page Giter Site logo

angular-tutorial's Issues

SPA单页面

AngularJS路由允许我们通过不同的URL访问不同的内容
路由是此链接中的http://127.0.0.1/angular/view/route.html#/home这部分#/home
它的格式是url后面加上#/xxxx,通过**#+标记实现路由跳转,类似锚点
不能直接访问
home.html**,因为这是个模版文件
http://127.0.0.1/angular/view/home.html
所以通过AngularJS可以实现多视图的单页Web应用(single page web application,SPA)
image
1.创建路由
引入路由所需要的route.js文件

<script type="text/javascript" src="../js/angular.js"></script>
<script type="text/javascript" src="../js/angular-route.js"></script>

2.包含了ngRoute模块作为主应用模块的依赖模块
angular.module('wsscat',['ngRoute'])

3.使用 ngView 指令

该div 内的HTML内容会根据路由的变化而变化,就是在这个div页面里面实现局部刷新

4.配置$routeProvider,AngularJS$routeProvider用来定义路由规则

app.config(function($routeProvider) {
                //when方法
                $routeProvider.when('/home', {
                    //当路由更改为home的时候,显示home.html页面,并且该页面由homeCtrl控制
                    controller: 'homeCtrl',
                    templateUrl: 'home.html'
                }).when('/detail/:number', {
                    controller: 'detailCtrl',
                    templateUrl: 'detail1.html'
                }).when('/index', {
                    controller: 'indexCtrl'
                }).when('/add', {
                    controller: 'addCtrl',
                    templateUrl: 'add.html'
                })
            })

5.ng-repeat把数组或者数组对象渲染成复数标签

var studentData = [{
            id: 0,
            name: '张同学',
            date: new Date(),
            content:'在 Bootstrap 2 中,我们对框架中的某些关键部分增加了对移动设备友好的样式。而在 Bootstrap 3 中,我们重写了整个框架,使其一开始就是对移动设备友好的。这次不是简单的增加一些可选的针对移动设备的样式,而是直接融合进了框架的内核中。也就是说,Bootstrap 是移动设备优先的。针对移动设备的样式融合进了框架的每个角落,而不是增加一个额外的文件。',
        }, {
            id: 1,
            name: '晨同学',
            date: new Date(),
            content:'在移动设备浏览器上,通过为视口(viewport)设置 meta 属性为 user-scalable=no 可以禁用其缩放(zooming)功能。这样禁用缩放功能后,用户只能滚动屏幕,就能让你的网站看上去更像原生应用的感觉。注意,这种方式我们并不推荐所有网站使用,还是要看你自己的情况而定!',
        }, {
            id: 2,
            name: '李同学',
            date: new Date(),
            content:'Bootstrap 需要为页面内容和栅格系统包裹一个 .container 容器。我们提供了两个作此用处的类。注意,由于 padding 等属性的原因,这两种 容器类不能互相嵌套。',
        }]

把上面的内容用$scope绑定在需要数据的视图并所在的控制器内
$scope.studentData = studentData;
在页面中可以用ng-repeat渲染,ng-repeat不适宜渲染过多的DOM,会引发性能问题

<table class="table table-striped">
    <tr>
        <th>序号</th>
        <th>名字</th>
        <th>时间</th>
    </tr>
    <tr ng-repeat="stu in studentData">
        <td>{{stu.id}}</td>
        <td><a ng-href="#/detail/{{stu.id}}">{{stu.name}}</a></td>
        <td>{{stu.date}}</td>
    </tr>
</table>

6.路由之间的跳转
视图中我们可以这样实现跳转
<a class="btn btn-primary" ng-href="#/add">新增</a>
控制器中我们可以实现这样跳转
window.location.href="#/home";
还可以用angular的方法,但记得要注入$location这个服务
$location.path('home');

7.在控制器中加载我们需要的服务
$http是AngularJS应用中最常用的服务。服务向服务器发送请求,应用响应服务器传送过来的数据
用$http向后台请求数据,并把数据绑定到视图上
还有常用的两个异步服务$timeout$interval
当然还能自建服务,并在需要用到的控制器中注入
自建服务必须返回的是对象

app.service('intance',[function(){
                var obj = {};
                obj.addFunc = function(a,b){
                    return a+b;
                }
                obj['name'] = 'wsscat';
                return obj;
                //console.log("这是我的服务");
            }])

用服务提供的方法来对控制器的数据进行操作,或者在控制器之间交换数据

app.service('instance',[function(){
            return {};
        }])

$rootSccope适合在中小型SPA应用中使用,大型应用交换数据,可以用service服务

app.controller('homeCtrl', ['$scope', '$rootScope', 'instance', function($scope, $rootScope, instance) {
            //利用$rootScope交换数据
            $rootScope.exchange = '123';
                        //利用服务交换数据
            instance.name = '123';
            console.log(instance);
        }])
app.controller('detailCtrl', ['$scope', '$rootScope','instance', function($scope, $rootScope, instance) {
            console.log($rootScope.exchange);
            console.log(instance.name);
        }])

8.路由传参数
让**#/detail/:number**路由带参数

app.config(function($routeProvider) {
                //when方法
                $routeProvider.when('/home', {
                    controller: 'homeCtrl',
                    templateUrl: 'home1.html'
                }).when('/detail/:number', {
                    controller: 'detailCtrl',
                    templateUrl: 'detail1.html'
            })

路由之间传递参数
在控制器中利用routeParams服务来读取这个数据

app.controller('detailCtrl', ['$scope', '$rootScope', '$routeParams', function($scope, $rootScope, $routeParams) {
            console.log($routeParams.number);
}])

angular4

安装

基于 Angular Quickstart,使用 Git 克隆 quickstart 项目,安装项目所需依赖并验证环境是否搭建成功

git clone https://github.com/angular/quickstart ng4-quickstart
cd quickstart ng4-quickstart
npm i
npm start

定义组件

在app文件夹里面新建components文件夹,在里面新建user.component.ts

image

import { Component } from '@angular/core';
@Component({
    selector: 'sl-user',
    template: `
    <h2>大家好,我是{{name}}</h2>
    <p>我来自<strong>{{address.province}}</strong>省,
      <strong>{{address.city}}</strong>市
    </p>
    `
})
export class UserComponent {
    /*name = 'Semlinker';
    address = {
        province: '广东',
        city: '广州'
    };*/
    //支持构造函数的形式初始化数据
    name: string;
    address: any;
    constructor() {
        this.name = 'Wscats';
        this.address = {
            province: '广东',
            city: '广州'
        }
    }
}

声明组件

import { NgModule }      from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent }  from './app.component';
//引入刚才新建的user.component文件
import { UserComponent  }  from './components/user.component';
@NgModule({
  imports:      [ BrowserModule ],
  //并在数组中注入UserComponent  
  declarations: [ AppComponent , UserComponent ],
  bootstrap:    [ AppComponent ]
})
export class AppModule { }

使用组件

app.component.ts文件里面的template模板中添加<sl-user></sl-user>组件

import { Component } from '@angular/core';
@Component({
	selector: 'my-app',
	template: `
		<h1>Hello {{name}} Wscats</h1>
		<sl-user></sl-user>
	`,
})
export class AppComponent {
	name = 'Angular';
}

接口

定义接口来判断对象的类型

import { Component } from '@angular/core';
//boolean string[] boolean string类型等
//必须写在@Component前面
interface Author {
	name: string;
	age: number;
}
@Component({
	selector: 'ws-list',
	template: `
    <ul>
    	<li *ngFor="let p of people;">{{p}}</li>
    </ul>
    <p>{{author.name}}<p>
    `
})
export class UserComponent {
	author: Author
	constructor() {
		this.author = {
			name: "Corrine",
			age 666
		}
		this.people = ["wscats", "oaoafly", "corrine"]
	}
}

表达式

可以使用{{}}插值语法实现数据绑定

绑定普通文本

import { Component } from '@angular/core';
@Component({
  selector: 'my-app',
  template: `<h1>Hello {{name}}</h1>`,
})
export class AppComponent  {
  name = 'Angular'; 
}

绑定对象属性

import { Component } from '@angular/core';
@Component({
	selector: 'sl-user',
	template: `
    <h2>大家好,我是{{name}}</h2>
    <p>我来自<strong>{{address.province}}</strong>省,
      <strong>{{address.city}}</strong>市
    </p>
    `
})
export class UserComponent {
	/*name = 'Semlinker';
	address = {
	    province: '广东',
	    city: '广州'
	};*/
	name: string;
	address: any;
	constructor() {
		this.name = 'Wscats';
		this.address = {
			province: '广东',
			city: '广州'
		}
	}
}

管道/过滤器

可以使用Angular内置的json管道,来显示对象信息

@Component({
  selector: 'my-app',
  template: `
    ...
    <p>{{address | json}}</p>
  `,
})
export class AppComponent {
  name = 'Wscats';
  address = {
    province: '广东',
    city: '广州'
  }
}

常用指令

在Angular实际项目中,最常用的指令是ngIfngFor指令

ngFor

语法:

<li *ngFor="let item of items;">...</li>

该指令用于基于可迭代对象中的每一项创建相应的模板,它与AngularJS 1.x中的ng-repeat指令的功能是等价的

import { Component } from '@angular/core';
@Component({
	selector: 'ws-list',
	template: `
    <ul>
    	<li *ngFor="let p of people">{{p}}</li>
    </ul>
    `
})
export class UserComponent {
	constructor() {
		this.people = ["wscats","oaoafly","corrine"]
	}
}

ngIf

语法:

//接受布尔值
<div *ngIf="condition">...</div>

该指令用于根据表达式的值,动态控制模板内容的显示与隐藏,它与AngularJS 1.x中的ng-if指令的功能是等价的

import { Component } from '@angular/core';
@Component({
	selector: 'ws-list',
	template: `
    <ul *ngIf = "isShowList">
    	<li *ngFor="let p of people;">
    		<div *ngIf = "p.isShow">{{p.name}}</div>
    	</li>
    </ul>
    `
})
export class UserComponent {
	constructor() {
		this.isShowList = true;
		this.people = [{
			name: "Wscats",
			isShow: true
		}, {
			name: "Oaoafly",
			isShow: false
		}, {
			name: "Corrine",
			isShow: true
		}];
	}
}

ngClass

语法

[ngClass]="{'类名':boolean值}"

第一个参数为类名称,第二个参数为boolean值,如果为true就添加第一个参数的类,示例组件如下

import { Component } from '@angular/core';
@Component({
	selector: 'header-cp',
	template: `
     <h1 [ngClass]="{'red':bool}">header</h1>
     <button (click)="testClick()">OK</button>
     `,
	styles: [`
     	.red{
     		color: red
     	}
     `]
})
export class HeaderComponent {
	bool: boolean = true;
	testClick() {
		this.bool = !this.bool;
	}
}

ngStyle

语法

[ngStyle]="{'css属性名':'css属性值'}"

注意驼峰和非驼峰写法均有效果

import { Component } from '@angular/core';
@Component({
	selector: 'header-cp',
	template: `
     //驼峰和非驼峰写法均可
     <p [ngStyle]="{'backgroundColor':'green'}">header</p>
     <p [ngStyle]="{'background-color':'green'}">header</p>
     `
})
export class HeaderComponent {}

由于ngShow指令已经移除,所以我们可以用它来实现ngShow指令,就像下面代码一样

[ngStyle]="{'display': bool?'block':'none'}"

ngSwitch

语法

[ngSwitch]="变量"
     *ngSwitchCase="固值1"
     *ngSwitchCase="固值2"
     *ngSwitchDefault

ngSwitch用于多个条件分支的情况,配合ngSwitchCasengSwitchDefault两个指令实现不同的视图切换

<div class="container" [ngSwitch]="myVar">
     <div *ngSwitchCase="'A'">Var is A</div>
     <div *ngSwitchCase="'B'">Var is B</div>
     <div *ngSwitchCase="'C'">Var is C</div>
     <div *ngSwitchDefault>Var is something else</div>
</div>

ngNonBindable

有时候我们需要不要绑定页面的某个部分,使用了ngNonBindable,花括号就会被当做字符串一起显示出来

<div ngNonBindable>
      {{这里的内容不会被绑定}}
</div>

innerHTML

输出html结构,比如配合富文本编辑器使用使用,这个指令会非常有用,但也需要注意有可能会遭受XSS攻击

import { Component } from '@angular/core';
//输出html结构必须引入DomSanitizer模块
import { DomSanitizer } from '@angular/platform-browser';
@Component({
	selector: 'header-cp',
	template: `
	<div [innerHTML]="html" ></div>
     `,
})
export class HeaderComponent {
	html: any;
	constructor(private sanitizer: DomSanitizer) {
                //如果不用DomSanitizer来转换,会出现警告,并且html结构不会完整显示
		this.html = this.sanitizer.bypassSecurityTrustHtml("<p>要进行<span style='color: red'>转换的内容</span>~</p>");
	}
}

ngModel

必须在app.module.ts文件中引入FormsModule 模块,然后就可以在组件中使用ngModel指令

import { NgModule }      from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
// 使用ngModel必须引入FormsModule模块
import { FormsModule } from '@angular/forms';

import { AppComponent }  from './app.component';

@NgModule({
  // 注入FormsModule
  imports:      [ BrowserModule, FormsModule ],
  declarations: [ AppComponent ],
  bootstrap:    [ AppComponent ]
})
export class AppModule { }

组件中就可以使用ngModel进行数据绑定,记得一定要写上name属性,不然不会生效

import { Component } from '@angular/core';
@Component({
  selector: 'my-app',
  template: `
    <p>{{num}}</p>
    <!---双向数据绑定->
    <input name="num" type="number" [(ngModel)]="num" />
    <!---单向数据绑定->
    <input name="num" type="number" [ngModel]="num" />
    <button (click)="ok()">ok</button>
  `,
})
export class AppComponent  {
  num = 1;
  ok(){
    this.num++
    console.log("ok")
  }
}

事件绑定

可以通过(eventName)的语法,实现事件绑定
语法:

<date-picker (dateChanged)="statement()"></date-picker>
//等价于
<date-picker on-dateChanged="statement()"></date-picker>

下面我们就可以在页面上的按钮中绑定一个on-click事件

import { Component } from '@angular/core';
@Component({
	selector: 'ws-event',
	template: `
	    <button (click)="toggleSkills()">
	        {{ showSkills ? "隐藏技能" : "显示技能" }}
	    </button>
    `
})
export class EventComponent {
	toggleSkills() {
		this.showSkills = !this.showSkills;
	}
}

Http模块

1.打开app.module.ts文件,从@angular/http模块中导入 Http 类,并在imports数组中注入HttpModule

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpModule } from '@angular/http';

import { AppComponent } from './app.component';
import { UserComponent } from './components/user.component';
import { EventComponent } from './components/event.component';

@NgModule({
	imports: [BrowserModule,HttpModule],
	declarations: [AppComponent, UserComponent, EventComponent],
	bootstrap: [AppComponent]
})
export class AppModule {}

2.导入RxJS中的map操作符
3.使用DI方式注入http服务
4.调用http服务的get()方法,设置请求地址并发送HTTP请求
5.调用Response对象的json()方法,把响应体转成JSON对象
6.把请求的结果,赋值给对应的属性

import { Component } from '@angular/core';
import { Http } from '@angular/http'; // (1)步骤1
import 'rxjs/add/operator/map'; // (2)步骤2 导入RxJS中的map操作符
@Component({
	selector: 'ws-event',
	template: ` `
})
export class EventComponent {
	constructor(private http: Http) {} //(3)步骤3
	ngOnInit() {
		console.log(this);
		this.http.get(`https://api.github.com/orgs/angular/members?page=1&per_page=5`) // (4)
			.map(res => res.json()) // (5)
			.subscribe(data => {
				if(data) this.members = data; // (6)
			});
	}
}
}

服务

可以再app文件夹下面新建个service文件夹再创建data.service.ts,定义服务文件

export class DataService {
  getData() {
    return ['wscat', 'corrine', 'oaoafly'];
  }
}

在app.module.ts文件里面的providers数组中注入DataService

import { NgModule }      from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent }  from './app.component';
import { UserComponent }  from './user.component';
//引入服务
import { DataService } from './service/data.service';
@NgModule({
  imports:      [ BrowserModule ],
  declarations: [ AppComponent , UserComponent ],
  // 全局注入
  providers:    [ DataService ],
  bootstrap:    [ AppComponent ]
})
export class AppModule { }

加载data.service.ts文件,引入DataService服务,在constructor里面注入DataService服务,注意是private类型,并把方法命名为dataService在ng的ngOnInit生命周期内即可调用

import { Component } from '@angular/core';
import { DataService } from './service/data.service';
@Component({
  selector: 'wscats',
  template: `
    <h1>Hello {{name}}</h1>
  `,
})
export class UserComponent implements OnInit {
  constructor(private dataService: DataService) { }
  name = 'Angular';
  // 生命周期
  ngOnInit() {
    console.log("父组件ngOninit");
    console.log(this.dataService.getData())
    setTimeout(()=>{
      this.name = "abc"
    },1000)
  }
}

基于服务之间的组件通信

创建data.service.ts服务,并且在主模块中注入,里面的state默认为1

export class DataService {
  state:number;
  constructor(){
    this.state = 1
  }
  getData() {
    return ['wscat', 'corrine', 'oaoafly'];
  }
}

父组件,触发DataService服务中state的改变

import { Component } from '@angular/core';
import { DataService } from '../../services/data.service';
@Component({
  selector: ' wscats-cp',
  template: `
     <!--子组件接受服务的改变-->
     <test-cp></test-cp>
     `
})
export class WscatsComponent {
  constructor(private dataService: DataService) {
    //父组件利用定时器去改变dataService服务中的的state值
    setInterval(() => {
	this.dataService.state++
	console.log(this.dataService)
    }, 1000)
  }
}

子组件,监听DataService中state的变化并进行渲染

import { Component } from '@angular/core';
import { DataService } from '../../services/data.service';

@Component({
	selector: 'test-cp',
	template: `
                 <!--这里就会观察到dataService的动态改变,从而完成父子之间的通信-->
		 <p>{{dataService.state}}</p>
        `
})
export class TestComponent {
        //接受dataService并把它交给TestComponent的私有变量dataService
	constructor(private dataService: DataService) {
	}
}

路由

需要引入@angular/router模块,当然要先在npm包管理中心下载

import { RouterModule }   from '@angular/router';

路由器包含了多种服务RouterModule和多种指令RouterOutlet、RouterLink、RouterLinkActive
路由告诉路由器,当用户点击链接或者把URL粘贴到浏览器地址栏时,应该显示哪个视图,下面配置的意思为,当URL匹配到/home路由的时候,就在视图RouterOutlet上显示HomeComponent组件

...
import { RouterModule } from '@angular/router';
...
// 省略code
// 主模块
@NgModule({
  // 内置服务
  imports: [BrowserModule, RouterModule.forRoot([
    {
      path: 'home',
      component: HomeComponent
    }
  ])],
  // 注册组件
  declarations: [AppComponent, ...],
  // 自定义服务
  providers: [...],
  // 注根组件
  bootstrap: [AppComponent]
})
export class AppModule { }

我们可以在根组件里,放router-outlet组件,这个相当于我们AngularJS的router-view标签,正如下面代码一样

import { Component } from '@angular/core';

@Component({
  selector: 'my-app',
  template: `
    <router-outlet></router-outlet>
  `,
})
export class AppComponent  {}

当然我们还可以利用routerLink来进行路由的跳转

<a routerLink="/home">Heroes</a>

引入样式和脚本

局部

局部样式可以配合styleUrlsstyles进行引入

@Component({
	selector: 'xpannel',
	templateUrl: './app.pannel.html',
	styleUrls: ['./app.pannel.css'],
	styles: [require("weui")]
})

全局

全局样式可以在.angular-cli.json文件中引入,注意如果使用cnpm,引入带下划线_,带@符号[email protected]@weui才是真身,而非weui文件夹,那个是快捷方式,还有文件的路径是基于src文件的相对路径

"styles": [
        "styles.css",
        "../node_modules/[email protected]@weui/dist/style/weui.css"
],

举一反三,全局引入JS也可以在.angular-cli.json文件中的引入

"scripts": [],

参考文档

Angular 4.x 修仙之路
Angular之路--带你来搭建Webpack 2 + Angular 4项目

ng-repeat绑定事件和嵌套

ng-repeat绑定事件

下面的代码会根据你点击的数字变成红色,这里我们在ng-repeat渲染完成后绑定事件,注意一定是要DOM完全渲染后再去绑定,不然事件会绑定失败
重点就是加上在组件中加上这个DOM的完全渲染完成的判断

if (scope.$last) {                                  // 这个判断意味着最后一个元素渲染完成
       //scope.$eval(attr.chooseItem)    // 执行绑定的表达式
}

全部代码

<!DOCTYPE html>
<html ng-app="wsscat">
    <head>
        <meta charset="UTF-8">
        <title></title>
        <script src="../js/angular.js"></script>
        <!--<script src="zepto_1.1.3.js"></script>-->
    </head>
    <body ng-controller="indexCtrl">
        {{name}}
        <ul>
            <li choose-item ng-repeat="item in items">{{item}}</li>
        </ul>
    </body>
    <script>
        var app = angular.module('wsscat', []);
        app.controller('indexCtrl', function($scope) {
            $scope.name = "wsscat"
            $scope.items = ['1', '2', '3', '4', '5']
        })
        app.directive('chooseItem', function() {
            return {
                link: function(scope, ele, attr) {
                    if(scope.$last) {
                        scope.$eval(function() {
                            //如果引入jquery和zepto时候的写法
                            //$('li').bind('click', function() {
                            //$(this).toggleClass('choosed')
                            //console.log('toggleClass')
                            //})
                            console.log(ele)
                            angular.element(document.querySelectorAll('li')).bind('click', function() {
                                angular.element(this).toggleClass('choosed')
                            })
                        }())
                    }
                }
            }
        })
    </script>
    <style>
        .choosed {
            color: red;
        }
    </style>
</html>

ng-repeat嵌套

在ng-repeat中我们可以再嵌套一个ng-repeat
外层格式为ng-repeat="links in slides"
内层格式为ng-repeat="link in links track by $index"
注意要加上track by和索引值**$index**

<!DOCTYPE html>
<html ng-app="wsscat">
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <script src="../js/angular.js"></script>

    <body ng-controller="indexCtrl">
        {{name}}
        <div ng-repeat="links in slides">
            <hr/>
            <div ng-repeat="link in links track by $index">
                {{link}}
            </div>
        </div>
    </body>
    <script>
        var app = angular.module('wsscat', []);
        app.controller('indexCtrl', function($scope) {
            $scope.name = "wsscat";
            $scope.slides = [
                [1, 1, 1],
                [4, 5, 6],
            ];
        })
    </script>
</html>

ui-route和ng-route

ui路由

引入JS文件

开始引入angular和ui-route的js文件

<script type="text/javascript" src="angular.js" ></script>
<script type="text/javascript" src="angular-ui-router.js"></script>

与原生angular不同的是,ui路由用ui-view而不是ng-view
<div ui-view></div>
在angular服务中注入ui.router
var app = angular.module('wsscat', ['ui.router']);

配置路由

用到**$stateProvider**和**$urlRouterProvider**两个服务
/* 注入$stateProvider,$urlRouterProvider */
        app.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider) {
            /* 使用when来对一些不合法的路由进行重定向 */
            $urlRouterProvider.when('', '/main');
            /* 通过$stateProvider的state()函数来进行路由定义 */
            $stateProvider.state('main', {
                url: '/main',
                templateUrl: 'views/main.html',
                controller: 'mainCtrl'
            }).state('main.a', {
                url: '/pageMain1',
                templateUrl: 'views/pageMain1.html',
                controller: 'pageMain1Ctrl'
            })
        }]);

主路由,路由地址为_#/main_

app.controller('mainCtrl', function($scope) {
            $scope.name = 'wsscat';
        })

main路由下的子路由,路由地址为_#/main/pageMain1_

app.controller('pageMain1Ctrl',function($scope){
            $scope.name = 'abc'
        })

嵌套路由

此时我们就可以在main.html上放第二个ui-view这里比原生好的地方在于可以嵌套路由
main.html

main
{{name}}
<div ui-view></div>

pageMain1.html

456
{{name}}

这里写图片描述

路由传参

我们在生成一个新的子控制器

.state('main.b', {
                url: '/pageMain2/:id',
                templateUrl: 'views/pageMain2.html',
                controller: 'pageMain2Ctrl'
            })

留意我们在url定义的路由中多了个**:id**,这样我们就可以在控制器之间传递参数
url: '/pageMain2/:id'
这里写图片描述
在控制器中我们注入$state服务

app.controller('pageMain2Ctrl',function($scope,$state){
            $scope.name = 'cbd'
            console.log($state.params);
        })

用$state.params就可以访问到路由上的参数
例如我们输入#/main/pageMain2/1,就会返回一个对象Object {id: "1"}

一个视图多个ui-view

当一个视图拥有多个ui-view,例如下面这样,平时我们一般一个视图只有一个ui-view的情况

<div ui-view name="first"></div>
<div ui-view name="second"></div>

当拥有多个这样的ui-view我们就要加上name属性,并绑定它到路由配置中的views属性,让子视图决定渲染到哪一个ui-view里面

.state('main.a', {
                url: '/pageMain1',
                views: {
                    "first": {
                        templateUrl: 'views/pageMain1.html',
                        controller: 'pageMain1Ctrl'
                    }
                }
            }).state('main.b', {
                url: '/pageMain2/:id',
                views: {
                    "first": {
                        templateUrl: 'views/pageMain2.html',
                        controller: 'pageMain2Ctrl'
                    }
                }
            }).state('main.c', {
                url: '/pageMain3/:id',
                views: {
                    "second": {
                        templateUrl: 'views/pageMain3.html',
                        controller: 'pageMain3Ctrl'
                    }
                }
            })

引入多个angular.js时候,angular程序会出错

比如下面这行代码,实际上引入了两个angular.jsionic.js,这样会引发致命错误,Angular程序只能引入一个angular.js,因为ionic.bundle.js本身就包含了angular.jsionic.js

<script type="text/javascript" src="js/angular.js"></script>
<script type="text/javascript" src="js/ionic.min.js"></script>
<script src="js/ionic.bundle.js"></script>

导致ng-repeat失效

<p ng-repeat="m in music"></p>

ng-options&&ng-switch

1.ng-options接受一个对象数组

$scope.options = [{
                id:'a',
                name: '表达式'
            }, {
                id:'b',
                name: '指令'
            }, {
                id:'c',
                name: '作用域'
            }];

然后进行转换
option.id as option.name for option in options
格式为option标签的value值 as option内容 for 数组索引项 in 控制器作用域绑定的数组
源码如下:

<!DOCTYPE html>
<html ng-app="wsscat">
    <head>
        <meta charset="utf-8">
        <script src="../js/angular.js"></script>
    </head>

    <body ng-controller="baseCtrl">
        Angular
        <select ng-model="myWsscat" ng-options="option.id as option.name for option in options">
            <option value="">控制器</option>
        </select>
        <hr>
        <div ng-switch="myWsscat">
            <div ng-switch-when="a">
                <div ng-include="'a.html'"></div>
            </div>
            <div ng-switch-when="b" ng-controller="bCtrl">
                <h1>{{name}}</h1>
                <p>AngularJS 通过被称为 指令 的新属性来扩展 HTML。 AngularJS 通过内置的指令来为应用添加功能。 AngularJS 允许你自定义指令。 AngularJS 指令 AngularJS 指令是扩展的 HTML 属性,带有前缀 ng-。 ng-app 指令初始化一个 AngularJS 应用程序。 ng-init 指令初始化应用程序数据。 ng-model 指令把元素值(比如输入域的值)绑定到应用程序。 完整的指令内容可以参阅 AngularJS 参考手册。</p>
            </div>
            <div ng-switch-when="c">
                <h1>AngularJS 作用域</h1>
                <p>Scope(作用域) 是应用在 HTML (视图) 和 JavaScript (控制器)之间的纽带。 Scope 是一个对象,有可用的方法和属性。 Scope 可应用在视图和控制器上。 如何使用 Scope 当你在 AngularJS 创建控制器时,你可以将 $scope 对象当作一个参数传递:</p>
            </div>
            <div ng-switch-default>
                <h1>AngularJS 控制器</h1>
                <p> AngularJS 控制器 控制 AngularJS 应用程序的数据。 AngularJS 控制器是常规的 JavaScript 对象。 AngularJS 控制器 AngularJS 应用程序被控制器控制。 ng-controller 指令定义了应用程序控制器。 控制器是 JavaScript 对象,由标准的 JavaScript 对象的构造函数 创建。</p>
            </div>
        </div>
        <hr>
        <p> AngularJS 事件 AngularJS 支持以下事件: ng-click ng-dbl-click ng-mousedown ng-mouseenter ng-mouseleave ng-mousemove ng-keydown ng-keyup ng-keypress ng-change
        </p>
    </body>
    <script>
        var app = angular.module('wsscat', []);
        app.controller('baseCtrl', function($scope) {
            $scope.options = [{
                id:'a',
                name: '表达式'
            }, {
                id:'b',
                name: '指令'
            }, {
                id:'c',
                name: '作用域'
            }];
        })
        app.controller('bCtrl',function($scope){
            $scope.name = 'AngularJS 指令';
        })
    </script>
</html>

2.ng-include
引用一个同域的文件
ng-include="'a.html'",注意文件外面有个单引号,少了会失效

<h1>AngularJS 表达式</h1>
<p>AngularJS 表达式写在双大括号内:{{ expression }}。 AngularJS 表达式把数据绑定到 HTML,这与 ng-bind 指令有异曲同工之妙。 AngularJS 将在表达式书写的位置"输出"数据。 AngularJS 表达式 很像 JavaScript 表达式:它们可以包含文字、运算符和变量。 实例 {{ 5 + 5 }} 或 {{ firstName + " " + lastName }}</p>

这里写图片描述

service demo

<!DOCTYPE html>
<html ng-app="wsscat">

    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0,user-scalable=no">
        <title></title>
    </head>
    <style>
        * {
            margin: 0;
            padding: 0;
        }

        canvas {
            width: 100%;
            height: 500px;
        }
    </style>

    <body>
        <div ng-controller="homeCtrl">
            <input ng-model="first" />
            <input ng-model="second" />
        </div>
        <div ng-controller="indexCtrl">
            <input ng-model="first" />
            <input ng-model="second" />
            <button ng-click="start()">start</button>
            <button ng-click="clear()">clear</button>
        </div>
    </body>
    <script src="angular.js"></script>
    <script type="text/javascript">
        var app = angular.module('wsscat', []);
        app.controller('homeCtrl', function($scope) {
            $scope.first = 20;
            $scope.second = 30;
            $scope.$watch('first', function(data) {
                console.log(data)
            })
        })
        app.controller('indexCtrl', function($scope, hh, $document, $http, $interval) {
            console.log(hh)
            $scope.start = function() {
                $scope.line = hh.m(0, 0, "indexCtrl");
                console.log($scope.line)
                    //$scope.line.lineTo(50, 60);
                $scope.line.lineWidth = 1;
                $scope.line.strokeStyle = 'red';
                $scope.line.stroke();
            }
            $scope.start();
            $scope.clear = function() {
                hh.c()
            }
            var offset = 5;
            $interval(function() {
                    $http.get('shullfe.php').success(function(data) {
                        offset += 5;
                        console.log($scope.line)
                        $scope.line.lineTo(offset, data);
                        $scope.line.lineWidth = 0.1;
                        $scope.line.strokeStyle = 'red';
                        $scope.line.stroke();
                    })

                }, 1000)
                //hh.e("indexCtrl")
                //console.log($document[0].querySelectorAll('[ng-controller=indexCtrl]'))
                //var canvasList = $document[0].querySelectorAll('[ng-controller=indexCtrl]');
                //var canvas = canvasList[0].getElementsByTagName("canvas");
                //console.log(canvas[0])
                //$scope.$watch('first', function(data) {
                //  console.log(data)
                //})
        })
        app.service('hh', function($document) {
            return {
                m: function(a, b, Ctrl) {
                    var can = this.e(Ctrl);
                    //var can = $document[0].getElementById('can');
                    var cans = can.getContext('2d');
                    cans.moveTo(a, b); //第一个起点
                    //cans.lineTo(c, d); //第二个点
                    //cans.lineTo(220, 60); //第三个点(以第二个点为起点)
                    cans.lineWidth = 1;
                    //当两条线条交汇时,创建圆形边角
                    cans.lineJoin = "round";
                    cans.strokeStyle = 'red';
                    //cans.stroke();
                    //返回cans,方便我们在控制器中画图
                    return cans;
                },
                //清除画布
                c: function() {
                    var can = $document[0].getElementById('can');
                    var cans = can.getContext('2d');
                    cans.clearRect(0, 0, 500, 500);
                },
                e: function(Ctrl) {
                    //获取对应控制器下的DOM结构
                    var canvasList = $document[0].querySelectorAll('[ng-controller=' + Ctrl + ']');
                    //在上面获取的DOM结构范围内生成一个canvas标签
                    var canvas = $document[0].createElement('canvas');
                    //配置canvas的id属性
                    canvas.id = Ctrl + 'Canvas';
                    //添加到该DOM结构下
                    canvasList[0].appendChild(canvas);
                    //canvas.width = 100;
                    //canvas.height = 500;
                    //var canvas = canvasList[0].getElementsByTagName("canvas");这个canvas跟上面的canvas是一样的
                    return canvas;
                }
            }
        })
    </script>

</html>

ng-touch

引入文件
anguar的单页面页面引入两个脚本,一个angular的框架,一个是触摸的库
<script type="text/javascript" src="dist/js/angular.js"></script>
<script type="text/javascript" src="dist/js/angular-touch.js"></script>

记得在这里引入ngTouch模块
var app = angular.module('wsscat', ['ngRoute','ngTouch']);

编写路由

.when('/touch', {
        controller: 'touchCtrl',
        templateUrl: 'view/touch.html'
})

还要在controller里面把注入$swipe服务,如果我们打印$swipe服务会发现里面只暴露了一个方法bind
这里写图片描述

touchCtrl控制器
执行$swipe服务的bind方法,bind方法可以传入三个参数
function(element, eventHandlers, pointerTypes)
第一个是获取的节点,可以是directive link方法中获取的element,也可以是原生JS选择器获取的节点,然后放进angular.element函数里面,第二参数是需要监听的触摸动作,总共四个startmoveendcancel,可以在他们对应的函数中获取对应滑动所在的坐标点

app.controller('touchCtrl', ['$scope', '$swipe', function($scope, $swipe) {
            console.log($swipe);
            var ele = angular.element(document.getElementById('trapezoid'));
            console.log(ele);
            $swipe.bind(ele, {
                'start': function(coords) {
                    startX = coords.x;
                    startY = coords.y;
                    console.log(coords);
                },
                'move': function(coords) {
                    //console.log(coords);
                    var delta = coords.x - startX;
                    if(delta < -300 && !locked) {
                        console.log('trun right');
                    } else if(delta > 300 && !locked) {
                        console.log('trun left');
                    }
                },
                'end': function(coords) {
                    console.log(coords);
                },
                'cancel': function(coords) {
                    console.log(coords);
                }
            });
        }])

touch视图
<div id="trapezoid"></div>

在控制器中可以有两个事件监听左右滑动(上下滑动却没有)

$scope.left = function(){
                console.log('wsscat is left');
            }
            $scope.right = function(){
                console.log('wsscat is right');
            }

<p ng-swipe-left="left()" ng-swipe-right="right()">尝试左右滑动</p>

angular下拉刷新

注意这里要固定列表的高度
在组件directive中,通过获取attr的属性值中的方法名
scope.$apply(attr.whenScrolled)可以执行when-scrolled="loadMore()"中的loadMore函数

<!DOCTYPE html>
<html ng-app="wsscat">

    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <script type="text/javascript" src="../js/angular.js"></script>
    <style type="text/css">
            li {
                /*height: 120px;*/
                border-bottom: 1px solid gray;
            }

            #fixed {
                height: 500px;
                overflow: auto;
            }
        </style>
    <body ng-controller="indexCtrl">
        <div id="fixed" when-scrolled="loadMore()">
            <ul>
                <li ng-repeat="item in items">{{item}}</li>
            </ul>
        </div>
    </body>
    <script>
        var app = angular.module('wsscat', []);
        app.controller('indexCtrl', function($scope) {
            $scope.items = ['wsscat number'];
            //产生随机数组
            for(var i=0;i<=50;i++){
                $scope.items.push(Math.random()*10);
            }
            console.log($scope.items);
            $scope.loadMore = function(){
                console.log('下拉刷新更多');
            }
        })
        app.directive('whenScrolled', function() {
            return function(scope, elm, attr) {
                //内层DIV的滚动加载
                var raw = elm[0];
                console.log(scope);
                console.log(elm);
                elm.bind('scroll', function() {
                    console.log(raw.scrollTop);   //翻滚距离顶部的距离  (一直变动)   
                    console.log(raw.offsetHeight);//未翻滚前列表的高度 (一直固定)
                    console.log(raw.scrollHeight);//列表的加载完的高度 (一直固定)
                    if(raw.scrollTop + raw.offsetHeight >= raw.scrollHeight) {
                        console.log(attr.whenScrolled);//log loadMore()
                        scope.$apply(attr.whenScrolled);//执行 loadMore函数
                    }
                });
            };
        });
    </script>
</html>

Angular中的MVC模型

简介

MVC是一种使用 MVC(Model View Controller 模型-视图-控制器)设计模式,该模型的理念也被许多框架所吸纳,比如,后端框架(Struts、Spring MVC等)、前端框架(Angular、Backbone等)。在学习angular的过程中,我在网上查找关于angular MVC介绍的文章很少,有些文章也没有很直白地为初学者指明angular MVC到底是啥样貌,因此,今天我们就来谈谈MVC模型在angular的形态。

为了介绍angular MVC模型,我建立一个最简单的例子。该例子的启动展示结果为:
image

下面我会逐一解释。

view

view指的是视图,在web前端工程中,view往往指的是HTML代码。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="css/bootstrap.css" type="text/css">
</head>
<body ng-app="app">

    <div class="col-md-4 col-md-offset-4" ng-controller="InputController">
        模型数据: <input type="text" class="text-primary" ng-model="book.title">
    </div>

    <script src="js/angular.js"></script>
    <script src="js/demo1.js"></script>
</body>
</html>

model

model指的是模型数据,在java后端开发中,我们常常使用java为业务数据单独建模,然而,在前端中,我们也可以为数据建立模型。比如,下面的代码片段。

var book = {
        title: "angular"
}

我们为书籍建立一个数据模型对象,为了简单,我只为book声明了一个属性。

controller

controller指的是控制器,它的作用是控制model与view之间的交互。

angular.module("app", ["InputModule"]);

angular.module("InputModule", [])
.controller("InputController", ["$scope", function ($scope) {
    var book = {
        title: "angular"
    }
    $scope.book = book;
}]);

在此例中,我将模型数据book定义在angular的controller控制器中。要想将模型中的数据传递给视图,angular规定依附在$scope上的数据才能传递给视图。
总结
接下来,我用图来描述一下angular中MVC 的关联。
image

在全局使用ng-app指令,我就不多介绍了。

  • 1、通过在div中添加属性ng-controller="InputController",并设置属性值,通过angular解析关联到相关的控制器。也只有该div元素及其子元素,才能有权限使用InputController中的$scope对象上的模型数据。
  • 2、ng-model="book.title",通过angular解析,关联到其所处控制器中的$scope对象。根据指令的不同,关联到$scope对象上的方式也不同。ng-model指令将$scope对象与view对象的值进行双向绑定,犹如java中将对象的引用传给了view对象。ng-bind指令则是将$scope对象与view对象进行单向绑定,犹如java中将对象的副本值传给view对象。

原文:带你初识Angular中MVC模型

ng-repeat嵌套

在ng-repeat中我们可以再嵌套一个ng-repeat
外层格式为ng-repeat="links in slides"
内层格式为ng-repeat="link in links track by $index"
注意要加上track by和索引值**$index**

<!DOCTYPE html>
<html ng-app="wsscat">
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <script src="../js/angular.js"></script>

    <body ng-controller="indexCtrl">
        {{name}}
        <div ng-repeat="links in slides">
            <hr/>
            <div ng-repeat="link in links track by $index">
                {{link}}
            </div>
        </div>
    </body>
    <script>
        var app = angular.module('wsscat', []);
        app.controller('indexCtrl', function($scope) {
            $scope.name = "wsscat";
            $scope.slides = [
                [1, 1, 1],
                [4, 5, 6],
            ];
        })
    </script>
</html>

Angular的post请求后台接受不了数据的解决方法

方案1

加上这个模块,这里改写了**$httpProvider**服务

angular.module('MyModule', [], function($httpProvider) {
	// Use x-www-form-urlencoded Content-Type
	$httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=utf-8';

	/**
	 * The workhorse; converts an object to x-www-form-urlencoded serialization.
	 * @param {Object} obj
	 * @return {String}
	 */
	var param = function(obj) {
		var query = '',
			name, value, fullSubName, subName, subValue, innerObj, i;

		for(name in obj) {
			value = obj[name];

			if(value instanceof Array) {
				for(i = 0; i < value.length; ++i) {
					subValue = value[i];
					fullSubName = name + '[' + i + ']';
					innerObj = {};
					innerObj[fullSubName] = subValue;
					query += param(innerObj) + '&';
				}
			} else if(value instanceof Object) {
				for(subName in value) {
					subValue = value[subName];
					fullSubName = name + '[' + subName + ']';
					innerObj = {};
					innerObj[fullSubName] = subValue;
					query += param(innerObj) + '&';
				}
			} else if(value !== undefined && value !== null)
				query += encodeURIComponent(name) + '=' + encodeURIComponent(value) + '&';
		}

		return query.length ? query.substr(0, query.length - 1) : query;
	};

	// Override $http service's default transformRequest
	$httpProvider.defaults.transformRequest = [function(data) {
		return angular.isObject(data) && String(data) !== '[object File]' ? param(data) : data;
	}];
});
var app = angular.module('wscat', ['MyModule']);
app.controller('loginCtrl', function($scope, $http) {
	$scope.name = 'wscat';
	$scope.submit = function() {
		$http.post('http://localhost/CI/myCi/index.php/login_api/login', {
			params: {
				username: $scope.username,
				password: $scope.password
			}
		}).success(function(data) {

		})
	}
})

更改前的数据格式为
image

更改过后数据格式为下图
image

我们就可以在后台获取数据了

public
    function login() {
    	$this -> load -> model('login_model');
        $data = array(
            'user_name' => $this->input->post('params')['username'],
            'password' => md5($this->input->post('params')['password'])
        );
        //or
        var_dump($_POST['params']);
    }

方案2

image

原因:可以发现传参方式是request payload,参数格式是json,而并非用的是form传参,所以在后台用接收form数据的方式接收参数就接收不到了

POST表单请求提交时,使用的Content-Typeapplication/x-www-form-urlencoded
而此处的Content-Type是:

image

解决:增添两段代码,代码如下;

$http({
	method: 'post',
	url: 'http://localhost:8081/search',
	data: {
		"page": page,
		"pageNum": pageNum
	},
	headers: { //1.设置类型
		'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8'
	},
	transformRequest: function(obj) { //2.处理传递参数的格式
		var str = [];
		for(var p in obj) {
			str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]))
		}
		return str.join('&')
	}
}).then(function(data) {

}, function(err) {

});

现在的谷歌监视为:
image

现在传参方式就变成form方式了,然后后端就可以正常接收参数了!

参考文档:Angular中的POST请求传递参数,服务端接收不到参数的解决方法

angular2

生成项目并添加组件

安装淘宝镜像

npm install -g cnpm --registry=https://registry.npm.taobao.org

image

安装angular2脚手架

cnpm install -g angular-cli@latest

image

这个命令为我们新建了一个名为hello-angular的工程

ng new hello-angular

image

生成一个hello-angular文件夹,进入文件夹

cd hello-angular

image
可以看到应用编译打包后server运行在4200端口

ng serve

image
打开浏览器输入 http://localhost:4200 即可看到效果

ng generate component wscat--inline-template --inline-style

image

wscat是我们的组件名称,后面的两个参数是告诉angular-cli生成组件时,请把组件的HTML模板和CSS样式和组件放在同一个文件中
Angular提倡的文件命名方式是这样的:

  • 组件名称.component.ts
  • 组件的HTML模板命名为: 组件名称.component.html
  • 组件的样式文件命名为: 组件名称.component.css

image

@component修饰配置中的selector: 'app-login',这意味着我们可以在其他组件的**template**中使用 `

打开hello-angular\src\app\app.component.html加入我们的组件

<h1>
  {{title}}
</h1>
<app-login></app-login>

编写组件添加事件

login.component.ts里面的模板中添加输入框和事件绑定

@Component({
  selector: 'app-login',
  template: `
    <p>
      login Works!
    </p>
    <input />
    <button (click)="test()">Ok</button>
  `,
  styles: []
})

**(click)**表示我们要处理这个button的click事件,圆括号是说发生此事件时,调用等号后面的表达式或函数
在下面代码中定义test事件

export class LoginComponent implements OnInit {
  constructor() { }
  ngOnInit() {
  }
  test(){
		console.log("123")
	}
}

如果一切无误当我们点击按钮的时候就会在控制台输出123结果
image

我们可以在文本输入框标签内加一个#usernameRef,这个叫引用(reference)

<input #usernameRef type="text" />
<button on-click="test(usernameRef.value)">Ok</button>
export class LoginComponent implements OnInit {
  constructor() { }
  ngOnInit() {
  } 
  test(data){
		console.log(data)
	}
}

当我们输入内容的时候再按触发点击事件,就可以获取视图输入框的数据

创建服务

image
在src\app下建立一个core的子文件夹(src\app\core),然后命令行中输入 ng g s core/auth(s这里是service的缩写,core/auth是说在core的目录下建立auth服务相关文件)。auth.service.tsauth.service.spec.ts这个两个文件应该已经出现在你的目录里了

我们可以定义一个简单的服务,如下面代码

import { Injectable } from '@angular/core';
@Injectable()
export class AuthService {
  constructor() { }
  loginWithCredentials(username: string, password: string){
    if(username === 'wscats'){
    	return true;
    }else{
    	return false;
    }
  }
}

路由

加载路由依赖,放在angular框架后面

<script type="text/javascript" src="../js/angular.js"></script>
<script type="text/javascript" src="../js/angular-route.js"></script>

$location.path

$routeProvider
两个核心方法when()otherwise()

  • controller //function或string类型。在当前模板上执行的controller函数,生成新的scope
  • controllerAs //string类型,为controller指定别名
  • template //string或function类型,视图所用的模板,这部分内容将被ngView引用
  • templateUrl //string或function类型,当视图模板为单独的html文件或是使用了<script type="text/ng-template">定义模板时使用
  • resolve //指定当前controller所依赖的其他模块
  • redirectTo //重定向的地址

directive组件化开发

<?php
    $ch = curl_init();
    $url = 'http://apis.baidu.com/jidichong/school_search/school_search?name=广东外语外贸大学&npage=1';
    $header = array(
        'apikey: 0aea38d1a7c4443f2f00adc86c4c3e72',
    );
    // 添加apikey到header
    curl_setopt($ch, CURLOPT_HTTPHEADER  , $header);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    // 执行HTTP请求
    curl_setopt($ch , CURLOPT_URL , $url);
    $res = curl_exec($ch);
    echo $res;
    //var_dump(json_decode($res));
?>

控制器

1.ng-src
ng-src指令里面需要{{}},其他ng指令一般只要直接写$scope所带的属性
<img ng-src="{{url}}" />

2.$rootScope
$rootScope可以实现控制器之间的数据交换,但是一旦刷新就会丢失

3.ng-style
ng-style指令,如果要用$scope传入一个css的样式表,要用json格式传递
ng-style="style"

$scope.style = {
        'border': '1px solid brown'
    };

4.ng-show
isexpand在ng-show里面不能带{{}},不然会认为永远字符串为真
<span ng-show="isexpand">...</span>
$scope.isexpand = true
当它<span ng-show="isexpand">...</span>"这样写时候为标签的属性
当它<span class="isexpand?ng-show:ng-hide">...</span>这样写的时候表现为css类

5.**ng-前缀的意思
不然DOM来解析,等到angular加载完才执行ng-自身指令
例如<img src="{{url}}" />,会先加载{{url}}地址的图片,报404错误,再等到angular解析才读取出图片
一般需用$scope把变量带到视图中的
src,href,style,class**等我们就带ng-前缀,如果不是的话,按原生写法即可

6.过滤器{{date| date:'yyyy-MM-dd hh:mm:ss EEEE'}}
date要传UNIX时间戳$scope.date = 1448864369815;

directive demo

angular组件写的轮播图
<swipe></swipe>标签进行复用
index.html

<!DOCTYPE html>
<html ng-app='wsscat'>
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>

    <body ng-controller="indexCtrl">
        {{text}}
        <swipe></swipe>
        <swipe></swipe>
    </body>
    <script src="angular.js"></script>
    <script>
        var app = angular.module('wsscat', []);
        app.controller('indexCtrl', function($scope) {
            $scope.text = "轮播图"
            $scope.images = ['denglu.png']
        })
        app.directive('swipe', function($interval) {
            return {
                templateUrl: 'template.html',
                link: function(scope, elm, attr) {
                    console.log(scope)
                    console.log(elm.find('li').length)
                    elm.addClass("red")
                    var curIndex = 0, //当前index
                    imgLen = elm.find('li').length;
                    var autoChange = setInterval(function() {
                        if(curIndex < imgLen - 1) {
                            curIndex++;
                        } else {
                            curIndex = 0;
                        }
                        //调用变换处理函数
                        changeTo(curIndex);
                    }, 2500);

                    function changeTo(num) {
                        var goLeft = num * 400;
                        elm.find('ul').css("left", "-" + goLeft + "px")
                        elm.find("li").removeClass("infoOn").eq(num).addClass("infoOn");
                        elm.find("li").removeClass("indexOn").eq(num).addClass("indexOn");
                    }
                }
            }
        })
    </script>
</html>

template.html

<div id="banner">
    <!-- 轮播部分 -->
    <ul class="imgList">
        <!-- 图片部分 -->
        <li>
            <a href="#"><img ng-src="{{images[0]}}"></a>
        </li>
        <li>
            <a href="#"><img ng-src="{{images[0]}}"></a>
        </li>
        <li>
            <a href="#"><img ng-src="{{images[0]}}"></a>
        </li>
        <li>
            <a href="#"><img ng-src="{{images[0]}}"></a>
        </li>
        <li>
            <a href="#"><img ng-src="{{images[0]}}"></a>
        </li>
    </ul>
</div>
<style type="text/css">
    body,
    div,
    ul,
    li,
    a,
    img {
        margin: 0;
        padding: 0;
    }

    ul,
    li {
        list-style: none;
    }

    a {
        text-decoration: none;
    }

    #wrapper {
        position: relative;
        margin: 30px auto;
        width: 400px;
        height: 200px;
    }

    #banner {
        position: relative;
        width: 400px;
        height: 200px;
        overflow: hidden;
    }

    .imgList {
        position: relative;
        width: 2000px;
        height: 200px;
        z-index: 10;
        overflow: hidden;
        transition: left 2.5s;
    }

    .imgList li {
        float: left;
        display: inline;
    }

    .imgList li a img{
        width: 400px;
        height: 200px
    }
</style>

ionic总结

移动端开发必备的一句话
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">

引入js文件和ionic的bundle文件,bundle文件里面包含了angular框架

<script type="text/javascript" src="js/ionic.bundle.js"></script>
<link rel="stylesheet" href="ionic.css" />

如果你只使用样式不使用组件的话,那就不用写var app = angular.module("wsscat",["ionic"]),相反用组件就一定要加上去

ion-content

设置一个可以滚动的内容区域

<ion-content>
    <p>我的第一个 ionic 应用。</p>
</ion-content>
配合固定的头部`<ion-header-bar>`,让内容框可以滚动可以这样写
`<ion-content class="content has-header ionic-pseudo">`
如果不让内容框滚动则这样写
`<div class="content has-header">`

下拉刷新

让ion-content拥有下拉刷新的滚动视图

<ion-refresher
    pulling-text="下拉刷新..."
    on-refresh="doRefresh()">
</ion-refresher>

ion-list

下拉刷新完后我们可以用ion-list

<ion-list>
    <ion-item ng-repeat="item in items">{{item}}</ion-item>
</ion-list>

ui-view与ion-nav-view

当我们以这种方式写路由的时候要,注意我们可以在ion-tabs里面使用<ion-nav-view>标签代替ui-route的<div ui-view=""></div>

.state('tabs.home', {
        url: "/home",
                //当一个页面有多个视图即ui-view或者ion-nav-view时候用views属性和视图的name配合指定
        views:{
            "home-tab":{templateUrl: "views/home.html",}
        }
                //相当于下面这张写法配合<div ui-view=""></div>
                //templateUrl: "views/home.html",
        //controller: 'HomeTabCtrl'
})
<ion-tabs class="tabs-icon-top tabs-positive">
    <ion-tab title="Home" icon="ion-home" href="#/tab/home">
        <ion-nav-view name="home-tab"></ion-nav-view>
                <!--<div ui-view=""></div>-->
    </ion-tab>
</ion-tabs>

其实本质是父容器的ui-view分不同几份ion-nav-view来写,ion-nav-view的区别用name来区分

ionic组件里面使用ng-model

如果要在ionic里面使用ng-model获取值,比如在,中获取<input ng-model="name" />name的值,就要在name前面加上$parent,<input ng-model="$parent.name" />这样控制器才能获取name值,因为ionic组件会在控制器的作用域下创建了一个子的作用域

过滤器

自定义过滤器

我们可以使用filter函数自定义一个过滤器,filter函数的第一个参数是过滤器到时候再DOM中要使用的名字,第二个参数是定义一个执行过滤操作的函数,返回的要是一个函数

app.filter("wsscat",function(){
            var func = function(input, bool){
                var out;
                console.log(input);
                console.log(bool);
            }
            return func;
})

我们就可以在DOM中使用这个过滤器,这里执行的时候会输出text的值,过滤器中的返回函数第一个参数就是我们传进去的text值,第二个参数是传递一个值,可以是布尔值,字符串,数字等等
<p>{{text|wsscat}}</p>
<p>{{text|wsscat:true}}</p>

所以打印的结果为

console.log(input);//text的值
console.log(bool);//true

在控制器中使用过滤器服务

往控制器中注入$filter服务
$filter(过滤器名字)(需要被过滤的参数,过滤器设置的参数)

app.controller('filterCtrl',function($scope,$filter){
            $scope.name = 'wsscat';
            //$filter第一个括号是过滤器的名字 第二个括号是接受过滤的参数和过滤器设置的参数
            $scope.price = $filter("currency")(123,'#');
            $scope.date = $filter("date")(new Date(),'yyyy-MM-dd hh:mm:ss');
})

控制器内单页切换

关键点在于ng-if的运用,利用布尔值判断页面是否显示,页面可以用ng-include包含外部页面,也可以一个页面内把两个切换页写完

然后可以用ng-class来切换样式
ng-class="{'blue':isOne}"
上面这句的意思是如果$scope.isOne = true;isOne为真的时候添加该样式,如果为假去除该样式

<!DOCTYPE html>
<html ng-app="wsscat">

    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <script type="text/javascript" src="angular.js"></script>

    <body ng-controller="homeCtrl">
        <button ng-click="toggle()">切换</button>
        <article>
            <section ng-click="show(1)" ng-class="{'blue':isOne}">左</section>
            <section ng-click="show(2)" ng-class="{'blue':isTwo}">右</section>
        </article>
        <div ng-if="tap.page1">第一页</div>
        <div ng-if="tap.page2">第二页</div>
    </body>
    <script>
        var app = angular.module('wsscat', []);
        app.controller('homeCtrl', ['$scope', function($scope) {
            $scope.name = 'yao';
            $scope.tap = {
                page1: true,
                page2: false
            }
            $scope.toggle = function() {
                //取反
                $scope.tap.page1 = !$scope.tap.page1;
                $scope.tap.page2 = !$scope.tap.page2;
            }
            $scope.lineBorder = true;
            $scope.show = function(page) {
                if(page==1){
                    //样式切换
                    $scope.isOne = true;
                    $scope.isTwo = false;
                    //页面切换
                    $scope.tap.page1 = true;
                    $scope.tap.page2 = false;
                }else{
                    $scope.isOne = false;
                    $scope.isTwo = true;
                    $scope.tap.page1 = false;
                    $scope.tap.page2 = true;
                }
            }
        }])
    </script>
    <style>
        article {
            display: flex;
        }

        article section {
            text-align: center;
            background-color: aquamarine;
            flex: 1;
        }
        /*下划线颜色*/

        .blue {
            color: #0c63ee;
            border-bottom: 2px solid #0c63ee;
        }
    </style>

</html>

下面这句取反来实现切换效果

$scope.toggle = function() {
                //取反
                $scope.tap.page1 = !$scope.tap.page1;
                $scope.tap.page2 = !$scope.tap.page2;
            }

$cacheFactory

$cacheFactory可以用来进行数据在controller之间传递

var cache = $cacheFactory('wsscat');
用**$cacheFactory**方法设置一个缓存,并赋给一个对象,该对象拥有下面的这些方法

  • put(key,value);
  • 在缓存对象中插入一个键值对(key,value)
  • get(key);
  • 在缓存对象中通过指定key获取对应的值
  • romove(key);
  • 在缓存对象中通过指定key删除对应的值
  • removeAll();
  • 删除缓存对象中所有的键值对
  • destroy();
  • 销毁这个缓存对象
  • info();
  • 获取缓存对象信息(id,size)

用**$cacheFactory**在控制器之间交换数据要注意的是,如果刷新页面,数据就不复存在,所以在做单页面应用时候,如果想在不同视图不同控制器之间交换数据,这种方法慎用

其实**$cacheFactory**在控制器交换数据等同于自定义一个服务,然后在自定义服务中交换数据

app.controller('pageMain1Ctrl', function($scope, $cacheFactory) {
            var cache = $cacheFactory('wsscat');
            cache.put('name', 'wsscat');
            cache.put('age', 0);
            var info = cache.info();
            console.log(info);
        })

app.controller('pageMain2Ctrl', function($scope, $state, $cacheFactory) {
            var cache = $cacheFactory.get('wsscat');
            var name = cache.get('name');
            console.log(name);
        })

这里写图片描述

表单认证

注意点
1.要让form.user.$error.required生效,必须在输入框加入H5的属性required
2.form.email.$dirty加了这句话可以让第一次进入页面的时候不提示用户名/邮箱是必须的,等有输入并输入框为空后再出现提醒
3.form表单的属性name="user"对应form.user中的form,input输入框的属性name="user"对应form.user中的user
4.<input type="submit" ng-disabled="form.user.$dirty && form.user.$invalid || form.email.$dirty && form.email.$invalid">表示有输入并且输入的名字是非法内容和有输入并且输入的邮箱是非法内容这两种情况只要满足其中一种就让按钮禁止使用

  • $dirty 表单有填写记录 也就是说表单在进入页面前是没有任何填写纪录的,一旦我们做来第一次输入之后,后面这个都判断为是有过填写记录
  • $valid 字段内容合法的
  • $invalid 字段内容是非法的 如果输入框为空那就属于非法的
  • $pristine 表单没有填写记录
<!DOCTYPE html>
<html ng-app="wsscat">
    <head>
        <meta charset="UTF-8">
        <title>wsscat表单认证</title>
    </head>
    <style>
        span {
            color: red;
        }
    </style>

    <body ng-controller="indexCtrl">
        <form name="form">
            <p>
                <input type="text" name="user" ng-model="user" required />
                <!--
                    $dirty      表单有填写记录   也就是说表单在进入页面前是没有任何填写纪录的,一旦我们做来第一次输入之后,后面这个都判断为是有过填写记录
                    $valid      字段内容合法的
                    $invalid        字段内容是非法的 如果输入框为空那就属于非法的
                    $pristine   表单没有填写记录
                -->

                <!--这里做了严谨的判断 第一个是让它进来的时候判断它是否已经输入过内容如果没输入就隐藏用户名必须这个红色输入框,第二个是判断非法字符-->
                <span ng-show="form.user.$dirty&&form.user.$invalid">
                    <span ng-show="form.user.$error.required">用户名是必须</span>
                </span>
            </p>
            <p>
                <input type="email" name="email" ng-model="email" required />
                <span ng-show="form.email.$dirty && form.email.$invalid">
                    <span ng-show="form.email.$error.required">邮箱是必须的</span>
                <span ng-show="form.email.$error.email">非法的邮箱地址</span>
                </span>
            </p>
            <p>
                <!--有输入并且输入的是非法内容,有输入并且输入的邮箱是非法内容-->
                <input type="submit" ng-disabled="form.user.$dirty && form.user.$invalid ||  
                form.email.$dirty && form.email.$invalid">
            </p>
        </form>
    </body>
    <script type="text/javascript" src="../js/angular.js"></script>
    <script>
        var app = angular.module('wsscat', []);
        app.controller('indexCtrl', function($scope) {})
    </script>
</html>

angular面试题

解释下什么是 $rootScrope 以及和 $scope 的区别
$rootScrope 页面所有 $scope 的父对象
Angular解析 ng-app 然后在内存中创建 $rootScope
带有ng-controller的div然后指向到某个controller函数。这个时候在这个controller函数中变有一个$scope对象实例

Angular Directive中restrict 中分别可以怎样设置
restrict中可以分别设置:

  • A 匹配属性
  • E 匹配标签
  • C 匹配class
  • M 匹配注释

ng-show/ng-hide与ng-if的区别
我们都知道ng-show/ng-hide实际上是通过 display 来进行隐藏和显示的。而ng-if实际上控制dom节点的增删除来实现的。因此如果我们是根据不同的条件来进行dom节点的加载确认的话,那么ng-if的性能好过ng-show

列出至少三种实现不同模块之间通信方式

  • Service
  • events,指定绑定的事件
  • 使用$rootScope

directive组件作用域

  • false,继承父作用域(默认值),父能影响子,子也能影响父;
  • true,继承父作用域,并且创建自己的作用域(子作用域),父能影响子,子不能影响父;
  • {},创建一个全新的隔离作用域,父子互不影响;
    这里写图片描述
<!DOCTYPE html>
<html ng-app="wsscat">

    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <script type="text/javascript" src="js/angular.js"></script>

    <body>
        <article ng-controller="indexCtrl">
            <p>父作用域:</p>
            <input ng-model="name" />
            <section>
                <p>组件作用域:</p>
                <wsscat></wsscat>
                <wsscat1></wsscat1>
                <wsscat2></wsscat2>
            </section>
        </article>
    </body>
    <script>
        var app = angular.module('wsscat', []);
        app.controller('indexCtrl', function($scope) {
            $scope.name = 'wsscat';
        })

        app.directive('wsscat', function() {
            return {
                restrict: "EAMC",
                template: "<p>双向数据绑定<br /><input ng-model='name' /></p>",
                scope: false
            }
        })
        app.directive('wsscat1', function() {
            return {
                restrict: "EAMC",
                template: "<p>父影响子,子不能影响父<br /><input ng-model='name' /></p>",
                scope: true
            }
        })
        app.directive('wsscat2', function() {
            return {
                restrict: "EAMC",
                template: "<p>互不影响<br /><input ng-model='name' /></p>",
                scope: {}
            }
        })
    </script>
    <style>
        article{
            border: 1px solid #009689;
        }
        section{
            border: 1px solid #22FFFF;
        }
    </style>
</html>

$broadcast,$emit and $on

发送事件可以用
向父控制器传递信息
$scope.$emit('name', 'args');
或者是
向子控制器传递信息
$scope.$broadcast('name', 'args');
name:事件的名字
args:事件所需要传递的参数
接受事件可以用(仅此一个方法可以接受事件)

接受来自于子或父传来的信息
$scope.$on('name',function(event,data){
//从$emit或者$broadcast中获取的args事件传递来的信息
})

例子如下
注意
bodyCtrl为indexCtrl的父
indexChildCtrl为indexCtrl的子

<!DOCTYPE html>
<html ng-app="wsscat">
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <script type="text/javascript" src="js/angular.js"></script>

    <body ng-controller="bodyCtrl">
        <article ng-controller="indexCtrl">
            {{name}}
            <button ng-click="click()">Ok</button>
            <section ng-controller="indexChildCtrl">
                <input ng-model="name" ng-change="changName()" />
                {{name}}
            </section>
        </article>

        <article ng-controller="indexBrotherCtrl">
            {{name}}
        </section>
        </article>
    </body>
    <script>
        var app = angular.module('wsscat', []);
        app.controller('bodyCtrl', function($scope) {
            $scope.$on('to-parent', function(event, data) {
                console.log('I am the parent, I got it', data);
            });
        })
        app.controller('indexCtrl', function($scope) {
            $scope.name = "wsscat";
            $scope.click = function() {
                //向下广播事件
                $scope.$broadcast('to-child', 'haha');
                //向上广播事件
                $scope.$emit('to-parent', 'hehe');
            }
            //子控制器indexChildCtrl改变名字后,向上发送to-parent-name事件委托告诉indexCtrl,$scope.name值已经发生改变,并一起作出改变
            $scope.$on('to-parent-name', function(event, data) {
                console.log('I am the parent to-parent-name, I got it', data);
                $scope.name = data;
            });
        })

        app.controller('indexChildCtrl', function($scope) {
            $scope.$on('to-child', function(event, data) {
                console.log('I am the child, I got it', data);
            });
            $scope.changName = function() {
                $scope.$emit('to-parent-name', $scope.name);
            }
        })

        app.controller('indexBrotherCtrl', function($scope,$rootScope) {
            $rootScope.$on('to-parent', function(event, data) {
                console.log('I am the parent from $rootScope, I got it', data);
                $scope.name = data;
            });
        })

        app.service("hiEventService", function($rootScope) {
            this.broadcast = function() {
                $rootScope.$broadcast("hi")
            }
            this.listen = function(callback) {
                $rootScope.$on("hi", callback)
            }
        })
    </script>
</html>

上面的结果,当我们按下按钮,indexCtrl分别向它的父于子进行消息传递,打印信息如下
这里写图片描述

angular运用jsonp

var http = require('http');
var fs = require('fs');
var url = require('url');
var querystring = require('querystring')
    //console.log(http);
http.createServer(function(request, response) {
    request.setEncoding('utf-8');
    //获取请求路径 比如index.html
    var pathname = url.parse(request.url).pathname;
    //获取请求参数 例如?callback=JSON_CALLBACK&name=yao
    var paramStr = url.parse(request.url).query;
    console.log(pathname);
    //将参数转化为json对象
    var param = querystring.parse(paramStr);
    console.log(param.callback);
    //发送 HTTP 头部 
    //HTTP 状态值: 200 : OK
    //内容类型: text/plain
    response.writeHead(200, {
        'Content-Type': 'text/jsonp'
    });
    var datas = {
        name: "wsscat",
        age: "99",
        sex: "cat",
        skill: ["html", "css", "js", "php"]
    };

    //发送响应数据
    //"angular.callbacks._0"才能正确执行&&JSON_CALLBACK不能正确执行
    //转化为jsonp的格式传递
    response.end(param.callback + "(" + JSON.stringify(datas)+")");
}).listen(8888);

//终端打印如下信息
console.log('Server running at http://127.0.0.1:8888/');
<!DOCTYPE html>
<html ng-app="wsscat">
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <script type="text/javascript" src="angular/angular.js"></script>
    <body ng-controller="homeCtrl">
            {{text}}
    </body>
    <script>
        var app = angular.module('wsscat', []);
        app.controller('homeCtrl', ['$scope', '$http', function($scope, $http) {
            $scope.text = 'wsscat';
            $http.jsonp('http://localhost:8888/index?callback=JSON_CALLBACK').success(function(data){
                console.log(data);
            })
        }])
    </script>
</html>

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.