angular-vue
(施工中)
学习Vue过程中,记下与Angular相比较的笔记
开发环境
VS Code
Win-10 v1903
NodeJs: v10.14.1
npm: 6.4.1
angular/cli: 8.3.20
rxjs: 6.4.0
安装
Angular:
Angular的起源这里只简单的介绍一下,有兴趣的可以自行搜索。
AngularJs诞生于2009年,起先也是类似于现在VueJs一样的,只需要html页面中导入相应的script库,即可使用,有兴趣的可以稍微看看我的AngularJS-1.6.6-Tutorial稍作了解。
从Angular2开始,Angular变成了一个完整的前端框架且主要使用TypeScript。之后为了与之前的AngularJs区分并且对Angular本身进行了很大的改变,跨过了Angular3,直接到了Angular4,并且计划每半年发布一次新版本。至今已是Angular8 (Angular9照计划应该已经推出,但是每次都会晚一些)。
安装Angular需要首先安装NodeJs和npm,搜索一下nodejs即可找到安装包,windows下npm也会随着nodejs安装,安装完成后使用node --version和npm --version检查是否安装成功。打开终端(cmd,powershell,windows terminal都可以),运行npm install -g @angular/cli,等待安装结束运行ng --version查看是否安装成功
vuejs
只有一步,导入即可。
使用
由于本人之前只用过Angular,vue的经验不多,具目前的使用来看大概分为几个部分,我将一一对比Angular和vuejs的代码。所有的代码我都会放在stackblitz: vuejs和angular
*1. 插值
*2. 双向绑定
*3. 组件事件
*4. 条件、循环调用组件和组件复用
*5. 将值传入子组件
*6. 子组件事件上浮至父组件
1. 插值
Vuejs:
index.html
{{message}}
index.js
// Import stylesheets
import './style.css';
import Vue from 'vue'
// Write Javascript code!
var vm = new Vue({
el:'#app', //绑定到id为app的元素,不可使用body
data:function(){ //插入值变量
return{
message:'hello world'
}
}
})
即可得到
angular
在stackblitz里可以直接创建一个空的angular项目,也可以本地使用ng new app 创建一个本地项目,这里推荐在stackblitz因为既快又方便。
app.component.ts //等价于index.js,使用ts编写
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
message = 'hello world';
}
app.component.html
{{message}}
这里可能会奇怪为什么没有完整的body和其他的tag,原因在于angular已经帮你绑定好了,你会看到项目内存在一个index.html的文件,如果打开你会看到一行代码
如果运行程序可以看到相同的结果
2. 双向绑定
在mvvm中,双向绑定是一个非常方便且很有必要的功能,在纯js中,如果我们有两个input让用户来输入他的邮箱和密码,再点击登录按钮登录,需要使用类似的代码
var email = document.getElementById('email').val();
var password = document.getElementById('password').val();
//code to send email & password
而在angular和vue中,如果我们使用了双向绑定,变量会自动得到当前的值而非手动
vue
首先,我们需要在index.js中的data设一个变量,如果没有默认值可以设为空值email:'x@zx.com'
第二步,在index.html中添加如下代码
双向绑定
angular
在angular中,第一次双向绑定会比vue多一步,而之后则是一样的先设变量再绑定。这是因为angular中的模块较多,需要手动添加需要的模块。
在app.module.ts中导入import { FormsModule } from '@angular/forms';,再在@NgModule里的imports中添加FormsModule添加email变量使用[(ngModel)]绑定
修改后的app.component.html代码如下
双向绑定
可以发现代码几乎完全一样,唯一的却别在于[(ngModel)]="email"和v-model="email"。
3.事件
与双相绑定一样,angular和vue的事件绑定也非常类似。
vue
在Vue对象中添加新的field-methods,在methods中定义方法。修改后的js如下:var vm = new Vue({
el:'#app',
data:function(){
return{
message:'hello world',
email:'x@zx.com',
count: 0
}
},
methods:{
addOne:function(){
this.count+=1;
}
}
})
添加对应的html并使用v-on:click="addOne"将按钮与事件绑定
事件
效果如下:
angular
在html文件中添加如下代码
事件
在ts文件中添加count变量并添加函数,修改后的AppComponent class如下:export class AppComponent {
message = 'hello world';
email:string = 'x@zx.com';
count:number = 0;
addOne(){
this.count++;
}
}
即可得到相同的效果,主要区别在于vue使用v-on:click="addOne"而angular使用(click)="addOne()",注意angular中的函数括号不可省略
4.条件、循环调用组件和组件复用
首先来看条件,从前面的插值、双向绑定和事件,能看出来vue和angular是非常相似的,这一点在条件和循环调用也是一样的。
vue
在html文件中添加如下代码:
条件
在Vue实例中添加showMsg变量和changeShowMsg函数如下showMsg: true
changeShowMsg:function(){
this.showMsg = !this.showMsg;
}
注意当v-if的变量表达式为false时,dom中是看不到这个元素的。效果如下:
angular
在html中添加如下代码:
条件
在ts文件中加入变量和方法如下:showMsg:boolean = true;
changeShowMsg(){
this.showMsg = !this.showMsg;
}
这里我们发现,angular的else是和if放在一起的*ngIf="showMsg;else anotherMsg"。而在else的模板中需要使用指令赋予一个名字#anotherMsg,这样angular才会知道else去渲染什么模板。并且这个模板必须使用ng-template,在angular中ng-template并不会真正的生产一个tag,当渲染时,会自动去除。
这里可能会认为angular这里会复杂一些,但是根据我的理解,事实并非如此,我们对vue中的条件稍作修饰如下:
条件2
当我们的if-else模板中的tag多余一个,我们也必须使用template,这样就和angular基本一致了。唯一的区别在于angular的else是需要放在*ngIf语句中,而vue是分开的。
循环
接下来是另一个重要的指令-循环
假设我们有一个包含n个Person对象的数组People,如果不使用任何框架(包括mvc),那么n个对象以为着我们要重复的写n遍html来显示所有对象的字段,而如果用循环,只需要写一次并放入循环即可。
vue
在data中添加一个数组如下:
people:[
{name: 'Jack', phone: '123-123-3456', addr: 'NYC'},
{name: 'Tom', phone: '123-123-1234', addr: 'CT'},
{name: 'Bell', phone: '123-123-5678', addr: 'CL'}
]
在css中添加table样式如下:
td,th{
border:1px solid;
padding: 5px;
}
table{
border-collapse:collapse;
text-align:center;
}
在html添加如下代码:
循环
Name | Phone | Address |
---|---|---|
{{person.name}} | {{person.phone}} | {{person.addr}} |
注意v-for="person in people"这里的people是data里的person,名字要保持一致,而person可以当成我们赋予的本地变量,就像c#中的for(var item in people)一样
无论数组中有多少个item,都会自动渲染出来,效果图如下:
angular
angular的代码和vue并不会有太大的区别,但是因为angular是用ts的,我们可以指定Person和People的类型,也可以不指定而使用js风格,代码如下:
ts
修改后的app.component.ts代码如下
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
message = 'hello world';
email: string = 'x@zx.com';
count: number = 0;
showMsg: boolean = true;
people:Person[] = [
new Person('Jack','123-123-3456','NYC'),
new Person('Tom','123-123-1234','CT'),
new Person('Bell','123-123-5678','CL'),
];
addOne() {
this.count++;
}
changeShowMsg() {
this.showMsg = !this.showMsg;
}
}
export class Person{
constructor(public name:string, public phone:string, public addr:string){}
}
若不想声明一个Person类,下面的代码等效:
people = [
{name: 'Jack', phone: '123-123-3456', addr: 'NYC'},
{name: 'Tom', phone: '123-123-1234', addr: 'CT'},
{name: 'Bell', phone: '123-123-5678', addr: 'CL'}
]
html:
循环
Name | Phone | Address |
---|---|---|
{{person.name}} | {{person.phone}} | {{person.addr}} |
可以发现html中唯一的区别在于是:
vue: v-for="person in people" 和 angular: *ngFor="let person of people"。
从前面的几个部分可以看出来,如果你会写vue,那么angular其实也会了,反之亦然。
5. 将值传入子组件
vue
在vue的官方文档中,vue实例有一个叫props的字段,可以定义传入的变量名,这样可以在调用自定义组件时绑定相应。假设我们有一个自定义的子组件,组件接受一个数组并在表格中显示所有的数据。就拿之前的一步做例子,我们新建并注册一个vue的component。
var personComponent = Vue.component('personComponent',{
props:['people'],
template:`
Name | Phone | Address |
---|---|---|
{{person.name}} | {{person.phone}} | {{person.addr}} |
`
})
注册component必须放在vue的实例之前
这里我们把前一步的table和循环放在了一个子组件里,这样我们可以在任意的地方调用这个子组件并传入相应的值。当我们需要在不同的地方使用同一块html的时候,组件会非常有用。
调用:
子组件传入
这里v-bind:people="people"中v-bind:people里的people是指的子组件里的props的值,而="people"是指的父组件(调用组件域)中的data里的people变量。
注意: 可能会疑惑为什么我们注册的component的名字为personComponent而调用的时候是使用
组件化或者模块化可以把复杂、大量的html分成简洁明了的代码,这在维护一个非常大、复杂的页面时是非常有用的。
angular
在一个angular项目中添加一个component后需要主动导入到根module中,这是因为避免加载过多的未使用的component而导致项目体积过大。*如果你使用angular cli,则使用ng g component
在app目录下新建一个文件夹名为person-component
在person-component文件下添加person-component.component.ts,person-component.component.html,person-component.component.css三个文件
在ts文件中添加如下代码:
import { Component, Input } from '@angular/core';
@Component({
selector: 'person-component',
templateUrl: './person-component.component.html',
styleUrls: ['./person-component.component.css']
})
export class PersonComponent {
@Input() people:any;
}
在html文件中添加如下代码:
Name | Phone | Address |
---|---|---|
{{person.name}} | {{person.phone}} | {{person.addr}} |
打开app.module.ts文件并在导入部分添加import { PersonComponent } from './person-component/person-component.component';,再在declarations数组中添加PersonComponent,导入完成。
在app.component.html中添加如下代码:
子组件传入
即可得到相同的效果,效果图如下:
解析:
vue中的props等价于angular中@Input()
vue中v-bind:people="people"等价于angular中的[people]="people"。
6. 子组件事件上浮至父组件
有传入就有传出,当我们需要把子组件的事件上浮到父组件中处理时,就需要把事件上浮。还是首先来看vue
vue
在子组件personComponent的模板中的
末尾添加, 点击按扭emit一个名为change-person的事件,需要在父组件中绑定,并传出参数person在html中添加代码,监听子组件中的事件名称并绑定方法:
注意这里的v-on:change-person="changePerson"中的change-person与模板中的$emit一致,而changePerson是父组件中的方法名称
子组件事件上浮
在父组件中添加方法如下,这个方法可以将子组件传出的值打印在控制台以方便我们观察:
changePerson:function(event){
console.log(event);
}
最终的效果如下:
angular
接下来是angular,在angular中的传入是Input,那么你可能已经猜到了上浮有可能是Output,答对了!
首先修改子组件的ts文件,添加一个Output的事件变量并导入EventEmitter和Output 的类,最后再添加事件上浮的方法:
import { Component, Input, Output, EventEmitter } from '@angular/core';
@Output() selectedPerson = new EventEmitter();
changePerson(e){
this.selectedPerson.emit(e);
}
修改子组件html文件,添加按钮和事件,angular的话子组件里只需要设置参数即可:
在父组件app.component.html中添加子组件并绑定本地方法,这里的selectedPerson与子组件中Output变量名一致,也可以设置其他名字,具体步骤可以搜索angular的官方文档:
事件上浮
app.component.ts:
changePerson(e){
console.log(e);
}
对比angular和vue可以发现他们的流程都是一样的,几个步骤如下:
在子组件中emit一个事件在父组件中设定一个变量和方法与上浮的事件进行绑定调用方法