最新要闻
- 酒店比价网站_酒店比价
- 【当前独家】“保时泰”破产重整后凄凉!股权六折甩卖仍无人接盘
- 每日速看!韩国拟取消校园暴力者读大学资格:转学脱罪也没用
- 环球精选!网友拍下真实版“乌鸦喝水” 原来是表演节目 两只乌鸦都会
- 今亮点!魅族20系列1元36月超长质保加码!电池最大容量低于80%免费换
- 全球新资讯:神舟十五号乘组太空出差过半:完成多项首次实验测试
- 全球新消息丨《最终幻想16》仍然只有白人:没有对人种多样性妥协
- 全球聚焦:AMD Zen4正式登顶!16核7954HX性能战平24核13980HX、功耗低得多
- 老司机全程不踩刹车?特斯拉潮州事故车主不服鉴定:官方尚未出责任认定书
- 天天百事通!3888元 + 可叠加百亿补贴:天猫无门槛红包12点正式开抢
- 4条狼青犬咬死几十只羊!警惕:性情凶狠、攻击性非常强
- 全球微头条丨211文科硕士吐槽均薪5500引争议:文科生转码或成趋势 还是理科香?
- 报道:“RNG老板道歉”登热搜 CEO:轮换中单是我的决定
- 【世界播资讯】李想:理想汽车要占20万元以上市场35% 将对标苹果特斯拉
- 垂头丧气的丧是什么意思?关于垂头丧气的反义词有哪些?
- 父亲的兄弟如何称呼?写给父亲的一封信作文模板
手机
iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
- 警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- 男子被关545天申国赔:获赔18万多 驳回精神抚慰金
- 3天内26名本土感染者,辽宁确诊人数已超安徽
- 广西柳州一男子因纠纷杀害三人后自首
- 洱海坠机4名机组人员被批准为烈士 数千干部群众悼念
家电
天天动态:玩转Angular系列:组件间各种通信方式详解
前言
在前端框架Angular中,组件之间的通信很基础也很重要,不同组件间的通信方式也不同,掌握组件间的通信方式会更加深刻的理解和使用Angular框架。
(相关资料图)
本文讲解不同类型组件间的不同通信方式,文中所有示例均提供源码,您可以 在线编辑预览或 下载本地调试,相信通过本文您一定可以掌握组件通信这一知识点。
父组件传子组件
@Input方式
@Input()
装饰器允许父组件更新子组件中的数据,分为4步:
第一步:在父组件app.component.ts
中定义要传递给子组件的数据parentMsg
。
export class AppComponent { parentMsg: string = "parent component message!";}
第二步:在父组件app.component.html
中的子组件标签
中定义属性[childMsg]
(子组件接收数据变量)来绑定父组件的数据parentMsg
。
第三步:在子组件child.component.ts
中引入@Input()
装饰器,修饰childMsg
接收父组件的传值。
import { Input } from "@angular/core";export class ChildComponent { @Input() childMsg: string = "";}
第四步:在子组件child.component.html
中通过模板标签{{childMsg}}
展示数据。
父组件传值内容:{{ childMsg }}
最终展示效果如下,您可以通过 在线示例预览效果和编辑调试:
说明:这里要理解父组件html中通过[]
定义了一个子组件的属性,该值必须与子组件中所定义的变量名一致,而等号右边的值为父组件要传递的属性名,示例中是将父组件中parentMsg
的值绑定在子组件childMsg
属性上。
子组件传父组件
@Output()方式
@Output()
装饰器允许数据从子组件传给父组件,分为6步:
第一步:在子组件child.component.ts
中引入Output
和EventEmitter
,通过@Output()
来修饰一个EventEmitter
实例的变量newItemEvent
。
import { Component, Output, EventEmitter } from "@angular/core";export class ChildComponent { @Output() newItemEvent = new EventEmitter();}
第二步:在子组件child.component.html
中添加点击事件,获取输入内容,点击按钮触发addNewItem()
方法。
第三步:在子组件child.component.ts
中通过newItemEvent
的emit()
方法,把数据发送到父组件。
export class ChildComponent { @Output() newItemEvent = new EventEmitter(); addNewItem(value: string) { this.newItemEvent.emit(value); }}
第四步:在父组件app.component.html
中子组件标签
中添加父组件方法addItem($event)
绑定到子组件的newItemEvent
发射器事件上,其中$event
为子组件的传递的值。
第五步:在父组件app.component.ts
中通过addItem($event)
方法获取处理数据。
export class AppComponent implements AfterViewInit { items = ["item1", "item2", "item3"]; addItem(newItem: string) { this.items.push(newItem); }}
第六步:在父组件app.component.html
中遍历items
展示数据。
- {{ item }}
最终展示效果如下,您可以通过 在线示例预览效果和编辑调试:
说明:这里要理解关键的第四步事件连接(newItemEvent)="addItem($event)"
含义,左侧是父组件监听子组件创建的一个发射器newItemEvent
,右侧是父组件的addItem($event)
方法。子组件通过发射器的emit(value)
方法广播传递值到父组件,父组件通过addItem($event)
中的$event
接收传值,完成通信。
本地变量方式
在父组件模板里,新建一个本地变量来代表子组件,可以利用这个变量来读取子组件的属性和调用子组件的方法。分为2步:
第一步:在子组件child.component.ts
中定义count
变量和addOne()
方法。
export class ChildComponent { count: number = 0; addOne() { this.count++; }}
第二步:在父组件app.component.html
中子组件标签
中添加本地变量#child
,点击按钮触发点击事件,通过本地变量调用子组件方法child.addOne()
。
最终展示效果如下,您可以通过 在线示例预览效果和编辑调试:
说明:在子组件标签中通过#+变量名
的方式新建一个本地变量代表子组件的引用。本地变量方式使用简单明了,但也有局限性,只能在模板html中使用,无法在ts文件中使用。
@ViewChild方式
通过@ViewChild
装饰器,将子组件注入到父组件。分为4步:
第一步:在子组件child.component.ts
中定义count
变量和add()
方法。
export class ChildComponent { count: number = 0; add(num: number) { this.count = this.count + num; }}
第二步:在父组件app.component.html
中子组件标签
中添加标签引用#child
,点击按钮触发点击事件,执行方法add()
。
第三步:在父组件app.component.ts
中引入ViewChild
,@viewchild
传入标签引用字符child
,由变量child
接收。除了使用标签引用child
,你也可以通过直接传入子组件ChildComponent
实现子组件的引用。
import { Component, ViewChild } from "@angular/core";import { ChildComponent } from "./child/child.component";export class AppComponent { // 第一种方法:传入组件引用名child @ViewChild("child") private child: any; // 第二种方法:传入组件实例ChildComponent @ViewChild(ChildComponent) private child: ChildComponent;}
第四步:在父组件app.component.ts
中方法add()
中调用子组件的add()
方法。
export class AppComponent { add(num: number) { this.child.add(num); }}
最终展示效果如下,您可以通过 在线示例预览效果和编辑调试:
说明:@ViewChild
的作用是声明对子组件元素的实例引用,意思是通过注入的方式将子组件注入到@ViewChild
容器中,你可以想象成依赖注入的方式注入,只不过@ViewChild
不能在构造器constructor
中注入,因为@ViewChild()
会在ngAfterViewInit()
回调函数之前执行,我们可以测试下:
import { Component, ViewChild, AfterViewInit } from "@angular/core";import { ChildComponent } from "./child/child.component";export class AppComponent implements AfterViewInit { @ViewChild("child") private child: any; constructor() { console.log("constructor func", this.child); // undefined } ngAfterViewInit() { console.log("ngAfterViewInit func", this.child); }}
最终展示效果如下,您可以通过 在线示例预览效果和编辑调试:
通过打印结果我们可以看到在构造函数constructor()
中,this.child
的值为undefined
,并没有注入到父组件,但在ngAfterViewInit()
生命周期钩子中注入成功了。
不相关组件
对于不相关联的组件,我们会使用其他中间媒介的方式进行通信,以下不相关组件的通信方式仍适用于父子组件。
service服务方式
组件间共享一个service服务,那么组件之间就可以通过service实现通信。
示例中我们使用rxjs
中的BehaviorSubject
,它是Subject
的一种变体,可以存储最后一条数据或者初始默认值,并会在订阅时发送其当前值。您可以通过RxJS官网进行了解,当然通过文中的说明,您还是可以了解其具体实现的功能。
我们创建两个不相关的组件A
和B
,组件A
发布数据,组件B
接收数据,通过服务文件data.service.ts
进行关联实现。
在公共文件目录下创建service
服务文件data.service.ts
,代码如下:
import { Injectable } from "@angular/core";// 1.引入import { BehaviorSubject } from "rxjs";@Injectable({ providedIn: "root",})export class DataService { // 2.创建subject subject: BehaviorSubject = new BehaviorSubject(0); constructor() {}}
引入BehaviorSubject
,创建一个BehaviorSubject
, 默认值设为0
。 记得在app.module.ts
文件中引入公共data.service.ts
文件,并声明。
import { DataService } from "./data.service";@NgModule({ providers: [DataService],})export class AppModule {}
创建组件A
,用于发布数据,a.component.ts
实现代码如下:
import { Component } from "@angular/core";// 1. 引入import { DataService } from "../data.service";@Component({ selector: "app-a", templateUrl: "./a.component.html",})export class AComponent { // 2. 注册 constructor(public dataService: DataService) {} inputValue: string = ""; send(): void { // 3. 发布 this.dataService.subject.next(this.inputValue); }}
引入service
文件,在constructor()
中注入服务依赖dataService
,使用服务中subject
的next()
方法发布广播数据。
创建组件B
,用于接收数据,b.component.ts
实现代码如下:
import { Component } from "@angular/core";// 1. 引入import { Subscription } from "rxjs";import { DataService } from "../data.service";@Component({ selector: "app-b", templateUrl: "./b.component.html",})export class BComponent { data: any; // 2. subscription subscription: Subscription; constructor(public dataService: DataService) { // 3. 订阅 this.subscription = this.dataService.subject.subscribe((data) => { this.data = data; }); } ngOndestry(): void { // 4. 取消订阅 this.subscription.unsubscribe(); }}
引入Subscription
,使用服务中subject
的subscribe()
方法创建一个订阅者,当组件A
数据被发布后就可以接收到数据。最后在销毁时记得取消订阅,否则会导致泄露。
最终展示效果如下,您可以通过 在线示例预览效果和编辑调试:
说明:示例中组件A
和B
都引入了同一个服务service
,service
服务则巧妙利用BehaviorSubject
实现数据的发布和订阅,在两个组件中进行数据的通信,是不是没有想象的那么难~
路由传参方式
路由传参有多种方式,首先我们新建一个路由模块app-routing.module.ts
,代码如下:
import { NgModule } from "@angular/core";import { RouterModule, Routes } from "@angular/router";import { AppComponent } from "./app.component";import { DetailComponent } from "./detail/detail.component";// 配置路由const routes: Routes = [ { path: "detail", component: DetailComponent }, { path: "detail/:id", component: DetailComponent },];@NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule],})export class AppRoutingModule {}
引入路由相关的RouterModule
和Routes
,引入跳转文章详情组件DetailComponent
,配置好路由routes
,当路径为detail
或detail/:id
时,会加载DetailComponent
组件,其中:id
为占位符,可以在组件ts
文件中获取id
值。
创建好路由模块我们还需要在根模块app.module.ts
中导入。
import { AppRoutingModule } from "./app-routing.module";@NgModule({ declarations: [...], imports: [AppRoutingModule], providers: [DataService], bootstrap: [AppComponent],})export class AppModule {}
在app.component.html
文件中添加
路由占位符,Angular框架会根据当前的路由器状态将不同组件动态填充它。
配置完路由准备工作,我们来具体看下有哪些路由传参方式。
路由路径传参
路由路径中传参,链接形式为:https://ip/detail/1
。
在app.component.html
中使用路由指令routerLink
的方式在路由路径中传参。
1.文章1(路由路径中传参,链接:https://ip/detail/1)
在detail
组件detail.component.ts
中使用当前路由对象ActivatedRoute
获取路由传递的参数。
import { Component, OnInit } from "@angular/core";import { ActivatedRoute, Params } from "@angular/router";@Component({ selector: "app-detail", templateUrl: "./detail.component.html",})export class DetailComponent implements OnInit { id: any; constructor(private routeInfo: ActivatedRoute) {} ngOnInit() { // 获取路由参数方法 this.routeInfo.params.subscribe((params: Params) => { this.id = params["id"]; }); }}
查询参数传参
查询参数中传参,链接形式为:https://ip/detail?id=2
。
在app.component.html
中同样使用路由指令routerLink
,在queryParams
查询参数中传递数据。
2. 文章2(查询参数中传参,链接:https://ip/detail?id=2)
在detail
组件detail.component.ts
中使用当前路由对象ActivatedRoute
获取路由传递的参数。
import { Component, OnInit } from "@angular/core";import { ActivatedRoute, Params } from "@angular/router";@Component({ selector: "app-detail", templateUrl: "./detail.component.html",})export class DetailComponent implements OnInit { id: any; constructor(private routeInfo: ActivatedRoute) {} ngOnInit() { // 获取路由参数方法(params改为queryParams) this.routeInfo.queryParams.subscribe((params: Params) => { this.id = params["id"]; }); }}
仔细观察会发现,第一种路由路径中传参使用的是this.routeInfo.queryParams
获取数据,而第二种查询参数中传参使用的是this.routeInfo.queryParams
,一定要注意这个区别。
路由配置传参
除了在app.component.html
中使用路由指令routerLink
,我们还可以在app.component.ts
文件中通过路由配置中传参。
在app.component.html
文件中绑定两个点击方法toArticle3()
和toArticle4()
。
3. 文章3(路由配置中传参,链接:https://ip/detail/3)4. 文章4(路由配置中传参,链接:https://ip/detail?id=4)
在app.component.ts
文件中通过路由Router
的navigate()
方法实现跳转。
import { Component } from "@angular/core";import { Router } from "@angular/router";@Component({ selector: "app-root", templateUrl: "./app.component.html", styleUrls: ["./app.component.css"],})export class AppComponent { constructor(private router: Router) {} toArticle3() { // 路由跳转文章3 this.router.navigate(["/detail", 3]); } toArticle4() { // 路由跳转文章4 this.router.navigate(["/detail"], { queryParams: { id: 4 } }); }}
虽然是通过路由配置传参跳转,但我们仍然可以发现,文章3和文章1的跳转链接一致,文章4和文章2的跳转链接一致,本质上也是路由路径传参和查询参数传参。所以在detail.component.ts
中,接收路由参数的方法是一致的。
import { Component, OnInit } from "@angular/core";import { ActivatedRoute, Params } from "@angular/router";@Component({ selector: "app-detail", templateUrl: "./detail.component.html",})export class DetailComponent implements OnInit { id: any; constructor(private routeInfo: ActivatedRoute) {} ngOnInit() { // 文章3路由参数获取(params) this.routeInfo.params.subscribe((params: Params) => { this.id = params["id"]; }); // 文章4路由参数获取(queryParams) this.routeInfo.queryParams.subscribe((params: Params) => { this.id = params["id"]; }); }}
最终展示效果如下,您可以通过 在线示例预览效果和编辑调试:
这里需要说明下,在线示例中点击文章url
并未发生改变,这是因为stackblitz工具机制的问题,你可以点击在线示例界面的Open in New Tab
按钮,在单独页面打开可规避该问题。
延伸:示例中的获取路由参数都是使用subscribe
参数订阅的方式,还有一种snapshot
参数快照的方式。如获取文章1路由参数写法为:this.id = this.routeInfo.snapshot.params["id"];
,获取文章2路由参数写法为:this.id = this.routeInfo.snapshot.queryParams["id"];
,可以看到同样是params
与queryParams
的区别。
snapshot
参数快照和subscribe
参数订阅两者的区别在于,当路由地址不变的情况下,若参数变化,snapshot
参数快照获取的参数值不变,subscribe
参数订阅获取的参数值会变化。
我们使用snapshot
参数快照测试一下文章1和文章3,效果如下:
那么snapshot
参数快照获取的参数为什么不发生变化了呢?这是由于第一次点击文章1跳转detail
组件,constructor()
和ngOnInit()
会被调用一次,再次点击文章3,由于detail
组件页面已经被创建了,ngOnInit()
方法不会再次被调用,所以路由参数id
依然保存着第一次被创建时候的值1
。
LocalStorage方式
当然你也可以使用本地存储这种比较通用的方式在组件间通信。
创建C
组件c.component.ts
将数据存储到key
为cValue
的localStorage
中,代码如下:
import { Component } from "@angular/core";@Component({ selector: "app-c", templateUrl: "./c.component.html",})export class CComponent { constructor() {} inputValue: string = ""; send(): void { // 存储数据 window.localStorage.setItem("cValue", this.inputValue); }}
创建D
组件d.component.ts
获取localStorage
中cValue
的值。
import { Component } from "@angular/core";@Component({ selector: "app-d", templateUrl: "./d.component.html",})export class DComponent { data: any; constructor() {} getValue() { // 获取数据 this.data = window.localStorage.getItem("cValue"); }}
最终展示效果如下,您可以通过 在线示例预览效果和编辑调试:
注:这里没有使用sessionStorage
存储是因为localStorage
生命周期是永久的,而sessionStorage
生命周期仅为当前标签页,如果两个组件分别在两个标签页,那么使用sessionStorage
是无法实现通信的。
服务端通信方式
最后一种通信方式是借助后台传输数据,如A
组件调接口发送数据data
存储到后台,再由B
组件调接口获取数据data
,实现数据通信,这里就不做演示了。
总结
Angular组件间的通信方式是多种多样的,对于不同情景我们可以采用合适的方式进行通信。
本文每个示例的重点我都有详细的说明,并延展一些相关知识。示例都是我自己一点点亲手敲的,从0到1研究示例实现方案,虽然花费了很长时间,但加深巩固了知识,之前忽略的一些知识细节也得到了补充,建议大家在学习的同时最好也能动手实现。
好啦,以上就是Angular组件间各种通信方式的所有内容,希望对你有所帮助,如有问题可通过我的博客https://echeverra.cn或微信公众号echeverra联系我。
你学“废”了么?
(完)
文章首发于我的博客 https://echeverra.cn/component-communication,原创文章,转载请注明出处。
欢迎关注我的微信公众号 echeverra,一起学习进步!不定时会有资源和福利相送哦!
天天动态:玩转Angular系列:组件间各种通信方式详解
焦点要闻:DL 基础:PyTorch 常用代码存档
世界热推荐:MySQL学习笔记-多表查询(下)
酒店比价网站_酒店比价
【当前独家】“保时泰”破产重整后凄凉!股权六折甩卖仍无人接盘
每日速看!韩国拟取消校园暴力者读大学资格:转学脱罪也没用
环球精选!网友拍下真实版“乌鸦喝水” 原来是表演节目 两只乌鸦都会
今亮点!魅族20系列1元36月超长质保加码!电池最大容量低于80%免费换
全球新资讯:神舟十五号乘组太空出差过半:完成多项首次实验测试
美团2面:如何保障 MySQL 和 Redis 数据一致性?这样答,让面试官爱到 死去活来
宕机了,Redis 如何避免数据丢失?
世界简讯:风控系统就该这么设计,万能通用,稳的一批!(建议收藏)
焦点要闻:权限提升(1)
全球新消息丨《最终幻想16》仍然只有白人:没有对人种多样性妥协
每日报道:sonar代码扫描bug:Use try-with-resources or close this "FileInputStream" in a "f
世界时讯:通过手动创建hibernate工厂,自动生成表,完成数据库备份还原功能
每日简讯:【36oj】 画圣诞树
全球聚焦:AMD Zen4正式登顶!16核7954HX性能战平24核13980HX、功耗低得多
老司机全程不踩刹车?特斯拉潮州事故车主不服鉴定:官方尚未出责任认定书
【播资讯】不为人知的网络编程(十五):深入操作系统,一文搞懂Socket到底是什么
轻松玩转makefile | 变量与模式
天天百事通!3888元 + 可叠加百亿补贴:天猫无门槛红包12点正式开抢
4条狼青犬咬死几十只羊!警惕:性情凶狠、攻击性非常强
全球微头条丨211文科硕士吐槽均薪5500引争议:文科生转码或成趋势 还是理科香?
报道:“RNG老板道歉”登热搜 CEO:轮换中单是我的决定
【世界播资讯】李想:理想汽车要占20万元以上市场35% 将对标苹果特斯拉
垂头丧气的丧是什么意思?关于垂头丧气的反义词有哪些?
头条焦点:百分比堆叠柱状图适用情形有哪些?速戳!
父亲的兄弟如何称呼?写给父亲的一封信作文模板
张靓颖的海豚音是哪首歌?张靓颖终于等到你的歌词是什么?
李想:如果不卖电池 电动车成本可以比燃油车低
热议:马斯克最疯计划曝光!给我10万亿美元:可拯救地球
梅西花百万买苹果手机送给阿根廷队友:定制了35部24K金的iPhone 14 Pro
天天微头条丨河南小伙1:1打造歼10战斗机模型!司机:这辈子拉过最硬的货
每日简讯:奇瑞背刺长城 捷途旅行者实车亮相:10多万的“硬汉”登场
早晨问候客户的正能量句子有哪些?早晨问候语有哪些?
仓央嘉措是哪个朝代的?仓央嘉措经典诗句有哪些?
蓝码健康码是什么意思?蓝码健康码是正常的吗?
32开纸是多大?32开纸有多大是几个A4?
ps字体怎么加描边?ps字体太小怎么调大?
移动硬盘参数怎么看?移动硬盘参数错误怎么解决?
usd是什么意思?usdt属于什么币种?
全球快讯:带有雨的诗句有哪些_带有雨的诗句具体有哪些
环球观焦点:WebLogic JNDI注入(CVE-2021-2109)
天天通讯!Java 根据模板导出PDF
从菜鸟程序员到高级架构师,竟然是因为这个字final
剑指 Offer 64. 求 1 + 2 + … + n(java解题)
当前简讯:浙江女子1600公里追到广州找到被偷的爱猫:苹果AirTag定位器立了大功
比亚迪豪华MPV成了!腾势D9上月热销7325台:均价41.5万
简讯:俞敏洪最新演讲:不喜欢《狂飙》 企业家只想赚钱就会像高启强后患无穷
复旦MOSS团队:取名是致敬《流浪地球2》 参数规模约ChatGPT的1/10
世界热推荐:跑着跑着会熄火 日产北美召回超80万辆奇骏:车钥匙背锅
环球头条:Git介绍下载安装以及基本使用
全球新消息丨解释器模式
每日时讯!promethues【centos7】时间同步
What is Point ?
【全球新要闻】那舅特大桥建成 又一时速350高铁开铺 南宁至玉林仅50分钟
3899元起 惠普战66六代锐龙版上架:锐龙7000系列加持
世界热议:3月17日开启Beta测试!《暗黑破坏神4》新预告片透露更多游戏内容
焦点短讯!拳头《无畏契约》3月14日起不再支持Win7/8/8.1系统:为了打击外挂!
论文阅读笔记(四):AS-MLP AN AXIAL SHIFTED MLP ARCHITECTUREFOR VISION
(数据库系统概论|王珊)第七章数据库设计-第五、六节:物理结构设计和数据库的实施和维护
全球消息!苹果何时大降价?iPhone 14 Plus成系列销量最差:用户宁愿买安卓
焦点信息:寓言诚不欺我!网友拍下现实版“乌鸦喝水”
焦点报道:儿子篮球班倒闭家长花1000万买下 网友:这就是钞能力
全球热议:999元卷王小金刚!优派推出VX2758显示器:27英寸2K/170Hz
15万就能买特斯拉?特斯拉宣布重大目标:成本降低50%
哪吒汽车2月份交付10073台 同比大涨41.5%
未成年人沉迷短视频得治 TikTok默认限制每天可刷一小时
“自己造自己” 特斯拉人形机器人亮相!马斯克承认罕见事实
【世界速看料】腾讯新游《黎明觉醒:生机》开放60帧:骁龙888、iPhone 13以上都能开
每日视点!印度男子展示绝技“乌鸦召唤术” 网友:在古代至少巫师级别
读Java性能权威指南(第2版)笔记06_数据库性能JPA&SpringData
全省严查!正在进行!
每日看点!马斯克大力推荐!特斯拉Cybertruck实车亮相:超级未来感
天天消息!马斯克宏图计划公布:储能240TWh 制造投资10万亿美元
日本死亡人数是新生儿数量两倍有多可怕:850万“幽灵屋”遍布全国
信息:特斯拉下一代电机将不需要任何稀土成分!马斯克挑战全球车企
环球新动态:Spark系列 - (5) Spark Shuffle
热消息:Fireasy3 揭秘 -- 万物伊始(依赖注入与服务发现)
全球信息:英语四级阅读技巧
一加Ace 2V 12+256G起步行业罕见:友商还在搞8+128卡价位的版本
实时:Redmi Note 12 Pro极速版12+256G到手1999元:开机就是MIUI 14
造车新势力2月交付量出炉:理想、蔚来、哪吒破万 零跑压力大
【全球速看料】厦门征求意见!过马路玩手机或将罚款50元 你支持吗?
世界快看:东风概念飞行汽车外观曝光!“鸥翼门”相当炫酷
【当前热闻】2018巴彦淖尔国际马拉松
环球焦点!胡明轩:平时杜导叫我和徐杰一起训练 要求我们承担起更多责任
世界快讯:makefile
基于alpine基础镜像构建jdk镜像以及tomcat镜像及业务构建
Linux极简入门系列(六):其它补充
CSS全局关键字
环球聚焦:委员建议隔周三休成热搜第一 网友吵翻 专家:很难行得通
今日热闻!Model 2明天发?这款15万的特斯拉便宜车:马斯克已经说了17年
环球新消息丨LOJ 3276 JOISC 2020 Day2 遗迹 题解 (计数DP)
环球快资讯:MySQL学习笔记-多表查询(上)
当前视讯!量化交易基础 - 011 - 样本外检验
风语筑(603466):上海风语筑文化科技股份有限公司关于股东权益变动比例超过1%的提示性公告
天天观察:希望工程发文感谢《原神》玩家 5天9万多人捐赠240万元
世界聚焦:“刺客”又来了!网友称买到1600元一斤话梅:每颗至少20元