展开
拓展 关闭
订阅号推广码
GitHub
视频
公告栏 关闭

Angular入门

构建项目

// 安装angular-cli
npm install -g @angular/cli
// 创建项目
ng new angular01
// 是否安装路由
// 选择(css/less/sass)
// 进入项目
cd angular01
// 安装依赖
npm install
// 启动并打开浏览器
ng serve -o
  • 导入vscode后,安装angular提示的插件

目录结构

  • 第一层文件
node_modules 第三方依赖包存放目录
e2e 端到端的测试目录 用来做自动测试的
src 应用源代码目录
.angular-cli.json Angular命令行工具的配置文件。后期可能会去修改它,引一些其他的第三方的包 比如jquery等
karma.conf.js karma是单元测试的执行器,karma.conf.js是karma的配置文件
package.json 这是一个标准的npm工具的配置文件,这个文件里面列出了该应用程序所使用的第三方依赖包。实际上我们在新建项目的时候,等了半天就是在下载第三方依赖包。下载完成后会放在node_modules这个目录中,后期我们可能会修改这个文件。
protractor.conf.js 也是一个做自动化测试的配置文件
README.md 说明文件
tslint.json 是tslint的配置文件,用来定义TypeScript代码质量检查的规则,不用管它
  • src目录
app目录 包含应用的组件和模块,我们要写的代码都在这个目录
assets目录 资源目录,存储静态资源的 比如图片
environments目录 环境配置。Angular是支持多环境开发的,我们可以在不同的环境下(开发环境,测试环境,生产环境)共用一套代码,主要用来配置环境的
index.html 整个应用的根html,程序启动就是访问这个页面
main.ts 整个项目的入口点,Angular通过这个文件来启动项目
polyfills.ts 主要是用来导入一些必要库,为了让Angular能正常运行在老版本下
styles.css 主要是放一些全局的样式
tsconfig.app.json TypeScript编译器的配置,添加第三方依赖的时候会修改这个文件
tsconfig.spec.json 不用管
test.ts 也是自动化测试用的
typings.d.ts 不用管
  • app目录
src\app\app.component.html // 根组件
src\app\app.component.less // 根组件
src\app\app.component.ts // 根组件
src\app\app.module.ts // 根模块
  • 根模块app.module.ts
// angular核心模块
import { NgModule } from '@angular/core';
// 浏览器解析模块
import { BrowserModule } from '@angular/platform-browser';
// 路由模块
import { AppRoutingModule } from './app-routing.module';
// 导入app目录下的三个根组件:app.component.html,app.component.less,app.component.ts
import { AppComponent } from './app.component';
@NgModule({
declarations: [
AppComponent // 将上面导入的根组件注册为自己的组件
],
imports: [ // 配置依赖的其他模块
BrowserModule, // 类似于导入挂载
AppRoutingModule
],
providers: [],
bootstrap: [AppComponent] // 指定根组件来启动应用
})
export class AppModule { } // 暴露当前接口,根模块可不用暴露
  • 根组件app.component.ts
// 导入angular的核心
import { Component } from '@angular/core';
@Component({
selector: 'app-root', // 导入该组件的名称
templateUrl: './app.component.html', // 导入根组件html
styleUrls: ['./app.component.less'] // 导入根组件less
})
export class AppComponent { // 定义根组件的属性
title = 'angular01';
}

新建子组件

  • 初始化项目:删除app.component.html中的默认代码
<style>
</style>
<div>
这是根组件
</div>
<router-outlet></router-outlet>
  • 新建子组件
// 提示
ng g
// 在app/components/路径下新建组件news
ng g component components/news
// 之后就会在components路径下生成news文件夹,整个文件夹都是news组件
// 在根模块app.module.ts中会自动引入news组件
import { NewsComponent } from './components/news/news.component';
@NgModule({
declarations: [
NewsComponent // 将上面导入的根组件注册为自己的组件
]
})
// 在子组件news.component.ts中
@Component({
selector: 'app-news', // 当前组件名称
templateUrl: './news.component.html',
styleUrls: ['./news.component.less']
})
// 在根组件中使用news组件
<app-news></app-news>

模板合成

  • 数据绑定
// 在news.component.ts中绑定一个title
export class NewsComponent implements OnInit {
// 修饰符类型:public、private、protected
public title: string="我是一个新闻组件";
// 生成一个对象
public userinfo: Object ={
name:"张山",
age:20
};
// 在构造函数中传入属性的值
constructor() {
this.title="这是改变后的值";
}
}
// 在news.component.html中使用
<span>{{title}}</span>
<span>{{userinfo}}</span>
  • 属性绑定
// news.component.ts中
export class NewsComponent implements OnInit {
public baidu: string="www.baidu.com";
}
// news.component.html中
<h2>属性绑定</h2>
<p title="这是title">baidu_0</p>
<p [title]="baidu">baidu_1</p><br>
<a [href]="baidu">baidu_2</a><br>
  • html绑定
// news.component.ts中
export class NewsComponent implements OnInit {
// html绑定
public content: string="<h2>这是一段文本!!</h2>"
public content2:string=`
<span>title</span>
<p>p2</p>
`
}
// news.component.html中
<h2>绑定html</h2>
<p>{{content}}</p>
<p [innerHTML]="content"></p>
<p [innerHTML]="content2"></p>
  • 简单运算
<h2>简单运算</h2>
<p>333+555={{333+555}}</p>
  • 数据循环
export class NewsComponent implements OnInit {
// 数组循环
public arr=["ass", "dsdsa", "asdf"];
public list: string[]=["asdfasd", "asdfasd", "asdfasdf", "adsfasd"];
public items:Array<string>=["asd", "asdf", "1324"];
public userList:object[]=[{username:"user", password: "123456"},{username: "user2", password: "1234567"}]
}
<h2>数据循环</h2>
<ul>
<li *ngFor="let item of arr">
{{item}}
</li>
</ul>
<p>-------</p>
<ul>
<li *ngFor="let item of list">
{{item}}
</li>
</ul>
<p>-------</p>
<ul>
<li *ngFor="let item of items">
{{item}}
</li>
</ul>
<p>-------</p>
<ul></ul>
<li *ngFor="let item of userList">
{{item.username}}
</li>

组件合成

  • 新建子组件home,以下操作在home组件中完成
  • 引入图片
// ts组件中指定图片地址
public picUrl:string="https://tse4-mm.cn.bing.net/th/id/OIP-C.uPx-FbZ4nf2U05kCoJ7_1QHaE8?w=299&h=197&c=7&r=0&o=5&dpr=1.24&pid=1.7";
// html组件中
<span><img src="assets/images/OIP-C.jpg"></span><br>
<p>引入图片方式二</p>
<img [src]="picUrl">
  • 循环数据时,显示索引
// ts组件中指定数组
public list: any[]=[
{"title":'新闻一'},{"title":'新闻二'},{"title":'新闻三'}
]
// html组件中
<ul>
<li *ngFor="let item of list; let key=index">
{{key}}----{{item.title}}
</li>
</ul>
  • ngif条件判断
public flag:boolean=false;
// html组件中
<div *ngIf="flag">
<img src="assets/images/OIP-C.jpg">
</div>
<div *ngIf="!flag">
<img [src]="picUrl">
</div>
  • ngSwitch条件判断
// ts组件中
public orderStatus:number=1;
// html组件中
<span [ngSwitch]="orderStatus">
<p *ngSwitchCase="1">已经支付</p>
<p *ngSwitchCase="2">未支付</p>
<p *ngSwitchCase="3">已收货</p>
<p *ngSwitchCase="4">为收货</p>
</span>
  • ngclass样式绑定
// ts组件中
public flag:boolean=false;
// less组件中
.red{
color: red;
}
.blue{
color: blue;
}
.yellow{
color: yellow;
}
// html组件中
<!-- 类名class1为true表示使用该样式 -->
<div [ngClass]="{'class1':true, 'class2':false}"></div>
<!-- flag为home.component.ts中定义的boolean类型 -->
<div [ngClass]="{'class3':flag, 'class4':!flag}"></div>
<ul>
<li *ngFor="let item of list; let key=index;" [ngClass]="{'red': key==1, 'blue': key==2}">
{{key}}----{{item.title}}
</li>
</ul>
  • 样式绑定ngStyle
// ts 组件中
public attr: string='red';
// less 组件中
.red{
color: red;
}
// html 组件中
<p [ngStyle]="{'color':'red'}">这是一段文本</p>
<p [ngStyle]="{'color':attr}">这是一段文本2</p>
  • 管道:转换格式
// ts组件中
public today: any=new Date();
// html 组件中
<span>未转换 -> </span>{{today}}
<br>
<span>转换后 -> </span>{{today | date:'yyyy-mm-dd HH-mm-ss'}}
  • 点击事件
// ts组件中
// 事件
run(){
alert("hello!!");
}
// 获取
getData(){
alert(this.picUrl);
}
public title: string="asdf";
// 设置数据
setData(){
this.title="sadfasdf"
}
// 点击获取事件对象
runEvent(e){
var dom: any = e.target;
dom.style.color='red';
dom.style.height='200px';
}
<button (click)="run()">点击1</button>
<br>
<!-- 点击时获取数据 -->
<button (click)="getData()">点击1</button>
<br>
<!-- 点击时改变数据 -->
data:{{title}}
<button (click)="setData()">点击2</button>
<br>
<br>
<button (click)="runEvent($event)">点击获取事件对象</button>
  • 键盘事件
// ts组件中
keyDown(e){
if(e.keyCode==13){
console.log("按了回车")
}else{
console.log(e.target.value)
}
}
// 键盘松开事件
keyUp(e){
if(e.keyCode==13){
console.log(e.target.value)
console.log("按了回车")
}
}
// html组件中
键盘按下<input type="text" (keydown)="keyDown($event)"/>
键盘松开<input type="text" (keyup)="keyUp($event)">
  • 报错
Error: src/app/components/home/home.component.ts:50:11 - error TS7006: Parameter 'e' implicitly has an 'any' type.
50 keyDown(e){
  • 解决方案

  • 双向数据绑定需在根组件中引入FormsModule

// app.module.ts中导入form组件
import { FormsModule } from '@angular/forms';
@NgModule({
imports: [ // 配置依赖的其他模块
FormsModule
],
})
// ts组件中
public keywords: any;
// html组件中
<input type="text" [(ngModel)]='keywords'/>
<br>{{keywords}}
  • 报错
Property 'keywords' does not exist on type 'HomeComponent'.
76 <br>{{keywords}}
  • 错误原因:ts中keywords没有指定类型

表单双向绑定

  • 新建子组件form
  • ts组件
export class FormComponent implements OnInit {
// 表单数据绑定
public people: any = {
username: '',
sex: '1',
cityList: ['shanghai', 'beijing', 'chongqing'],
city: 'shanghai',
hobby: [
{title: 'lanqiu', checked: false},{title: 'cang', checked: false},{title: 'tiao', checked: false}
],
mark: ''
}
}
  • html组件
<p>文本框双向绑定</p>
<input type="text" [(ngModel)]="people.username">
<br>{{people.username}}
<p>单选框双向绑定</p>
<input type="radio" value="1" [(ngModel)]="people.sex">
<input type="radio" value="2" [(ngModel)]="people.sex"><br>
<br>{{people.sex}}
<p>下拉列表双向绑定</p>
<select [(ngModel)]="people.city">
<option *ngFor="let item of people.cityList" [value]="item">{{item}}</option>
</select>
<br>{{people.city}}
<p>多选框双向数据绑定</p>
<span *ngFor="let item of people.hobby, let key=index">
<input type="checkbox" id="check+'key'" [(ngModel)]="item.checked">{{item.title}}--{{item.checked}}
</span>
<br>
<p>文本域双向数据绑定</p>
<textarea [(ngModel)]="people.mark"></textarea>
<br>{{people.mark}}

搜索框历史功能

  • 新建子组件search
  • html组件
<div class="search">
<!-- 文本框双向绑定 -->
<input type="text" [(ngModel)]="keyword" placeholder="Search">
<!-- 点击按钮添加到历史记录 -->
<button type="button" (click)="doSearch()">search</button>
<br>
<div class="historyList">
<!-- 遍历循环历史记录,点击删除事件 -->
<li *ngFor="let item of historyList; let key=index;">
{{item}}<span (click)="deleteHistory(key)" class="del">X</span>
</li>
</div>
</div>
  • ts组件
// 与搜索框双向绑定
public keyword: string;
// 历史记录的数组
public historyList: any[] = [];
// 判断历史记录中是否存在,添加到历史记录
doSearch(){
if(this.historyList.indexOf(this.keyword)==-1){
this.historyList.push(this.keyword);
}
this.keyword='';
}
// 删除历史记录
deleteHistory(key){
//alert(key);
this.historyList.splice(key, 1);
}

事项清单

  • 新建子组件todolist
  • html组件
<div class="todolist">
<!-- 文本框双向绑定,键盘事件添加历史记录 -->
<input type="text" placeholder="Search" [(ngModel)]="keyword" (keyup)="doAdd($event)">
<hr>
<div class="historyList">
<p>待办事项</p>
<div class="history"></div>
<!-- 遍历历史记录,hidden表示status=0时显示 -->
<div class="his" *ngFor="let item of todolist; let key=index;" [hidden]="item.status==1">
<!-- 双向绑定状态status -->
<input type="checkbox" [(ngModel)]="item.status" class="inp">
{{item.title}}
<span class="del" (click)="delete(key)">x</span>
</div>
</div>
</div>
<div class="todos">
<p>已完成事项</p>
<div class="todo2">
<!-- 遍历历史记录数组,hidden表示status为1时显示;删除记录的方法 -->
<div class="todo" *ngFor="let item of todolist; let key=index;" [hidden]="item.status==0">
<!-- 双向绑定单条历史记录的状态 -->
<input type="checkbox" [(ngModel)]="item.status" class="inp">
{{item.title}}
<span class="del" (click)="delete2(key)">x</span>
</div>
</div>
</div>
</div>
  • ts组件
export class TodolistComponent implements OnInit {
// 双向绑定搜索框
public keyword: string;
// 默认的历史记录
public todolist: any[] = [{title: 'vuejs', status: 0}];
// 添加历史记录的方法
doAdd(e){
if(e.keyCode==13){
this.todolist.push({title: this.keyword, status: 0});
this.keyword='';
}
}
// 删除历史记录的方法
delete(key){
this.todolist.splice(key,1);
}
// 删除历史记录的方法
delete2(key){
this.todolist.splice(key,1);
}
}

angular服务

  • angular是基于组件化的开发,一个组件不能调用另一个组件中方法,这时需要把公共的方法或数据放到angular服务中,这样所有的组件都可以调用服务中的方法和数据,类型于vuex
  • 使用步骤1(不推荐):
// 1. 创建服务
ng g service services/storage
// 2. 在根模块app.module.ts中引入并注册
import { StorageService } from './service/storage.service';
@NgModule({
providers: [StorageService],
})
// 3. 在创建的服务中编写公共的方法
export class StorageService {
get(){
console.log("这是一个公共方法!");
}
}
// 4. 测试:在子组件search中使用;如果要在某个子组件中使用同样需映入并创建服务实例
import { StorageService } from '../../service/storage.service';
var storage = new StorageService;
export class SearchComponent implements OnInit {
constructor() {
// 测试服务中的公共方法
console.log(storage)
}
}
  • 使用步骤2(官方推荐):
/// 1. 创建服务
ng g service services/storage
// 2. 在根模块app.module.ts中引入并注册
import { StorageService } from './service/storage.service';
@NgModule({
providers: [StorageService],
})
// 3. 在创建的服务中编写公共的方法
export class StorageService {
get(){
console.log("这是一个公共方法!");
}
}
// 4. 测试:在子组件search中使用;如果要在某个子组件中使用同样需映入并创建服务实例
import { StorageService } from '../../service/storage.service';
export class SearchComponent implements OnInit {
constructor( public storage: StorageService) { // 相当于上面的new服务实例
let s= this.storage.test();
console.log(s);
}
}

案例:服务中编写公共方法

  • angular服务中编写方法
export class StorageService {
// 事项清单添加数据到本地缓存
set(key: string, value: any){
localStorage.setItem(key, JSON.stringify(value));
}
// 从本地缓存中获取数据
get(key: string){
return localStorage.getItem(key);
}
// 删除本地缓存中的数据
remove(key: string){
localStorage.removeItem(key);
}
}
  • 在search.component.ts中使用
  • 在ts组件中ngOnInit方法会在每次刷新时触发
import { StorageService } from '../../service/storage.service';
// 1.引入
export class SearchComponent implements OnInit {
ngOnInit(): void {
console.log("刷新页面时会触发该周期函数")
// 2.每次刷新时都会从本地缓存中获取数据
var searchlist: any= this.storage.get('searchlist');
if(searchlist){
this.historyList=searchlist;
console.log("获取成功")
}
// console.log(this.storage.get('searchlist'))
// let searchlist: any =this.storage.get('searchlist');
// this.historyList.push(searchlist);
}
doSearch(){
if(this.historyList.indexOf(this.keyword)==-1){
this.historyList.push(this.keyword);
// 3.添加历史记录到本地缓存
this.storage.set('searchlist', this.historyList);
console.log("添加成功")
}
this.keyword='';
}
}

dom节点操作

  • 方式一:
// html组件中有一个box节点
<div id="box">这是一个盒子!</div>
// ts组件中通过原生的js方法操作
ngOnInit(): void {
let box: any= document.getElementById('box');
console.log("dom" + box.innerHTML);
box.style.color="blue";
}
  • 方式二:
// html组件中的dom节点中有angular指令
<div id="box2" *ngIf="flag">这是一个盒子!</div>
// ts组件中,在ngAfterViewInit函数中操作,注意大小写,否则不起作用
ngAfterViewInit(): void {
let box2: any= document.getElementById('box2');
console.log("dom" + box2.innerHTML);
box2.style.color="red";
}
  • 方式三:使用viewchild
// 1. html组件中自定义节点名称box3
<div #box3 *ngIf="flag" >这是一个盒子!</div>
// 2. ts组件中操作,引入viewchild
import { ViewChild } from '@angular/core';
export class DomComponent implements OnInit {
public flag: boolean = true;
// 3. 使用viewchild,定义组件名称
@ViewChild('box3') box3: any;
ngAfterViewInit(): void {
// 4. 使用
console.log("box3" + this.box3.nativeElement);
this.box3.nativeElement.style.color="red";
}
}
  • 使用viewChild调用另一个组件中的方法
// 例如dom组件调用form组件中的方法
// 1. 在dom组件的html中引入form组件,并指定名称
<app-form #form></app-form>
// 2. 在dom组件的ts组件中操作,引入viewchild
import { ViewChild } from '@angular/core';
export class DomComponent implements OnInit {
// 3. 使用viewchild,定义组件名称
@ViewChild('form') form: any;
ngAfterViewInit(): void {
// 4. 调用form组件中的方法
console.log("form -> " + this.form.run());
}
}

实现一个侧边栏

  • 新建组件transition
// 编写html
<div id="content">
内容区<br>
<button (click)="showAside()">弹出侧边栏</button>
<button (click)="hiddenAside()">隐藏侧边栏</button>
</div>
<div id="aside">
侧边栏
</div>
// 全局样式
body{
width: 100%;
overflow-x: hidden;
}
// ts组件中
export class TransitionComponent implements OnInit {
showAside(){
var asideDom = document.getElementById('aside');
asideDom.style.transform = "translate(0,0)";
}
hiddenAside(){
var asideDom = document.getElementById('aside');
asideDom.style.transform = "translate(100%,0)";
}
}
posted @   DogLeftover  阅读(20)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 推荐几款开源且免费的 .NET MAUI 组件库
· 实操Deepseek接入个人知识库
· 易语言 —— 开山篇
· 【全网最全教程】使用最强DeepSeekR1+联网的火山引擎,没有生成长度限制,DeepSeek本体
历史上的今天:
2022-09-22 使用栈实现综合计算器
2022-09-22
2022-09-22 约瑟夫问题(二)
2022-09-22 约瑟夫问题(一)
2022-09-22 双向链表
2022-09-22 单链表(三)
2022-09-22 单链表(二)
点击右上角即可分享
微信分享提示

目录导航