JavaScript 第26章:Angular 基础

Angular是由Google维护的一个开源框架,用于构建Web应用程序。Angular提供了一套完整的解决方案来构建动态Web应用,它利用TypeScript语言来编写组件,并提供了一系列内置指令和管道来简化前端开发工作。

Angular 概述

Angular是一个完整的MVC(Model-View-Controller)框架,它旨在简化Web应用的开发流程,通过模块化的方式组织代码,提供依赖注入系统,以及丰富的指令和管道等功能。Angular支持组件化开发,这意味着你可以把应用分割成小的、可重用的组件。

组件与服务

在Angular中,组件是构成应用的基本单元。每个组件都由三个部分组成:一个类(组件类),一个HTML模板,以及一个样式表。组件类负责业务逻辑,模板定义了组件的视图,样式表则负责组件的外观。

服务则是封装了应用逻辑的部分,通常用来处理数据获取、认证等跨组件的工作。服务可以通过依赖注入(DI)机制在组件中使用。

模板语法

Angular模板语法允许你在HTML中嵌入TypeScript代码,以便实现动态内容。你可以使用*ngFor来遍历数据集合,使用*ngIf来控制元素的显示隐藏,以及其他内置指令来控制DOM元素的行为。

数据绑定

Angular支持多种类型的数据绑定:

  • 属性绑定:将组件类中的属性值绑定到HTML元素的属性上,如[attr.class]="className"
  • 事件绑定:将事件(如点击)与组件类中的方法绑定起来,如(click)="onClick($event)"
  • 双向数据绑定:通过[(ngModel)]指令来同步HTML控件和组件类中的属性。

实战案例:Angular入门应用

下面是一个简单的Angular入门应用,该应用将展示一个待办事项列表,并允许用户添加和删除待办事项。

创建Angular应用

首先,你需要安装Angular CLI来创建一个新的Angular项目:

npm install -g @angular/cli
ng new my-todo-app
cd my-todo-app
修改AppComponent

接下来,修改src/app/app.component.ts文件,创建一个简单的待办事项列表。

import { Component } from '@angular/core';@Component({selector: 'app-root',templateUrl: './app.component.html',styleUrls: ['./app.component.css']
})
export class AppComponent {title = 'my-todo-app';todos: string[] = [];addTodo(todo: string) {this.todos.push(todo);}removeTodo(index: number) {this.todos.splice(index, 1);}
}
修改AppComponent模板

接着,在src/app/app.component.html中添加模板代码:

<h1>{{ title }}</h1>
<input [(ngModel)]="newTodo" placeholder="输入待办事项">
<button (click)="addTodo(newTodo)">添加</button>
<ul><li *ngFor="let todo of todos; let i = index">{{ todo }}<button (click)="removeTodo(i)">删除</button></li>
</ul>

注意,这里使用了ngModel来进行双向数据绑定,你需要导入FormsModule来启用模板驱动的表单。

导入FormsModule

src/app/app.module.ts中导入FormsModule

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms'; // 导入FormsModuleimport { AppComponent } from './app.component';@NgModule({declarations: [AppComponent],imports: [BrowserModule,FormsModule // 添加FormsModule],providers: [],bootstrap: [AppComponent]
})
export class AppModule { }
启动应用

最后,运行以下命令启动应用:

ng serve

打开浏览器访问 http://localhost:4200,你应该可以看到一个简单的待办事项列表应用。

这个例子展示了如何使用Angular创建一个简单的Web应用,包括如何定义组件、使用模板语法进行数据绑定以及处理用户输入。通过这些基础知识,你可以开始构建更复杂的应用程序了。

接下来,让我们继续深入探讨Angular的基础知识,并通过扩展之前的待办事项应用来进一步演示Angular的一些核心特性。

更深入地了解Angular特性

依赖注入(Dependency Injection, DI)

Angular的依赖注入系统允许你轻松地管理和传递依赖项。依赖注入可以让你在组件内部声明它所需要的服务或其他对象,而不必关心这些对象是如何被创建的。Angular会负责创建这些依赖并将它们注入到需要的地方。

指令(Directives)

除了Angular内置的指令(如*ngFor, *ngIf等),你还可以创建自定义指令来扩展HTML的行为。自定义指令可以用来改变DOM元素的行为、样式,甚至可以响应用户交互。

管道(Pipes)

管道是在Angular模板中使用的特殊函数,用于转换一个值。例如,可以使用内置的日期管道{{ date | date:'short' }}来格式化日期字符串。

扩展待办事项应用

现在,让我们通过添加一些新的功能来扩展之前的待办事项应用,比如使用服务来管理待办事项列表、使用自定义指令来高亮显示完成的任务、以及使用管道来格式化日期。

创建服务来管理待办事项

首先,我们需要创建一个服务来管理待办事项列表。使用Angular CLI来创建一个服务:

ng generate service todo

然后编辑src/app/todo.service.ts

import { Injectable } from '@angular/core';@Injectable({providedIn: 'root'
})
export class TodoService {private todos: { text: string, completed: boolean, createdAt: Date }[] = [];constructor() { }addTodo(text: string): void {this.todos.push({ text, completed: false, createdAt: new Date() });}removeTodo(index: number): void {this.todos.splice(index, 1);}getTodos(): { text: string, completed: boolean, createdAt: Date }[] {return this.todos;}toggleTodo(index: number): void {this.todos[index].completed = !this.todos[index].completed;}
}
在组件中使用服务

接下来,我们需要在AppComponent中使用TodoService来管理待办事项列表:

import { Component } from '@angular/core';
import { TodoService } from './todo.service';@Component({selector: 'app-root',templateUrl: './app.component.html',styleUrls: ['./app.component.css']
})
export class AppComponent {title = 'my-todo-app';newTodo = '';constructor(private todoService: TodoService) { }addTodo() {this.todoService.addTodo(this.newTodo);this.newTodo = '';}removeTodo(index: number) {this.todoService.removeTodo(index);}toggleTodo(index: number) {this.todoService.toggleTodo(index);}getTodos() {return this.todoService.getTodos();}
}
创建自定义指令

我们可以创建一个自定义指令来高亮显示已完成的任务:

import { Directive, HostBinding, Input } from '@angular/core';@Directive({selector: '[appHighlight]'
})
export class HighlightDirective {@Input() appHighlight: boolean;@HostBinding('class.completed') get highlight() {return this.appHighlight;}
}

注册自定义指令:

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
import { HighlightDirective } from './highlight.directive';
import { TodoService } from './todo.service';@NgModule({declarations: [AppComponent,HighlightDirective],imports: [BrowserModule,FormsModule],providers: [TodoService],bootstrap: [AppComponent]
})
export class AppModule { }
更新模板

更新app.component.html来使用自定义指令和管道:

<h1>{{ title }}</h1>
<input [(ngModel)]="newTodo" placeholder="输入待办事项">
<button (click)="addTodo()">添加</button>
<ul><li *ngFor="let todo of getTodos(); let i = index" appHighlight="todo.completed"><input type="checkbox" [(ngModel)]="todo.completed"><span [ngClass]="{ completed: todo.completed }">{{ todo.text }}</span><small>{{ todo.createdAt | date }}</small><button (click)="removeTodo(i)">删除</button></li>
</ul>

总结

通过这些扩展,我们不仅增强了待办事项应用的功能,还引入了Angular的服务、自定义指令以及管道等特性。这些特性使得Angular成为构建复杂Web应用程序的理想选择。希望这些示例能够帮助你更好地理解Angular,并鼓励你在自己的项目中运用这些知识。

我们将继续扩展待办事项应用,并探讨Angular的一些其他重要特性,如路由管理、表单处理、以及如何使用Angular Material来美化应用界面。

Angular路由管理

为了使待办事项应用更加实用,我们可以添加一些额外的页面,如登录页面、用户信息页面等,并使用Angular路由来管理这些页面之间的导航。

创建路由

首先,我们需要创建一个新的组件作为登录页面,并配置路由。

  1. 使用Angular CLI创建一个新的组件:

    ng generate component login
    
  2. 编辑login.component.html,创建一个简单的登录表单:

    <h1>登录</h1>
    <form (ngSubmit)="onLogin()"><div><label for="username">用户名:</label><input id="username" type="text" [(ngModel)]="username" name="username" required></div><div><label for="password">密码:</label><input id="password" type="password" [(ngModel)]="password" name="password" required></div><button type="submit">登录</button>
    </form>
    
  3. 编辑login.component.ts

    import { Component } from '@angular/core';@Component({selector: 'app-login',templateUrl: './login.component.html',styleUrls: ['./login.component.css']
    })
    export class LoginComponent {username = '';password = '';onLogin() {// 登录逻辑}
    }
    
  4. 配置路由:

    编辑app-routing.module.ts

    import { NgModule } from '@angular/core';
    import { RouterModule, Routes } from '@angular/router';
    import { AppComponent } from './app.component';
    import { LoginComponent } from './login/login.component';const routes: Routes = [{ path: '', component: AppComponent },{ path: 'login', component: LoginComponent }
    ];@NgModule({imports: [RouterModule.forRoot(routes)],exports: [RouterModule]
    })
    export class AppRoutingModule { }
    
  5. 更新app.component.html以包含路由出口:

    <router-outlet></router-outlet>
    

表单处理

在上面的登录页面中,我们使用了模板驱动的表单。Angular还支持反应式的表单处理,这对于更复杂的表单场景非常有用。下面是一个使用反应式表单的例子:

使用反应式表单
  1. 更新login.component.ts以使用反应式表单:

    import { Component, OnInit } from '@angular/core';
    import { FormBuilder, FormGroup, Validators } from '@angular/forms';@Component({selector: 'app-login',templateUrl: './login.component.html',styleUrls: ['./login.component.css']
    })
    export class LoginComponent implements OnInit {loginForm: FormGroup;constructor(private fb: FormBuilder) { }ngOnInit() {this.loginForm = this.fb.group({username: ['', Validators.required],password: ['', Validators.required]});}onLogin() {if (this.loginForm.valid) {// 登录逻辑}}
    }
    
  2. 更新login.component.html以使用formControlName

    <form [formGroup]="loginForm" (ngSubmit)="onLogin()"><div><label for="username">用户名:</label><input id="username" type="text" formControlName="username" required></div><div><label for="password">密码:</label><input id="password" type="password" formControlName="password" required></div><button type="submit">登录</button>
    </form>
    

使用Angular Material

Angular Material 提供了许多预构建的组件,可以快速美化你的应用界面。下面我们来添加一些Material组件来改善待办事项应用的外观。

  1. 安装Angular Material:

    ng add @angular/material
    
  2. 选择一个合适的主题颜色方案,并在全局样式文件中导入:

    /* styles.css */
    @import '~@angular/material/prebuilt-themes/deeppurple-amber.css';
    
  3. app.module.ts中导入所需的Material模块:

    import { NgModule } from '@angular/core';
    import { BrowserModule } from '@angular/platform-browser';
    import { FormsModule } from '@angular/forms';
    import { AppComponent } from './app.component';
    import { HighlightDirective } from './highlight.directive';
    import { TodoService } from './todo.service';
    import { RouterModule } from '@angular/router';
    import { AppRoutingModule } from './app-routing.module';
    import { LoginComponent } from './login/login.component';
    import { MatInputModule } from '@angular/material/input';
    import { MatButtonModule } from '@angular/material/button';
    import { MatCheckboxModule } from '@angular/material/checkbox';
    import { MatListModule } from '@angular/material/list';@NgModule({declarations: [AppComponent,HighlightDirective,LoginComponent],imports: [BrowserModule,FormsModule,RouterModule,AppRoutingModule,MatInputModule,MatButtonModule,MatCheckboxModule,MatListModule],providers: [TodoService],bootstrap: [AppComponent]
    })
    export class AppModule { }
    
  4. 更新app.component.html以使用Material组件:

    <mat-toolbar color="primary"><span>{{ title }}</span>
    </mat-toolbar>
    <mat-list><mat-list-item *ngFor="let todo of getTodos(); let i = index"><mat-checkbox [(ngModel)]="todo.completed"></mat-checkbox><mat-list-item-content><span [ngClass]="{ completed: todo.completed }">{{ todo.text }}</span><small>{{ todo.createdAt | date }}</small></mat-list-item-content><button mat-button (click)="removeTodo(i)">删除</button></mat-list-item>
    </mat-list>
    
  5. 更新login.component.html以使用Material组件:

    <mat-toolbar color="primary"><span>登录</span>
    </mat-toolbar>
    <form [formGroup]="loginForm" (ngSubmit)="onLogin()"><mat-form-field appearance="fill"><mat-label>用户名</mat-label><input matInput formControlName="username" required></mat-form-field><mat-form-field appearance="fill"><mat-label>密码</mat-label><input matInput type="password" formControlName="password" required></mat-form-field><button mat-raised-button color="primary" type="submit">登录</button>
    </form>
    

总结

通过上述步骤,我们不仅增强了待办事项应用的功能,还引入了Angular的路由管理、表单处理以及Angular Material来提升应用的用户体验。这些特性使得Angular成为一个强大的框架,适用于构建高度交互性的Web应用程序。

好的,我们继续扩展待办事项应用,并进一步探讨Angular的一些其他特性,如状态管理、单元测试等。此外,我们还将讨论如何优化和重构代码,以确保应用的可维护性和可扩展性。

状态管理:使用NgRx

对于较大的应用来说,状态管理变得非常重要,特别是当多个组件需要共享状态时。Angular生态系统中,NgRx是一个流行的库,用于实现Redux模式的状态管理。下面我们将使用NgRx来管理待办事项的状态。

安装NgRx

首先,安装NgRx相关的包:

ng add @ngrx/store
ng add @ngrx/entity
创建State和Reducer

创建一个状态来存储待办事项列表,并定义一个reducer来处理状态更新。

  1. 创建一个store模块:

    ng generate module store --flat --module=app
    
  2. store模块中创建状态和reducer:

    // store/todo.state.ts
    export interface Todo {id: number;text: string;completed: boolean;createdAt: Date;
    }export interface State {todos: Todo[];
    }export const initialState: State = {todos: []
    };// store/todo.reducer.ts
    import { createReducer, on } from '@ngrx/store';
    import { addTodo, removeTodo, toggleTodo } from './todo.actions';export const todoReducer = createReducer(initialState,on(addTodo, (state, { todo }) => ({...state,todos: [...state.todos, todo]})),on(removeTodo, (state, { id }) => ({...state,todos: state.todos.filter(todo => todo.id !== id)})),on(toggleTodo, (state, { id }) => ({...state,todos: state.todos.map(todo =>todo.id === id ? { ...todo, completed: !todo.completed } : todo)}))
    );
    
  3. 创建Action文件:

    // store/todo.actions.ts
    import { createAction, props } from '@ngrx/store';export const addTodo = createAction('[Todo] Add Todo',props<{ todo: Todo }>()
    );export const removeTodo = createAction('[Todo] Remove Todo',props<{ id: number }>()
    );export const toggleTodo = createAction('[Todo] Toggle Todo',props<{ id: number }>()
    );
    
  4. store.module.ts中注册reducers:

    // store.module.ts
    import { NgModule } from '@angular/core';
    import { StoreModule } from '@ngrx/store';
    import { todoReducer } from './todo.reducer';@NgModule({imports: [StoreModule.forRoot({ todos: todoReducer })]
    })
    export class StoreModule { }
    
在组件中使用NgRx

接下来,我们需要在组件中使用NgRx来获取和更新状态。

  1. app.component.ts中使用select来获取状态:

    import { Component, OnInit } from '@angular/core';
    import { Store } from '@ngrx/store';
    import { addTodo, removeTodo, toggleTodo } from './store/todo.actions';
    import { selectTodos } from './store/todo.selectors';@Component({selector: 'app-root',templateUrl: './app.component.html',styleUrls: ['./app.component.css']
    })
    export class AppComponent implements OnInit {todos$ = this.store.select(selectTodos);newTodo = '';constructor(private store: Store) { }ngOnInit() {// 初始化逻辑}addTodo() {if (this.newTodo.trim()) {const newTodo = {id: Date.now(),text: this.newTodo,completed: false,createdAt: new Date()};this.store.dispatch(addTodo({ todo: newTodo }));this.newTodo = '';}}removeTodo(id: number) {this.store.dispatch(removeTodo({ id }));}toggleTodo(id: number) {this.store.dispatch(toggleTodo({ id }));}
    }
    
  2. 创建选择器来获取状态:

    // store/todo.selectors.ts
    import { createFeatureSelector, createSelector } from '@ngrx/store';
    import { State } from './todo.state';const selectTodoFeature = createFeatureSelector<State>('todos');export const selectTodos = createSelector(selectTodoFeature,state => state.todos
    );
    
更新模板

最后,更新app.component.html以反映状态变化:

<h1>{{ title }}</h1>
<input [(ngModel)]="newTodo" placeholder="输入待办事项">
<button (click)="addTodo()">添加</button>
<ul><li *ngFor="let todo of todos$ | async; let i = index"><mat-checkbox [(ngModel)]="todo.completed" (change)="toggleTodo(todo.id)"></mat-checkbox><span [ngClass]="{ completed: todo.completed }">{{ todo.text }}</span><small>{{ todo.createdAt | date }}</small><button mat-button (click)="removeTodo(todo.id)">删除</button></li>
</ul>

单元测试

Angular提供了Angular CLI工具来帮助编写单元测试。我们可以为组件和服务编写单元测试,以确保它们按预期工作。

创建单元测试
  1. AppComponent编写单元测试:

    ng generate component app --spec=false
    
  2. 编写测试代码:

    // app.component.spec.ts
    import { ComponentFixture, TestBed } from '@angular/core/testing';
    import { AppComponent } from './app.component';
    import { StoreModule, combineReducers } from '@ngrx/store';
    import { provideMockStore } from '@ngrx/store/testing';
    import { todoReducer } from './store/todo.reducer';
    import { addTodo } from './store/todo.actions';describe('AppComponent', () => {let component: AppComponent;let fixture: ComponentFixture<AppComponent>;beforeEach(async () => {await TestBed.configureTestingModule({declarations: [AppComponent],imports: [StoreModule.forRoot({ todos: todoReducer }),],providers: [provideMockStore()]}).compileComponents();});beforeEach(() => {fixture = TestBed.createComponent(AppComponent);component = fixture.componentInstance;fixture.detectChanges();});it('should create the app', () => {expect(component).toBeTruthy();});it('should dispatch addTodo action when addTodo is called', () => {const storeSpy = jasmine.createSpyObj('Store', ['dispatch']);component['store'] = storeSpy;component.addTodo();expect(storeSpy.dispatch).toHaveBeenCalledWith(addTodo({ todo: { id: expect.any(Number), text: '', completed: false, createdAt: expect.any(Date) } }));});
    });
    

总结

通过这些步骤,我们不仅增强了待办事项应用的功能,还引入了状态管理(NgRx)、单元测试等高级特性。这些特性使得Angular成为一个强大且灵活的框架,适合构建复杂的企业级Web应用程序。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/57821.shtml

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

相关文章

【C++】类和对象(附题)

目录 一、类的定义 1.1.类定义格式 1.2.访问限定符 1.3.类域 二、实例化 2.1.实例化概念 2.2.对象大小 三、this指针 附加题&#xff1a;&#xff08;增进对this指针的理解&#xff09; 1.下面程序编译运行结果是&#xff08;&#xff09; 2.下面程序编译运行结果是&…

昆虫种类识别数据集昆虫物种分类数据集YOLO格式VOC格式 目标检测 机器视觉数据集

一、数据集概述 数据集名称&#xff1a;10类昆虫图像数据集 数据集包含了多种农作物中常见的昆虫种类&#xff0c;包括军虫、豆蓟象、红蜘蛛、水稻瘿蚊、水稻卷叶蛾、水稻叶蝉、水稻水蚤、小麦薄翅薄翅蔗蝇、白背飞虱和黄稻螟。 1.1可能应用的领域 农业害虫监测与防控&#x…

基于 Python 的机器学习模型部署到 Flask Web 应用:从训练到部署的完整指南

目录 引言 技术栈 步骤一&#xff1a;数据预处理 步骤二&#xff1a;训练机器学习模型 步骤三&#xff1a;创建 Flask Web 应用 步骤四&#xff1a;测试 Web 应用 步骤五&#xff1a;模型的保存与加载 保存模型 加载模型并在 Flask 中使用 步骤六&#xff1a;Web 应用…

超越OpenAI GPT-4o,Yi-Lightning指南:中国AI大模型新巅峰

Yi-Lightning 是零一万物公司最新发布的旗舰模型&#xff0c;它在国际权威盲测榜单 LMSYS 上超越了硅谷知名 OpenAI GPT-4o-2024-05-13、Anthropic Claude 3.5 Sonnet&#xff0c;排名世界第六&#xff0c;中国第一&#xff0c;这标志着中国大模型首次实现超越 OpenAI GPT-4o 的…

node.js下载安装以及环境配置超详细教程【Windows版本】

node安装以及环境变量配置 Step1&#xff1a;选择版本进行安装Step2&#xff1a;安装Node.jsStep3&#xff1a;环境配置Step4&#xff1a;检查node.js是否成功安装Step5&#xff1a;npm修改下载镜像 Step1&#xff1a;选择版本进行安装 Node.js 安装包及源码下载地址为 Node.…

从0到1搭建大数据平台v1.0

文章目录 一、 文看懂大数据的技术生态1 大数据2 大数据核心技术2.1 HDFS分布式文件系统2.2 MapReduce计算引擎2.3 Hive数据仓库2.4 快一点吧 Spark/Flink2.5 Oozie / Azkaban任务调度2.6 yarn资源管理器2.7 数据采集 Sqoop / Flume / DataX/Kafka 3 从0到1搭建大数据平台 二、…

【Qt6聊天室项目】 主界面功能实现

1. 获取当前用户的个人信息 1.1 前后端逻辑分析&#xff08;主界面功能&#xff09; 主界面上所有的前后端交互逻辑相同&#xff0c;分析到加载会话列表后其余功能仅实现。 核心逻辑总结 异步请求-响应模型 客户端发起请求&#xff0c;向服务器发送包含会话ID的请求服务端处…

Map(一)

HashMap 和 Hashtable 的区别 线程是否安全&#xff1a; HashMap 是非线程安全的&#xff0c;Hashtable 是线程安全的,因为 Hashtable 内部的方法基本都经过synchronized 修饰。&#xff08;如果你要保证线程安全的话就使用 ConcurrentHashMap 吧&#xff01;&#xff09;&…

C# 委托简述

1.委托 1.1什么是委托 委托委托 官网解释: 委托是安全封装方法的类型&#xff0c;类似于 C 和 C 中的函数指针。 与 C 函数指针不同的是&#xff0c;委托是面向对象的、类型安全的和可靠的。 委托的类型由委托的名称确定。 个人理解:委托就是一个方法的模板。它可以接收…

云渲染主要是分布式(分机)渲染,如何使用blender云渲染呢?

云渲染主要是分布式&#xff08;分机&#xff09;渲染&#xff0c;比如一个镜头同时开20-100张3090显卡的机器渲染&#xff0c;就能同时渲染20-100帧&#xff0c;渲染不仅不占用自己电脑&#xff0c;效率也将增加几十上百倍&#xff01; blender使用教程如下&#xff1a; 第一…

Ansible 的脚本 --- playbooks剧本

playbooks 本身由以下各部分组成 &#xff08;1&#xff09;Tasks&#xff1a;任务&#xff0c;即通过 task 调用 ansible 的模板将多个操作组织在一个 playbook 中运行 &#xff08;2&#xff09;Vars&#xff1a;变量 &#xff08;3&#xff09;Templates&#xff1a;模板 &a…

qt QMainWindow详解

一、概述 QMainWindow继承自QWidget&#xff0c;并提供了一个预定义的布局&#xff0c;将窗口分成了菜单栏、工具栏、状态栏和中央部件区域。这些区域共同构成了一个功能丰富的主窗口&#xff0c;使得应用程序的开发更加简单和高效。 二、QMainWindow的常用组件及功能 菜单栏&…

CSS的外边距合并规则

有时候&#xff0c;我们给组件设置了外边距&#xff0c;但是在实际运行可能和预期不符&#xff0c;这里有一个知识点叫外边距合并规则 比如我们这里有三个容器&#xff0c;A和B都设置了外边距10px&#xff0c;那他们在水平方向的间距是一个求和关系&#xff0c;一共是20px 但…

物联网之超声波测距模块、arduino、esp32

MENU 原理硬件电路设计软件程序设计 原理 超声波是一种频率高于20000Hz的声波&#xff0c;功率密度为p≥0.3W/cm&#xff0c;它的方向性好&#xff0c;反射能力强&#xff0c;易于获得较集中的声能。超声波用于许多不同的领域&#xff0c;比如检测物体和测量距离&#xff0c;清…

JAVA Maven 的安装与配置

一、下载地址 官方网站&#xff1a;Maven – Download Apache Maven 我这里是3.8.6版本 二、安装步骤 maven安装之前要先安装jdk&#xff0c;请确保你的系统已经安装了jdk环境。 1.将下载好的 Maven 进行解压 apache-maven-3.6.8-bin.zip 2.配置本地仓库:修改 conf/settin…

理解计算机系统_简述链接

前言 以<深入理解计算机系统>(以下称“本书”)内容为基础&#xff0c;对程序的整个过程进行梳理。本书内容对整个计算机系统做了系统性导引,每部分内容都是单独的一门课.学习深度根据自己需要来定 引入 源代码在机器层面,是以指令存在的.指令包含了指令码和操作…

vscode离线状态ssh连接不断输入密码登不上:配置commit_id

如题&#xff0c;vscode在一个离线服务器上&#xff0c;通过remote-ssh登录远程服务器&#xff0c;不断弹出密码框&#xff0c;总是进不去&#xff0c;后来了解到主要是不同vscode版本需要下载对应抑制commit-id的vscode-server-linux-x64.tar.gz包。 1&#xff09;vscode, 点…

html小游戏-飞机大战

敌机图片&#xff1a; 子弹图片&#xff1a; 我方飞机&#xff1a; 目录结构 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><title>飞机大战</title><style>* {margin: 0;padding: 0;}#ga…

WebView渲染异常导致闪退解决方案

背景&#xff1a; App主页面使用了大量WebView容器(10个以上)显示图表信息&#xff0c;最新发现bugly上面出现一些关于浏览器Native Crash&#xff0c;如下&#xff1a; 经排查&#xff0c;是WebView渲染失败导致Crash&#xff0c;可以通过webView.loadUrl("chrome://cra…

如何微调(Fine-tuning)大语言模型?

导读 本文介绍了微调的基本概念&#xff0c;以及如何对语言模型进行微调。 从 GPT3 到 ChatGPT、从GPT4 到 GitHub copilot的过程&#xff0c;微调在其中扮演了重要角色。什么是微调&#xff08;fine-tuning&#xff09;&#xff1f;微调能解决什么问题&#xff1f;什么是 Lo…