使用 Component 拆分界面
我们知道,Angular 中的 component
是 TS class, html, css 三个文件组成的,抛开 css 不谈,我们可以把 html 当作,view 层,class 当作逻辑层。整个页面可以简单的通过 component 组成的逻辑树渲染而成。如类似如下的结构:
app
--header
--body
--body.html
--body.ts
当然,我们可以把共享的逻辑拆分成更下的 component
。比如,A 页面, B 页面 共享一个 Search Box, 那我们就可以将 Search Box 抽离成一个独立的 searchBox.component。
使用 Loc Service 拆分 UI 无关的逻辑代码
但其实有时候,并不一定是 UI 与逻辑都恰好是共享的逻辑块,有时候,会有一部分纯逻辑,需要被共享,我们需要单独抽离开来,Angular 中为我们提供了 Service 这样的概念。比如,A,B component 同时需要使用 c.service。我们就可以非常简单的使用依赖注入实现:
class A {
constructor(
public cService: CService,
) { }
}
class B {
constructor(
public cService: CService,
) { }
}
CService 会在第一次使用的时候被实例化,比如,如果 A component 被先创建的话,cService = new CService(), 就已经被调用的, B Component 再被创建的话,就会直接使用已经被创建好的 cService。当然,你也可以手动指定当前的 cService 是随着 component 新创建的。通过指定,provides 就可以实现。
@Component({
////////
providers: [CService],
})
export class A {
constructor(
public cService: CService,
) { }
}
这样做有什么好处呢?我们来看一下component中的例子,HTML 中需要显示,fullName,我们会在 class 中定义 fullName, 这样通过藏检查,只要 ts 中的 fullName 变了,HTML 中的 fullName 也会重新改变。
<div>{{fullName}}</div>
//////
export class A {
fullName = 'zhangsan'
constructor(
public cService: CService,
) { }
}
但是实际情况中,也可能会复杂的多,TS 中可能会有大量的逻辑部分,这部分逻辑与 View 并没有直接联系。举个例子:
export class A {
fullName = 'zhangsan';
firstName;
lastName;
constructor(
public cService: CService,
) { }
getFirstName() {}
getLastName() {}
}
FullName 可能是通过复杂的计算得来的,而我们实际上再 Component 这一层只关心 FullName 的变化,对中间层并不关心。很容易想到,我们其实应该将具体的逻辑层抽离出来,哪怕这部分逻辑并不会被共享。这样我们就用到了刚刚的 Service 的用法。这样,我们对于一个常见的复杂 component, 基本上得到了这样一个编程范式:
HTML + Component.ts
TS class 通过 Loc 调用 service。
ts class 中的 public property 与 HTML 中使用的变量对应。(应该尽可能减少 HTML 中不使用的变量,避免逻辑变得复杂)
Service 分为两种:一种是共享的 service,一种是只属于当前 class 的 service。通过 service 组成 component 中想要使用的数据。
Store
Service 的概念很简单,就是通过 Loc 被使用的 class,但是在 component 的使用中,有一种范式很被常用:
- class 提供 state
- class 提供 methods 修改 state
- state 只能被 methods 修改,不能直接被修改
- state 可以被监听变化 这种 class 的范式,我们可以称之为 store。
我们来看如何简单的实现一个 store:
class AStore {
state = {
a1: '',
a2: ''
};
changeA1 = (a) => {
return ({
...this.state,
a1: a,
});
}
}
当然,如果把 State 包裹为一个 Observable 就可以不依赖藏检查。
这样,因为 store 是直接被 Component 使用的,我们就可以得到这样一个编程范式:
HTML Template => Component => Store (local store, shared store) => Service
当然 store 也可以 call store, service 也可以 call service,但是层数不应该太深。
NgRx Store
NgRx 帮我们提供了 NgRx store 和 NgRx component store。其实,component store可以理解成 local store,NgRx store 可以当成 shared store。正常的范式可以是
component => component store => ngrx store
component => component store + ngrx store