当前位置: 首页 > news >正文

第一个 Angular 项目 - 静态页面

第一个 Angular 项目 - 静态页面

之前的笔记:

  • [Angular 基础] - Angular 渲染过程 & 组件的创建

  • [Angular 基础] - 数据绑定(databinding)

  • [Angular 基础] - 指令(directives)

这是在学完了上面这三个内容后能够完成的项目,目前因为还没有学到数据在不同组件之前的传输,因此只会有一个 UI 的渲染,而不会涉及到事件的实现

业务需求

wireframe 如下:

在这里插入图片描述

简单的说起来就是当前页面需要包含一个 Header,一个部分列举出所有的食谱(recipe),另外一个部分则列举出对应食谱的购物清单(shopping list)

虚线边框框起来的则是我认为的组件构成,将其转化成 Venn Diagram 则如下:

在这里插入图片描述

ingridentrecipe 为 Model,也就是 MVVM 中一直没讨论的部分(之前一直讨论的都是 VM 层和 V 层之间的互动)

根据需求也就可以开始下一步的实现了

创建项目

主要通过 bash 实现:

❯ ng new recipe-book --no-strict --standalone false --routing falsecd recipe-book
# 在 angular.json 中配置对应的 bootstrap CSS 文件,第一篇笔记中有提npm i bootstrap@3
❯ ng g c header --skip-tests
❯ ng g c recipes --skip-tests
❯ ng g c recipes/recipe-list --skip-tests
❯ ng g c recipes/recipe-list/recipe-item --skip-tests
❯ ng g c shopping-list --skip-tests
❯ ng g c shopping-list/shopping-edit --skip-tests# 这是当前目录的结构
❯ tree src/app/
src/app/
├── app.component.css
├── app.component.html
├── app.component.spec.ts
├── app.component.ts
├── app.module.ts
├── header
│   ├── header.component.css
│   ├── header.component.html
│   └── header.component.ts
├── recipes
│   ├── recipe-detail
│   │   ├── recipe-detail.component.css
│   │   ├── recipe-detail.component.html
│   │   └── recipe-detail.component.ts
│   ├── recipe-list
│   │   ├── recipe-item
│   │   │   ├── recipe-item.component.css
│   │   │   ├── recipe-item.component.html
│   │   │   └── recipe-item.component.ts
│   │   ├── recipe-list.component.css
│   │   ├── recipe-list.component.html
│   │   └── recipe-list.component.ts
│   ├── recipes.component.css
│   ├── recipes.component.html
│   └── recipes.component.ts
└── shopping-list├── shopping-edit│   ├── shopping-edit.component.css│   ├── shopping-edit.component.html│   └── shopping-edit.component.ts├── shopping-list.component.css├── shopping-list.component.html└── shopping-list.component.ts8 directories, 26 files

component 的创建主要则是根据上面提到的业务需求进行实现,目前还没有创建对应 Model 对应的文件

实现功能

这里会用 bootstrap 内置的 class 实施不少功能,而 bootstrap 的部分不会细谈,主要还是针对 Angular 的学习

添加骨架

修改的部分为这里的 V 层:

src/app/
├── app.component.html

修改内容如下:

<app-header></app-header>
<div class="container"><div class="row"><div class="col-md-12"><app-recipes></app-recipes><app-shopping-list></app-shopping-list></div></div>
</div>

这里主要提供的是一个结构,并且展示三大组件:header, recipe 和 shopping list

header

修改的部分为这里的 V 层:

src/app/
├── header
│   ├── header.component.html

实现如下:

<nav class="navbar navbar-default"><div class="container-fluid"><div class="navbar-header"><a href="#" class="navbar-brand">Recipe Book</a></div><div class="collapse navbar-collapse"><ul class="nav navbar-nav"><li><a href="#">Recipes</a></li><li><a href="#">Shopping List</a></li></ul><ul class="nav navbar-nav navbar-right"><li class="dropdown"><ahref="#"class="dropdown-toggle"data-toggle="dropdown"role="button"aria-haspopup="true"aria-expanded="false">Manage <span class="caret"></span></a><ul class="dropdown-menu"><li><a href="#">Save Data</a></li><li><a href="#">Fetch Data</a></li></ul></li></ul></div></div>
</nav>

这里全都是 bootstrap 就不多赘述了,实现后效果如下:

在这里插入图片描述

recipe

recipe 部分的结构通过上面的文件结构也能看出来了,简化一下如下:

├── recipes
│   ├── recipe-detail
│   ├── recipe-list
│   │   ├── recipe-item
│   ├── recipe.model.ts # 即将创建的 model
recipes V 层

这个文件就是 recipes.component.html 这个文件,实现比较简单,只是导入 recipe-list 和当前选中的 recipe-detail:

<div class="row"><div class="col-md-5"><app-recipe-list></app-recipe-list></div><div class="col-md-7"><app-recipe-detail></app-recipe-detail></div>
</div>

这个会让 recipe-list 和 recipe-detail 出现在同一行

接下来就可以处理细节了

recipe model

这里主要就是定义了 recipe 应该有的数据,实现如下:

export class Recipe {constructor(public name: string,public description: string,public imagePath: string) {}
}

这代表着 Recipe 对象会有名字、描述和图片三个属性

recipe list VM 层

VM 层目前的逻辑也比较简单,它只需要存储一个 recipes 的数组,让 V 层可以渲染即可,代码如下:

import { Component } from '@angular/core';
import { Recipe } from '../recipe.model';@Component({selector: 'app-recipe-list',templateUrl: './recipe-list.component.html',styleUrl: './recipe-list.component.css',
})
export class RecipeListComponent {recipes: Recipe[] = [{name: 'Recipe 1',description: 'Description 1',imagePath: 'http://picsum.photos/200/200',},{name: 'Recipe 2',description: 'Description 2',imagePath: 'http://picsum.photos/200/200',},];
}

这里没用 new Recipe() 创建也不会报错,本质上来说 TS 的类型检查是检查数据是否对的上,而不是真的会检查 a instanceof A,而是做 a 有 name, a 有 description, a 有 imagePath -> a 是 A ✅ 这样一个检查

⚠️:picsum.photos 是我在 placeimg.com 上找到的代替网站。placeimg.com 于去年年中正式关站了(🕯️)

recipe list V 层

这一层要做的也比较简单,主要就是跑一个 ngFor 去渲染当前 list 中包含的数据,并且正确的渲染 recipe.name, recipe.descriptionrecipe.imagePath 即可,这里主要用到的还是 string interpolation 和 property binding

实现代码如下:

<div class="row"><div class="col-xs-12"><button class="btn btn-success">New Recipe</button></div>
</div>
<div class="row"><div class="col-xs-12"><a href="#" class="list-group-item clearfix" *ngFor="let recipe of recipes"><div class="pull-left"><h4 class="list-group-item-heading">{{ recipe.name }}</h4><p class="list-group-item-text">{{ recipe.description }}</p></div><span class="pull-right"><img[src]="recipe.imagePath"[alt]="recipe.name"class="image-responsive"style="max-height: 50px"/></span></a></div><app-recipe-item></app-recipe-item>
</div>

完成后的效果:

在这里插入图片描述

⚠️:这里的 ngFor + 输出所有的数据在 ngFor 是因为还没有实现跨组件交流,否则直接在 ngFor 中渲染 app-recipe-item,并传递对应对象即可

recipe detail V 层

同样因为跨组件交流还没实现,目前只会渲染一个静态且不会动的 V 层:

<div class="row"><div class="col-sx-12"><img [src]="" [alt]="" class="img-responsive" style="max-height: 300px" /></div>
</div>
<div class="row"><div class="col-xs-12"><h1>Recipe Name</h1></div>
</div>
<div class="row"><div class="col-xs-12"><div class="btn-group"><button type="button" class="btn btn-primary dropdown-toggle">Manage Recipe <span class="caret"></span></button><ul class="dropdown-menu"><li><a href="#">To Shopping List</a></li><li><a href="#">Edit Recipe</a></li><li><a href="#">Delete Recipe</a></li></ul></div></div>
</div><div class="row"><div class="col-sx-12">Description</div>
</div><div class="row"><div class="col-sx-12">Ingredients</div>
</div>

完成后效果:

在这里插入图片描述

至此 recipe 部分结束

shopping-list

shopping-list 的实现和 recipe 差不多,也是创建 model,随后填充 VM 层

ingredient model

这个 model 在的目录不太一样:

src/app/
├── shared
│   └── ingredient.model.ts

个人的话,大概便好创建一个新的 src/app/model 用来存放所有的 model 吧,不过这种有点看个人便好/项目规定了。实现如下:

export class Ingredient {constructor(public name: string, public amount: number) {}
}
shopping-list VM 层

这个和 recipe VM 层差不多,添加 Ingredient[] 即可

import { Component } from '@angular/core';
import { Ingredient } from '../shared/ingredient.model';@Component({selector: 'app-shopping-list',templateUrl: './shopping-list.component.html',styleUrl: './shopping-list.component.css',
})
export class ShoppingListComponent {ingredients: Ingredient[] = [new Ingredient('Apples', 5),new Ingredient('Tomatoes', 10),];
}
shopping-list V 层

这里的实现也和上面 recipe list 的实现对应:

<div class="row"><div class="col-xs-10"><app-shopping-edit></app-shopping-edit><hr /><ul class="list-group"><aclass="list-group-item"style="cursor: pointer"*ngFor="let ingredient of ingredients">{{ ingredient.name }} ({{ ingredient.amount }})</a></ul></div>
</div>

实现后效果如下:

在这里插入图片描述

shopping-list edit V 层

出于同样的原因,这里只有 V 层,实现如下:

<div class="row"><div class="col-xs-12"><form><div class="row"><div class="col-sm-5 form-group"><label for="name">Name</label><input type="text" id="name" class="form-control" /></div><div class="col-sm-2 form-group"><label for="amount">Amount</label><input type="number" id="amount" class="form-control" /></div></div><div class="row"><div class="col-xs-12"><div class="btn-toolbar"><button class="btn btn-success mr-2" type="submit">Add</button><button class="btn btn-danger mr-2" type="button">Delete</button><button class="btn btn-primary" type="button">Edit</button></div></div></div></form></div>
</div>

最终结果:

在这里插入图片描述

下个章节开始数据传输之类的,也就是让页面动起来的部分

http://www.lryc.cn/news/298859.html

相关文章:

  • 网络协议与攻击模拟_17HTTPS 协议
  • 【linux系统体验】-ubuntu简易折腾
  • Android 判断通知是进度条通知
  • 学习数据结构和算法的第8天
  • JCIM | MD揭示PTP1B磷酸酶激活RtcB连接酶的机制
  • 基于Java (spring-boot)的音乐管理系统
  • 在 MacOS M系列处理器上使用 Anaconda 开发 Oralce 的Python程序
  • 四、OpenAI之文本生成模型
  • CSS之flex布局
  • UnityShader——02三大主流编程语言
  • Centos7安装nginx yum报错
  • 【机组】基于FPGA的32位算术逻辑运算单元的设计(EP2C5扩充选配类)
  • Asp .Net Core 系列:Asp .Net Core 集成 NLog
  • 一个基于 .NET 7 + Vue.js 的前后端分离的通用后台管理系统框架 - DncZeus
  • 更换商品图片日期JSON格式报错 - 序列化与反序列化日期格式设置
  • FastJson、Jackson使用AOP切面进行日志打印异常
  • 嵌入式大厂面试题(2)—— 富士康
  • 力扣_字符串4—编辑距离
  • MySQL篇----第二十篇
  • Promise 基础
  • RPA财务机器人之UiPath实战 - 自动化操作Excel进行财务数据汇总与分析之流程建立与数据读取、处理、汇总、分析
  • 华为机试真题实战应用【赛题代码篇】-输入整型数组和排序标识/根据排序标识flag给数组排序(附Java、C++和python代码)
  • 【算法随想录01】环形链表
  • macOS Sonoma 14.3.1(23D60)发布
  • 2024-02-11 叮当鸭-平台系统-第三次重构-目标确定
  • Android7.0-Fiddler证书问题
  • Kotlin:单例模式(项目使用实例)
  • vue百度地图的和element输入框/v-region的联动
  • 搜索+哈希/平衡树,LeetCode 987. 二叉树的垂序遍历
  • 蓝桥杯每日一题之内存问题