学习Angular并与Vue.js进行比较 – 实现部分 – 第三部分
继前一篇文章,学习Angular与Vue.js的比较 – 配置篇 – 第2部分
我打算从这里开始写代码。
你首先要做什么?
因为想要比较页面跳转,所以打算创建主页、列表页和详细页这三个页面。
在列表页面和详情页面中展示从API获取的数据。
设计的样子是这样的
不管怎样,跳转页面。
我想首先创建一个空白页面。
在Vue的情况下
<template>
<div class="top">
Top
</div>
</template>
<script>
export default {
name: 'Top',
}
</script>
<template>
<div class="list">
List
</div>
</template>
<script>
export default {
name: 'List',
}
</script>
<template>
<div class="detail">
Detail
</div>
</template>
<script>
export default {
name: 'Detail',
}
</script>
下一步是将组件和过渡联系起来。
URL将设置为以下3个。
-
- / トップページ
-
- /list 一覧ページ
- /detail/[id] 詳細ページ
import Vue from 'vue'
import VueRouter from 'vue-router'
import Top from '@/views/Top.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'Top',
component: Top
},
{
path: '/list',
name: 'List',
component: () => import(/* webpackChunkName: "list" */ '@/views/List.vue')
},
{
path: '/detail/:id',
name: 'Detail',
component: () => import(/* webpackChunkName: "detail" */ '@/views/Detail.vue')
}
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
export default router
便宜起见,在此我们使用了webpackchunk,并不详细解释。
只要每个页面的URL显示如下,就算是成功。
如果是Angular的情况
让我们创建一个空页面在Angular中。
在Vue中,我們需要複製文件來建立頁面。但在Angular CLI中,我們可以使用以下命令來生成文件和目錄。
$ ng generate component top # 省略形のコマンド ng g c top
$ ng generate component list
$ ng generate component detal
敲击三个命令后,可以确认已生成了三个包含三个文件的目录。
从顶层目录提取的摘要
<p>top works!</p>
// 空のファイル
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-top',
templateUrl: './top.component.html',
styleUrls: ['./top.component.scss']
})
export class TopComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}
/src/app/app.module.ts文件中追加了一个需要注意的部分
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { TopComponent } from './top/top.component';
import { ListComponent } from './list/list.component';
import { DetailComponent } from './detail/detail.component';
@NgModule({
declarations: [
AppComponent,
+ TopComponent,
+ ListComponent,
+ DetailComponent
],
imports: [
BrowserModule,
AppRoutingModule,
],
bootstrap: [AppComponent]
})
export class AppModule { }
通过将组件文件加载到声明中,可以在组件内部使用所需的文件,从而可以使用其他组件。
接下来,我们将编写用于转移的路由文件。
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
+ import { TopComponent } from './top/top.component';
+ import { ListComponent } from './list/list.component';
+ import { DetailComponent } from './detail/detail.component';
const routes: Routes = [
+ {
+ path: '',
+ component: TopComponent
+ },
+ {
+ path: 'list',
+ component: ListComponent
+ },
+ {
+ path: 'detail/:id',
+ component: DetailComponent
+ }
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
这里与Vue几乎没有什么不同。
只要在URL上访问并确认屏幕上显示下方的图片,就表示成功了。
CSS布局
由于文件创建已经完成,所以我们将开始进行CSS布局。
首先,我们需要编写normalize.scss和共通CSS来解决不同浏览器之间的布局差异。
Vue的情况下
安装normalize.scss
yarn add normalize.scss
or
npm install normalize.scss
导入 normalize.scss 文件
<template>
<div id="app">
<router-view/>
</div>
</template>
+ <script>
+ import 'normalize.scss/normalize.scss'
+
+ export default{
+ name: 'App'
+ }
+ </script>
写上通用CSS
<template>
<div id="app">
<router-view/>
</div>
</template>
<script>
import 'normalize.scss/normalize.scss'
export default{
name: 'App'
}
</script>
<style>
body {
font-family: YuGothic,'Yu Gothic','Hiragino Kaku Gothic ProN','ヒラギノ角ゴ ProN W3','メイリオ', + Meiryo,'MS ゴシック',sans-serif;
font-weight: 400;
font-size: 12px;
}
</style>
在Angular的情况下
normalize.scss的安装方式不变,故省略不提。
Angular的环境配置文件中存在一个名为angular.json的东西,我想要在node_modules文件夹中安装的文件中使用scss进行读取。
"node_modules/normalize.scss/normalize.scss
将其追加到styles中。
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"sample-angular": {
...
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
...
"styles": [
+ "node_modules/normalize.scss/normalize.scss",
"src/styles.scss"
],
...
}
为了设定Angular的共通样式,可以准备styles.scss文件,并在此处加载normalize.scss并编写共通样式描述。
@import '~normalize.scss';
body {
font-family: YuGothic,'Yu Gothic','Hiragino Kaku Gothic ProN','ヒラギノ角ゴ ProN W3','メイリオ', + Meiryo,'MS ゴシック',sans-serif;
font-weight: 400;
font-size: 12px;
}
这样一切准备都完成了。
创建首页
创建首页
首页的结构是
准备可供共同使用的组件,并将其加载到首页上。
共通组件
– 按钮
– 头部
对于Vue而言
按钮组件应使用props从父组件接收数据,以便进行数据传递。
<template>
<router-link :to="path" class="button">{{ text }}</router-link>
</template>
<script>
export default {
name: 'BaseButton',
props: {
/**
* @param text buttonに表示させる文字列
* @param path 遷移先のURLのパス
*/
text: {
type: String,
required: true
},
path: {
type: String,
required: true
}
}
}
</script>
<style lang="scss" scoped>
.button{
display: block;
font-size: 22px;
width: 400px;
height: 70px;
padding: 25px;
box-sizing: border-box;
color: #fff;
background: #000;
font-weight: 700;
text-align: center;
line-height: 1;
transition: all .3s ease;
border: 1px solid transparent;
&:hover {
background-color: #fff;
border-color: #000;
color: #000;
}
}
</style>
在中文中,Header组件使用router-link-active来为跳转页面应用CSS类。
<template>
<header class="header">
<nav>
<ul class="navList">
<li class="navItem">
<router-link to="/" class="navLink" exact>トップ</router-link>
</li>
<li class="navItem">
<router-link to="/list" class="navLink" exact>商品一覧</router-link>
</li>
</ul>
</nav>
</header>
</template>
<script>
export default {
name: 'TheHeader',
}
</script>
<style lang="scss" scoped>
.header{
padding: 60px 0;
}
.navList{
display: flex;
justify-content: center;
}
.navLink{
color: #ccc;
font-weight: 700;
line-height: 1;
}
.navItem{
padding: 0 20px;
&:not(:first-child){
border-left: 1px solid #000;
}
}
.router-link-active{
color: #000;
}
</style>
在顶部使用 import 导入共通组件文件,通过 components 编写以在 Vue 模板中使用。
<template>
<div class="top">
<TheHeader></TheHeader>
<div class="titleWrap">
<h1 class="title">それっぽいトップページ</h1>
<p class="subTitle">KAKKO II EIGO NO TEKISUTO GA HAIRU</p>
<p class="subTitleBg">KAKKO II EIGO<br>NO TEKISUTO GA HAIRU</p>
</div>
<div class="button">
<BaseButton text="商品を見る" path="/list"></BaseButton>
</div>
</div>
</template>
<script>
import TheHeader from '@/components/TheHeader'
import BaseButton from '@/components/BaseButton'
export default {
name: 'Top',
components: {
TheHeader,
BaseButton
}
}
</script>
<style lang="scss" scoped>
.titleWrap{
position: relative;
margin-top: 200px;
}
.title{
font-size: 120px;
line-height: 1;
font-weight: 700;
text-align: center;
}
.subTitle{
margin-top: 30px;
font-size: 20px;
text-align: center;
}
.subTitleBg{
position: absolute;
top: 70px;
left: 50%;
z-index: -1;
font-size: 60px;
line-height: 1.05;
color: #eee;
text-align: center;
transform: translateX(-50%);
}
.button{
width: 400px;
margin: 150px auto 0;
}
</style>
在App中添加重置CSS后,首页完成了。
<template>
<div id="app">
<router-view/>
</div>
</template>
<script>
import 'normalize.scss/normalize.scss'
export default{
name: 'App'
}
</script>
<style>
body {
font-family: YuGothic,'Yu Gothic','Hiragino Kaku Gothic ProN','ヒラギノ角ゴ ProN W3','メイリオ', Meiryo,'MS ゴシック',sans-serif;
font-weight: 400;
font-size: 12px;
height: 100%;
background: #FCFCFC;
}
h1, p, ul{
margin: 0;
}
ul{
list-style-type: none;
padding-left: 0;
}
a{
text-decoration: none;
}
</style>
在Angular的情况下
在Angular中,虽然几乎是相似的,但为了方便使用共享文件,我想创建一个shared文件夹来管理组件。
首先,使用cli命令创建用于管理的文件夹。
ng generate module shared # 省略形はng g m shared
生成的文件
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
@NgModule({
declarations: [],
imports: [
CommonModule
]
})
export class SharedModule { }
本次将组件文件作为共享文件进行管理,
考虑将来可能还会将其他功能进行共享化,
因此创建一个share/component文件夹,以便更方便地进行管理。
ng generate module shared/component
生成的文件
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
@NgModule({
declarations: [],
imports: [
CommonModule
]
})
export class ComponentModule { }
创建文件后, 按照 App 模块← shared 模块← shared/compoent 模块的顺序将它们连接在一起, 以便在 App 组件中使用.
最初,将shared模块文件与app模块关联起来。
关联模块文件是通过将其载入到imports: []中实现的。
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { TopComponent } from './top/top.component';
import { ListComponent } from './list/list.component';
import { DetailComponent } from './detail/detail.component';
+ import { SharedModule } from './shared/shared.module';
@NgModule({
declarations: [
AppComponent,
TopComponent,
ListComponent,
DetailComponent
],
imports: [
BrowserModule,
AppRoutingModule,
+ SharedModule
],
bootstrap: [AppComponent]
})
export class AppModule { }
接下来,我们将在shared模块中加载shared/component模块。
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ComponentModule } from './component/component.module';
@NgModule({
declarations: [],
imports: [
CommonModule,
+ ComponentModule
]
})
export class SharedModule { }
下面是一个可能的中文翻译选项:
在某些特殊情况下,当在外部类似于app模块的地方使用已加载的模块时,需要在exports:[]中写下所使用的外部模块文件。因此,需要在exports中逐步记录shared/component模块。
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ComponentModule } from './component/component.module';
@NgModule({
declarations: [],
imports: [
CommonModule,
ComponentModule
],
+ exports: [
+ ComponentModule
+ ]
})
export class SharedModule { }
这样就完成了共享文件夹的创建。
接下来,使用cli命令创建按钮组件和头部组件的文件。
ng generate component shared/component/button # 省略形はng g c shared/component/button
ng g c shared/component/header
当命令成功执行时,将会生成ts、html和scss文件。
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-button',
templateUrl: './button.component.html',
styleUrls: ['./button.component.scss']
})
export class ButtonComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.scss']
})
export class HeaderComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}
当成功生成文件后,可以确认自动加载了组件到父模块文件的声明中
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ButtonComponent } from './button/button.component';
import { HeaderComponent } from './header/header.component';
@NgModule({
+ declarations: [ButtonComponent, HeaderComponent],
imports: [
CommonModule
]
})
export class ComponentModule { }
然而,如果保持现状,无法在共享模块中调用,因此需要添加导出命令。
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ButtonComponent } from './button/button.component';
import { HeaderComponent } from './header/header.component';
@NgModule({
declarations: [
ButtonComponent,
HeaderComponent
],
imports: [
CommonModule
],
+ exports: [
+ ButtonComponent,
+ HeaderComponent
+ ]
})
export class ComponentModule { }
从 shared 模块中正确加载了 button 组件和 header 组件吗?尝试从 top 组件中调用并进行确认。
<app-header></app-header>
<app-button></app-button>
如果在模板中嵌入组件,可以使用组件文件中指定的选择器名称进行调用。
接下来我们将创建一个button组件。
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ButtonComponent } from './button/button.component';
import { HeaderComponent } from './header/header.component';
+ import { RouterModule } from '@angular/router';
@NgModule({
declarations: [
ButtonComponent,
HeaderComponent
],
imports: [
CommonModule,
+ RouterModule
],
exports: [
ButtonComponent,
HeaderComponent
]
})
export class ComponentModule { }
如果想要使用Vue中的标签进行页面跳转,只需添加标签即可使用,并无特殊需求。
在Angular中,需要在module文件中加载RouterModule模块。
RouterModule不是一个自定义的模块,而是一个在框架中预先提供的模块文件。
<a [routerLink]="path" class="button">{{ text }}</a>
如果加载了module文件,可以通过routerLink=”文件路径”来指定导航目标。在这种情况下,我想添加变量而不是字符串,所以我通过[routerLink]=”变量名包含文件路径”的形式进行数据绑定。
.button{
display: block;
font-size: 22px;
width: 400px;
height: 70px;
padding: 25px;
box-sizing: border-box;
color: #fff;
background: #000;
font-weight: 700;
text-align: center;
line-height: 1;
transition: all .3s ease;
border: 1px solid transparent;
&:hover {
background-color: #fff;
border-color: #000;
color: #000;
}
}
对于scss的详细说明将被省略。
+ import { Component, OnInit, Input } from '@angular/core';
@Component({
selector: 'app-button',
templateUrl: './button.component.html',
styleUrls: ['./button.component.scss']
})
export class ButtonComponent implements OnInit {
/** Vueで言う所のpropsに該当するもの
* @param text buttonに表示させる文字列
* @param path 遷移先のURLのパス
*/
+ @Input() text: string;
+ @Input() path: string;
constructor() { }
ngOnInit() {
}
}
在Vue中,通过使用props,可以从父组件传递数据。
在Angular中,通过使用Input,可以传递和接收数据。
import { Input } from '@angular/core';
class Hoge {
@Input() val: type; // @Input() 変数: 型の名前
}
下一步,创建header组件。
<header class="header">
<nav>
<ul class="navList">
<li class="navItem">
<a routerLink="/" class="navLink" routerLinkActive="router-link-active" [routerLinkActiveOptions]="{exact: true}">トップ</a>
</li>
<li class="navItem">
<a routerLink="/list" class="navLink" routerLinkActive="router-link-active" [routerLinkActiveOptions]="{exact: true}">商品一覧</a>
</li>
</ul>
</nav>
</header>
与之前的button组件不同,routerLink需要放入一个字符串。
routerLinkActive是一个能够在路由器链接到指定位置时传递class的功能。在routerLinkActive中指定class,可以使指定的class在活动时生效。
[routerLinkActiveOptions]="{exact: true}"
如果上述代码的目标路径正确,它将被设定为激活状态。
只需写入 SCSS。
.header{
padding: 60px 0;
}
.navList{
display: flex;
justify-content: center;
}
.navLink{
color: #ccc;
font-weight: 700;
line-height: 1;
}
.navItem{
padding: 0 20px;
&:not(:first-child){
border-left: 1px solid #000;
}
}
.router-link-active{
color: #000;
}
@import '~normalize.scss';
body {
font-family: YuGothic,'Yu Gothic','Hiragino Kaku Gothic ProN','ヒラギノ角ゴ ProN W3','メイリオ', Meiryo,'MS ゴシック',sans-serif;
font-weight: 400;
font-size: 12px;
height: 100%;
background: #FCFCFC;
}
h1, p, ul{
margin: 0;
}
ul{
list-style-type: none;
padding-left: 0;
}
a{
text-decoration: none;
}
下一步是创建首页。
通过父组件向传递数据。
<div class="top">
<app-header></app-header>
<div class="titleWrap">
<h1 class="title">それっぽいトップページ</h1>
<p class="subTitle">KAKKO II EIGO NO TEKISUTO GA HAIRU</p>
<p class="subTitleBg">KAKKO II EIGO<br>NO TEKISUTO GA HAIRU</p>
</div>
<div class="button">
<app-button text="商品を見る" path="/list"></app-button>
</div>
</div>
请写上用于顶部布局的css样式
.titleWrap{
position: relative;
margin-top: 200px;
}
.title{
font-size: 120px;
line-height: 1;
font-weight: 700;
text-align: center;
}
.subTitle{
margin-top: 30px;
font-size: 20px;
text-align: center;
}
.subTitleBg{
position: absolute;
top: 70px;
left: 50%;
z-index: -1;
font-size: 60px;
line-height: 1.05;
color: #eee;
text-align: center;
transform: translateX(-50%);
}
.button{
width: 400px;
margin: 150px auto 0;
}
Angular的主页已完成。
总结
编写源代码后,发现作为文章变得非常长。
当我们在代码级别上比较SPA框架时,我们发现它们具有相同的功能。
也许是因为Vue的创作者尤雨溪先生参与了AngularJS的开发,所以这两者的机制可能相似。
我想在下一章中创建商品列表页面和详细页面。
希望这成为最后一章。
在学习Angular的实际应用中与Vue.js进行比较 – 实施篇- 第4部分。