第一个 Angular 项目 - 静态页面

news2024/9/24 11:33:16

第一个 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.ts

8 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">
          <a
            href="#"
            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">
      <a
        class="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.coloradmin.cn/o/1439397.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【漏洞复现】多语言药房管理系统MPMS文件上传漏洞

Nx01 产品简介 多语言药房管理系统 (MPMS) 是用 PHP 和 MySQL 开发的, 该软件的主要目的是在药房和客户之间提供一套接口&#xff0c;客户是该软件的主要用户。该软件有助于为药房业务创建一个综合数据库&#xff0c;并根据到期、产品等各种参数提供各种报告。 Nx02 漏洞描述 …

【服务器数据恢复】HP EVA虚拟化磁盘阵列数据恢复原理方案

EVA存储结构&原理&#xff1a; EVA是虚拟化存储&#xff0c;在工作过程中&#xff0c;EVA存储中的数据会不断地迁移&#xff0c;再加上运行在EVA上的应用都比较繁重&#xff0c;磁盘负载高&#xff0c;很容易出现故障。EVA是通过大量磁盘的冗余空间和故障后rss冗余磁盘动态…

笔记---dp---数字三角形模型

所谓数字三角形模型&#xff0c;即是从数字三角形这一题衍生出来的 题目为经典题目&#xff0c;不再赘述&#xff0c;此笔记根据AcWing算法提高课来进行对数字三角形模型衍生例题的记录 题目关系如下&#xff08;见AcWing里的AcSaber&#xff09;&#xff1a; AcWing.1015.摘…

Nature Machine Intelligence 使用机器学习驱动的可拉伸智能纺织手套捕捉复杂的手部动作和物体交互

研究背景 对灵巧手运动的精确实时跟踪在人机交互、元宇宙、机器人和远程医疗等领域有着广泛的应用。当前的可穿戴设备中的大多数仅用于检测精度有限的特定手势&#xff0c;并且没有解决与设备的可靠性、准确性和可清洗相关的挑战。对传感器直接放置在用户的手上有严格的要求&am…

自然人如何代开发票

1&#xff1a;登录国家税务总局深圳市电子税务局 地址&#xff1a;国家税务总局深圳市电子税务局 2&#xff1a;个人所得税APP 扫描登录 或 身份证登录 3&#xff1a;选择 自然人代开增值税电子普通发票 4&#xff1a;申请代开 5&#xff1a;人脸识别 6&#xff1a;画框的…

Ubuntu20.04更新Cmake版本详解

最近在跑一个融合惯导定位的slam框架ins_eskf_kitti&#xff0c;在框架的安装过程中&#xff0c;需要对从GitHub上克隆下来的glog进行编译。其命令如下&#xff1a; glog&#xff1a; git clone https://github.com/google/glog.git cd glog mkdir build cd build cmake .. m…

1分钟搞定面试——Activity与Fragment生命周期

目录 1.Activity与Fragment启动 2.Fragment之间的切换 2.1 使用add() 2.2 使用replace() 3.带Fragment_A的MainActivity切换到SecondActivity&#xff0c;再返回到MainActivity 4.带有Fragment_B的SecondActivity返回到MainActivity 5.详细谈谈生命周期中各方法 因为Fra…

c#读取csv文件中的某一列的数据

chat8 (chat779.com) 上面试GPT-3.5,很好的浏览网站&#xff0c;输入问题&#xff0c;可得到答案。 问题1&#xff1a;c#如何在csv中读取某一列数据 解答方案&#xff1a;在 C#中&#xff0c;你可以使用File.ReadAllLines来读取CSV中的所有行&#xff0c;然后逐行解析每一行…

HCIA-HarmonyOS设备开发认证V2.0-3.轻量系统内核基础

目录 一、前言二、LiteOS-M系统概述三、内核框架3.1、CMSIS 和 POSIX 整体架构3.2、LiteOS-M内核启动流程 四、内核基础4.1、任务管理4.2、时间管理(待续)4.3、中断管理(待续)4.4、软件定时器(待续) 五、内存管理5.1、静态内存(待续)5.2、动态内存(待续) 六、内核通信机制6.1、…

深度学习(15)--PyTorch构建卷积神经网络

目录 一.PyTorch构建卷积神经网络(CNN)详细流程 二.graphviz torchviz使PyTorch网络可视化 2.1.可视化经典网络vgg16 2.2.可视化自己定义的网络 一.PyTorch构建卷积神经网络(CNN)详细流程 卷积神经网络&#xff08;Convolutional Neural Networks&#xff09;是一种深度学…

每日一题 力扣993.二叉树的堂兄弟节点

993. 二叉树的堂兄弟节点 题目描述&#xff1a; 在二叉树中&#xff0c;根节点位于深度 0 处&#xff0c;每个深度为 k 的节点的子节点位于深度 k1 处。 如果二叉树的两个节点深度相同&#xff0c;但 父节点不同 &#xff0c;则它们是一对堂兄弟节点。 我们给出了具有唯一值…

实现RBAC

一、菜单权限的控制 左边侧边栏的菜单显示是来自于userlnfoStore.menuRoutes&#xff0c;当前进行打印&#xff0c;得到的内容其实就是staticRoutes静态路由表定义的路由数组对象;最终staticRoutes(静态路由)、allAsyncRoutes(动态路由)、anyRoute(任意路由)需要进行一次整合、…

spring boot和spring cloud项目中配置文件application和bootstrap中的值与对应的配置类绑定处理

在前面的文章基础上 https://blog.csdn.net/zlpzlpzyd/article/details/136065211 加载完文件转换为 Environment 中对应的值之后&#xff0c;接下来需要将对应的值与对应的配置类进行绑定&#xff0c;方便对应的组件取值处理接下来的操作。 对应的配置值与配置类绑定通过 Con…

单片机的认识

单片机的定义 先简单理解为&#xff1a; 在一片集成电路芯片上集成了微处理器&#xff08;CPU &#xff09;存储器&#xff08;ROM和RAM&#xff09;、I/O 接口电路&#xff0c;构成单芯片微型计算机&#xff0c;即为单片机。 把组成微型计算机的控制器、运算器、存储器、输…

MQTT 服务器(emqx)搭建及使用

推荐阅读&#xff1a; MQTT 服务器(emqx)搭建及使用 - 哔哩哔哩 (bilibili.com) 一、EMQX 服务器搭建 1、下载EMQX https://www.emqx.com/zh/try?productbroker 官方中文手册&#xff1a; EMQX Docs 2、安装使用 1、该软件为绿色免安装版本&#xff0c;解压缩后即安装完…

重写Sylar基于协程的服务器(7、TcpServer HttpServer的设计与实现)

重写Sylar基于协程的服务器&#xff08;7、TcpServer & HttpServer的设计与实现&#xff09; 重写Sylar基于协程的服务器系列&#xff1a; 重写Sylar基于协程的服务器&#xff08;0、搭建开发环境以及项目框架 || 下载编译简化版Sylar&#xff09; 重写Sylar基于协程的服务…

高考志愿填报模拟系统的功能和技术总结

一、金秋志愿高考志愿填报系统主要功能&#xff1a; 用户注册与登录&#xff1a;允许学生和家长注册账号&#xff0c;使用注册的账号登录系统。 个人信息管理&#xff1a;允许用户查看、修改个人信息&#xff0c;如姓名、性别、联系方式等。 高考成绩输入&#xff1a;学生输…

删除和清空Hive外部表数据

外部表和内部表区别 未被external修饰的是内部表&#xff08;managed table&#xff09;&#xff0c;被external修饰的为外部表&#xff08;external table&#xff09;&#xff1b; 区别&#xff1a; 内部表数据由Hive自身管理&#xff0c;外部表数据由HDFS管理&#xff1b; …

STM32——LCD(1)认识

目录 一、初识LCD 1. LCD介绍 2. 显示器的分类 3. 像素 4. LED和OLED显示器 5. 显示器的基本参数 &#xff08;1&#xff09;像素 &#xff08;2&#xff09;分辨率 &#xff08;3&#xff09;色彩深度 &#xff08;4&#xff09;显示器尺寸 &#xff08;5&#xff…

Redis篇之缓存雪崩

一、什么的缓存雪崩 缓存雪崩&#xff1a;在同一时间段大量的缓存key同时失效或者redis服务宕机&#xff0c;导致大量请求到达数据库给数据库带来巨大压力&#xff0c;可能导致数据库崩了。 二、应该怎么解决 1.给不同的Key的TTL添加随机值 2.利用Redis集群提高服务的可用性 3…