关于前端:我的前端技术思考

4次阅读

共计 12221 个字符,预计需要花费 31 分钟才能阅读完成。

又名 —《深入浅出 Angular 前端开发的几座大山》

前言

次要分享本人做前端 3 年多以来的技术思考,主题内容也是大略都是围绕咱们比拟相熟的那一套货色,比方:组件化开发、状态治理、Dialog、Angular 服务 等,框架上以 Angular 为主,但也会有一些和 React 在代码组织上的比照剖析。

技术思考局部属于一些集体了解,每个人都应该有本人对技术的了解和思考,期待和大家达到共识。

免责申明 – 分享中波及一些集体的了解,比方和 React 理念和思路的比照,仅代表集体对待技术的一个角度。

主题目录
1、技术体系
2、组件化
3、Angular 服务
4、状态治理
5、弹出层

技术体系


因为咱们公司是 ToB 的业务,比拟重前端,须要解决简单交互、简单状态治理以及多团队的开发治理,所以整个技术体系还是比较复杂的,对于开发者来说也是比拟有挑战点、有意思的。

说难不难,说容易也不容易。

CDK 全称 Component Development Kit 是 Angular 官网提供组件开发包,前端组件开发的圣经。

集体倡议:
首先根底方面是必须扎实的比方 JavaScript、Angular 框架,再者就是要对前面的几项精通 1~2 项。
另外就是做业务开发的过程中要敢于去深刻技术细节,基于业务实际去相熟技术链上的技术点、结构设计,针对不欠缺的局部提出改良意见。
珍惜这样的业务机会,让本人的技术往深度方向延长。

组件化

组件
组件是前端交互逻辑封装的根本 单元,依据复用水平能够分为:组件库、业务组件库、业务组件。

咱们这边的开发大略也是这样,写业务组件、根底组件,业务组件中通用的局部抽取到根底组件中作为根底组件库或者根底业务组件库,以最大化实现代码复用,格调交互对立。

咱们这边目前开发的一个难点也在于此,就是须要教训去确定哪些是能够复用的,组件库业务组件库都曾经进行了那些封装,确定根底组件库是否满足业务需要等等。

组件实质

组件作为根底逻辑单元,实质上就是 DOM 结构设计、交互管制(MVC 中的 View 和 Control),从这个层面看来说三大框架都差不多,并且咱们当初所探讨的组件通常是框架组件,因为当初浏览器尽管反对了原生组件(Web Component),然而当初基于 Web Component 去封装的组件库还很少,一方面是 Web Component 比照 Angular、React 等框架的在组件个性方面还有些落后,另以方面是 angular、react、vue 的生态曾经很成熟,惟一有余的是组件库不能通用,然而公司外部能够抉择对立的技术栈,那么这个问题也不是那么突出了。

Angular 组件 / 指令
Angular 组件有两种状态:组件和指令,这块简略的讲就是组件提供实现逻辑解决、DOM 构造的封装,指令通常是只提供逻辑封装,指令须要附加到宿主 HTML 元素上。

组件的话不必过多介绍,这里额定谈谈: 指令,Angular 指令是不容许提供模板的,它须要绑定到一个宿主上,对宿主元素进行额定的逻辑解决。

如果大家基于 Angular 写过新的组件库组件应该比较清楚,在实现一个根底组件的时候,咱们通常有三种对外应用的形式:全局服务、组件、指令,组件设计阶段最先思考的应该是 组件的划分、是否提供指令、是否提供服务 等。

比方通常 Angular 组件库中的 Tooltip 模块就是对外提供一个全局服务和一个指令,因为它是在已有 HTML 元素上进行的交互解决,这种场景下指令是一种更不便的应用形式,使用者只需在原有的 HTML 元素上绑定即可具备 tooltip 的性能。

tooltip 模块代码过于简单,上面以一个简略的指令 thyStopPropagation 阐明指令的特点:

它的性能就是阻止冒泡,状态上和组件基本一致,能够在构造函数获取到宿主元素(DOM 节点),而后监听事件,阻止事件默认的冒泡行为,且能够通过参数指定阻止冒泡的事件类型。

能够看出指令是纯正的逻辑复用,它是很好的代码封装的一种形式。

大家能够思考下,React 中只有组件的概念如果要实现相似于 Angular 中 thyStopPropagation 指令的这中需要该是怎么封装和和应用呢?

组件治理

大部分状况下组件是由框架治理的,咱们开发者通常是依照框架规定的形式编写组件,而后应用组件其实就是交给框架去执行组件逻辑,框架承当了组件的大部分的管理工作,比方组件的创立、销毁以及其余申明周期函数,组件树的治理,组件状态的更新,组件对应的 DOM 的保护,咱们当初写的前端是比拟高级的代码,因为框架帮咱们做了太多的事件。

有些状况下咱们须要本人创立组件(Angular),比方弹出层场景,这个时候就须要开发者本人治理组件了,即是手动创立组件实例,然而这也不是齐全脱离框架,肯定水平上还要受框架的治理,比方开发者本人动态创建组件的时候应用的 viewContainerRef 对象,它其实就是 Angular 的组件上线文容器,组件实例通过 viewContainerRef 跟框架的组件树建设关联,运行状态、销毁等还是受框架管制。

根底组件树:

动态创建组件 D:

上图示意的是动态创建的组件与 Angular 组件树的关系,留神这里示意的只是与组件树的关系,组件对应的 DOM 构造是能够随便管制。

组件化的这部分到这里根本完结,次要谈谈对组件化的了解,以及 Angular 框架下组件的组织状态。

Angular 服务

Angular 服务是区别其它框架的一个特色点,我说的不是服务自身,而是蕴含了依赖注入、Rxjs 等的组合技术,它是组件、利用之间状态共享、音讯通信的桥梁,也是代码组织的一种重要形式。

利用场景
① Angular 状态治理:Angular 的状态治理技术相干技术根本都是以服务为根底实现的。
② 单例服务:注入组件库中的 ThyDialog、ThyPopover,这类的代码组织是处理函数和数据状态组合的一个状态,比方 ThyDialog 服务的实例能够关上弹框,那么这个弹框的实例状态就在服务中保护了,能够同时关上多个弹框,能够管制最大关上 3 个弹窗,就须要在服务中保护一个实例状态的列表。
③ 组件内配置服务:这类通常对应到咱们的业务实现,比方 Wiki 产品中须要实现一个跨组件的事件或状态传递,层层传递参数或者层层抛出事件都太麻烦了,于是一个自然而然的计划进去了,通过一个服务存储共享状态,或者在服务中基于 Rxjs 做一个告诉流,实现跨组件的通信。

其中,[③ 组件内配置服务] 是一个一把双刃剑,应用服务它解决跨组件通信问题是一个利器,也存在被滥用或者不标准应用的问题:

  1. 须要明确服务是单例的还是组件注入
    a. 组件注入须要思考注入在那个层级
    b. 组件注入的状况须要思考组件的各种应用场景下是否都能取到服务实例
  2. 留神服务中的状态保护(谨严的保护数据状态)
  3. 对于数据流要留神勾销订阅
  4. 留神服务中依赖注入的上线文,比方服务所依赖的服。

思辨点
服务在 Angular 中被认为是一个很好的组织业务逻辑的形式,然而在函数式编程中像服务这样的个性却被不屑一顾,因为它不合乎纯函数的思维,服务中能够存储部分状态,那么服务中的办法就不再纯正,这可能是代码坏滋味的开始。
还有一点就是组件间的通信减少了一层服务会使利用的数据流向、组件间通信方向变得不再直观,所以我也感觉服务是个好货色,然而要想分明了能力用。

React 场景计划
React 不存在服务的概念,React 的外围就是组件,其它一些概念设计全副围绕组件发展,那么后面提到的 Angular 中应用服务解决的业务场景在 React 中它是如何解决的呢?

这也是 React 中的根底,我不是特地精通,这里算是卖弄一下:
① 父子级通信 – 参数传递,事件回调
② context – 一个上下文用于在有层级关系的组件中共享状态,这个在 React 中用的十分多,实现了组件属性穿透。
③ 状态治理 – 毫无疑问,React 中状态治理是一种常见的跨组件通信的解决方案
④ 自定义事件 – 用自定义事件来实现非嵌套组件构造下的音讯通信问题,定义一个事件源,一个组件绑定事件处理函数,一个组件依据行为触发事件,思路大略是这样。

能够看出这类场景的解决实质上是一样的,状态共享、公布订阅,Angular 和 React 最大的差别是理念,React 推崇纯函数,所以在设计上不容许服务这样的概念存在,因为服务能够存储部分状态,违反了纯函数的理念,这是代码形式或者说是模式的疏导,并不代表者 React 开发者不能应用相似服务的货色(也有人把依赖注入和服务引入到 React 中,但它注定被动不会被支流接收),集体有趣味能够拐个弯或者换个状态也是能够用的。

服务的限度
不晓得大家在用 Angular 框架开发利用的过程中有没有遇到过服务应用的场景限度,就是有那些那些场景我用不了服务或者用服务很吃力?
**
① 组件注入场景 – 老手常常遇到的一个问题,就是服务在组件内配置,因为依赖注入上下文的关系,这个服务只能在该组件以及子组件去注入,同级组件或者父级组件(以及全局服务)是无奈通过构造函数注入获取的。这种隐含关系的构建有它的灵活性,也减少了代码的复杂度,我感觉这是服务应用限度之一。
② 工具函数场景 – 大家都晓得服务只能通过构造函数注入的形式获取实例,那么工具函数场景下应用服务就比拟麻烦了,这个限度在编辑器中常常遇到,Wiki 编辑器的一些配置参数(只读状态、默认字号大小)获取或者是组件上下文服务,有时候须要在组件中用到、有时候须要在工具函数中用到,这个时候在工具函数中获取就比拟麻烦。

能够给大家看下咱们是如何解决这个问题的,就是工具函数中获取 Angular 服务的思路,上面是 Wiki 编辑器中设置字体大小工具函数的实现代码:

外围是在编辑器初始化的时候给对象赋值一个依赖注入的 injector 对象,这个 injector 对象的依赖注上下文就是编辑器组件的上下文,有了这个 injector 对象在工具函数中就能够随心所欲了,就像开挂一样。

下面的例子用 injector 获取 Wiki 编辑器的上下文服务,除此之外还能够应用 injector 获取一些全局的 Angular 服务,比方我心愿在工具函数解决中关上一个快捷菜单,那么我就能够通过 injector 获取全局的 ThyPopover 服务,去执行它的 open 函数关上菜单。

基于 Weakmap 的状态共享计划
后面次要是说用 injector 对象能够为工具函数和 Angular 服务之间的调用架起一组桥梁,其实在基于 Slate 开发富文本编辑器的过程中还有一部分的代码设计能够解决这方面的问题,能够了解为它也是一种状态共享计划,这里把它称为:基于 Weakmap 的状态共享计划。

实践上在利用中共享数据间接把数据存到一个全局变量中就能够了,而后就能够在工具函数中、Angular 组件中性能应用(回到了最原始的形式),然而这种状况下有一个问题,就是多编辑器状况下数据可能会相互影响,所以个别不倡议将组件的数据存成全局数据,用 WeakMap 能够解决这个问题,能够把 Weakmap 的 key 指定为编辑器利用对象,这样每个编辑器的数据旧会起到隔离的作用,WeakMap 在 Wiki 编辑器中有很多利用:

从上图 Weakmap 的定义能够看出 Weakmap 的实际上单例的,key 的类型指定为 Editor 能够隔离多编辑器数据,这种数据设计方案十分简洁、实用。

到这里 Angular 服务的局部节本完结了,Angular 服务在 Angular 框架承当了桥梁的作用,让 Angular 框架的组织能力、代码设计能力大幅度加强。

状态治理

状态治理也是我集体的一个痛,因为在以前我始终搞不明确状态治理有什么作用,来到 Worktile 当前才算弄明确,所以这里外围说下我对状态治理的一个了解,当然也会联合 PingCode 中状态治理状态介绍下咱们的利用场景:全局数据,业务数据,微前端数据等。

值得一提的是没有状态治理是相对正当的,严格来说它都不能算作一种技术,因为状态治理就是数据的一种组织形式,而且它不是必须的。
状态治理的实质是标准数据的应用,包含数据的初始化、批改、页面更新,属于利用技术计划。

状态治理思维
状态治理外围体现的是治理的思维,提供数据批改的对立门路,让数据的批改规范化,数据批改自身能够 被记录 对立解决

对于一般的利用状态治理不是必须的,然而随着 React 的倒退以及状态治理相干开源库的遍及,状态治理逐渐变成了一种潮流,当然状态治理的思维自身也有它的进步性,所以当初大家通常依照状态治理的思维去解决数据。

基础理论
最简略的状态治理蕴含两个概念:不可变数据、Action。
① Immutable – 数据是不能够批改,如果批改只能从新创立一个新的对象,代表库:immutable.js、immer。
② Action – 形容数据批改,也能够了解为给每一次的数据需改减少一个类型标识。

而状态治理的鼻祖 Redux 还有一些更简单的概念,这里再做过多介绍,外围关注这两个就能够了。

Redux Dev Tool
这是一个帮忙开发者监控状态治理数据的浏览器插件,个别写过 React 的都用过,这是一个很不错的调试工具,它能够记录利用中的每一次数据批改,也能够比照出数据批改前后的数据变动,能够无效帮忙开发者排查问题,梳理简单数据的批改流程,我感觉这也是 Redux 胜利的一个起因,就是配套工具做的很欠缺,开发者享受到了切切实实的便当,不枉学了那么多的概念。

思维延长
状态治理作为一种优良的数据管理的思维,在咱们的富文本编辑器中也有用到,而且在富文本编辑器中这种对数据批改的设计和管制则是刚需,它是实现协同编辑、Redos/Undos 的根底。

上面是一个 图片节点 的数据示意:

[
  {
    type: 'image',
    url: 'https://altas.pingcode.com/xxx',
    align: 'center'
  }
]

当初用通过界面把对齐形式调整为居左,新的数据如下:

[
  {
    type: 'image',
    url: 'https://altas.pingcode.com/xxx',
    align: 'left'
  }
]

大家想一想这个过程该怎么产生?,以及如何应答 协同编辑 和 Undo 场景?

简略的形式
间接批改数据,Undo 时间接复原上一个的状态,协同编辑则须要把全量数据发送给协同方

管控的形式

  • 对立数据批改的形式
  • 给每一个种数据的批改设计一类 数据操作类型
    这种形式其实对应于 Slate 中的 Transforms 模块,无论数据结构变动的多简单,数据的批改能够转化为一种根底操作类型(相似于后面说到的 Action 的概念),这样一来和后面的状态治理相似,我能够记录数据的批改操作,精确的晓得本次数据批改的信息,包含数据批改的类型,变动前后的数据(对应 Slate 中的 Operation 对象)。
    基于这个 Operation 对象实现协同和 Undo 操作:
  • Undo 时只须要执行这个 Operation 的反操作(一个插入字符的操作 insert_text 对应的反操作就是 remove_text,通过执行一个操作的反操作能够实现撤回的目标)。
  • 协同是只须要把这个 Operation 发送给协同方,协同方就能够基于这个 Operation 的信息实现数据的同步。

这个是我的一个类比,如果不是很了解也没有关系。

框架绑定
我认为状态治理技术能够大略分为三个局部:标准批改、批改告诉、框架绑定
框架绑定是我抽取的一个阶段,我的了解是状态治理自身以及它和框架绑定应该是两个层,实践上状态治理中的标准批改、批改告诉能够是框架无关的,只有框架绑定层才是与框架无关的。
因为状态数据最终是须要在界面上进行显示的,所以框架绑定就是联合框架的数据更新机制、把数据批改通知框架,在框架的渲染机制内驱动界面刷新。

Angular界面更新的外围机制是变化检测,如果组件不是 OnPush 模式,那么 Store 中的数据只有更新,界面就会自动更新,这很不便。然而如果组件是 OnPush 模式,那么组件须要订阅 Store 中数据的更新,手动执行 markForCheck 或者 detectChanges 去驱动界面刷新。

OnPush 模式是 Angular 对组件进行性能优化的一个形式,组件是 OnPush 模式意味着只有当组件的参数的援用更新后才会执行组件极其子组件的变化检测,参数无变动的状况下是会跳过变化检测的,就跟 React 的 useMemo 相似。

React – React 中驱动组件更新的形式次要靠 setState,那么 React 中可能会基于高阶组件去封装由状态治理数据到组件状态更新这块的逻辑,进而驱动数据更新时的界面刷新。

状态治理的根本状态
这里想要想比照 @tethys/store、Redux、Mobx 的根底应用、体现状态。

@tethys/store咱们的状态治理库,它是一种非常灵活的形式,Store 能够通过全局注入作为全局状态,也能够在组件内注入作为部分状态,次要是以 Angular 服务的形式存储和应用数据,只不过是数据的批改和存储是被组织化的。
Redux 齐全遵循纯函数,是最 React 形式的状态,然而代码是比拟离散。
Dva 国人封装的一个库,是 Redux、Thunk、Sagas 三种形式的联合,Redux 中不容许有异步,然而获取数据的 http 申请肯定是异步的,所以提出一层专门解决异步申请,异步申请实现了再调用同步的数据批改,redux 因为太过离散,actions、reduces 等都是定义在独立的文件中所以,dva 对这种状况进行了封装,让状态定义、同步批改、异步批改等对立封装到一个 Model 中,不同业务模块的能够定义多个 Model。
Mobx 可能就是一步到位了,就是以 Store 的状态存储业务数据,在 Store 上提供数据批改办法。

咱们的 Store(@tethys/store)状态上和 Mobx 相似,管什么纯函数,不便就完事,干就完了。

某种意义上 Redux 下的是一盘大棋,整出一套思维,整出一套巨简单、变态的流程去束缚你的数据的操作,而后为你提供了巨牛逼的调试工具,而后就搭载 React 一起火了起来,火起来之后开发者还是感觉它很麻烦,而后有了 Dva、Mobx 这类更易用的形式去状态治理。

其实我对这些货色向来不敏感,让我应用 Redux 那种写法我也感觉没啥,让我用咱们的 @tethys/store我也感觉 OK,它就是一种代码架构形式,只有团队可能达成共识就行。

PingCode 前端状态数据
这块是咱们 PingCode 产品中状态治理的一个典型场景的剖析:全局数据、利用数据管理(封装在业务组件库实现逻辑复用)、简单状态治理计划。

① 全局数据
AppRootContext – 个人信息、全局配置的信息管理,单例模式
GlobalUsersStore – 全局用户信息的治理,单例模式

GlobalUsersStore 数据获取流程大略如下:

  • Portal 利用通过 API 获取初始化的数据
  • 把初始化数据寄存到 window 对象上
  • 子利用通过构造函数注入时在 window 读取这些数据或者对象

Portal 属于 PingCode 产品中的根底利用,对应于微前端架构下的基座利用。

这块的代码是在业务组件库中:styx/module.ts 中

应用 useFactory 配置服务的提供商,保障微前端模式子利用应用服务的是单例的。

useFactory 定义如下:

能够看出背地的技术也很简略,就是把取到的数据挂到 window 对象上。

这块是通过业务组件库注入这些全局的数据的,因为要实现多利用共享,采纳了绝对传统的形式存储值,把数据挂载到 window 对象上了,感觉技术到了又回归到了不举荐的形式上,可能好一些的是咱们这种形式是有节制的应用,没有滥用。

利用数据管理
PilotStore – 这是咱们利用中比拟典型的一个数据管理场景,首先它在各个子利用中有肯定的通用性,API 统一(查问、搜寻、珍藏)、界面也比拟相似,所以在业务组件库对 Pilot 有肯定的封装,包含数据封装和组件封装。

Pilot 是咱们外部形象的一个领航的一个概念,代码每个利用的主体,比方:项目管理产品 Pilot 就代表我的项目、Wiki 产品 Pilot 就代表知识库。

有一个共识就是业务组件的封装更难一些,因为开发者须要均衡那些能够写死、那些不能写死、还要应用方尽可能的简略。

具体到 Pilot 数据管理的场景,每个子利用界面交互、数据结构基本相同,只有 API 不同,API 构造如下:
https://{sub_domain}.pingcode.com/api/wiki/pilot -> https://{sub_domain}.pingcode.com/api/{applicationName}/pilot
对于 Url 的不同业务组件能够有两种做法:

  • 子利用在应用这块的时候传递一个 Url
  • 业务组件库读取子利用的配置主动拼接这个 Url
    两种形式都差不多,没有本质区别,因为咱们每个子利用在初始化的时候都会减少一个全局的参数配置 StyxConfig 的实例,蕴含利用的标识名称,所以在 Pilot 封装的过程中间接读取这个标识就能够了,所以咱们是用了第二种计划。

PingCode 前端状态治理技术
Angular 服务和 Rxjs 基本上是形成 PingCode 前端状态治理的核心技术,次要的应用场景是在组件中,通过依赖注入获取服务实例(Store),通过订阅 Store 中的数据(Rxjs 流)获取数据的更新推送,Store 自身也提供快照如果只须要读取一次能够间接通过快照获取无需订阅。
具体实现代码曾经齐全开源,这里不在做细节介绍,感兴趣的能够参考:
github 仓储:https://github.com/tethys-org/store 
文档地址:https://tethys-org.github.io/store/guides/intro 

简单状态治理
Wiki 中有一块绝对简单的逻辑,就是页面数据更新的同步,以前总是出问题,通过去年的一次重构当初问题曾经很少了,咱们采纳的是 总线模式:整体思路和实现都十分直观简洁,这里在进行简略介绍,供大家参考:

modify origin : 页面数据批改源,能够是批改题目、批改内容、批改公布人等可能有无数个。
page event bus:全局的页面数据批改的 Bus,基于公布订阅模式。
sync target:对应于要同步的批改的 store,也就是页面要同步数据批改的局部,也有可能有无数个。

数据批改源批改数据时 emit 一个数据批改事件,page-event-bus 接管到批改事件告诉把它转发给订阅者,须要同步数据批改的中央订阅只须要订阅 page-event-bus 就能够了。整体的的关系是:多对 1、1 再对多
针对这个以前写了一篇技术文章:[https://zhuanlan.zhihu.com/p/…](https://zhuanlan.zhihu.com/p/… 

弹出层

弹出层是我特地想讲的,也是我最相熟的,感觉咱们 PingCode 产品的交互皆是弹框。

弹出层交互
弹出层交互在 PingCode 中无处不在,大半的交互都是基于弹出层做的,Wiki 的页面详情弹框、页面编辑、Project 的工作项详情,Portal 的开展侧边栏,弹框详情中的内容抉择、利用内的 Pilot 切换搜寻,操作胜利、失败揭示,提及抉择、关联抉择等等,总之弹出层很重要。

从另外一个角度思考,弹出层是脱离路由交互的另外一种状态,它能够脱离以后的路由实现交互,是单页面利用交互的重要特色,脱离路由意味着它能够是跨利用、跨模块交互的一种状态,比方咱们能够在一个利用中关上另外一个利用的页面详情。

弹出层技术
Angular 框架下应用程序的弹出层技术大多是基于 CDK Overlay 和 CDK Portals 实现的。

Overlay 负责弹出层的整体构造和交互解决,Protals 次要是对 Angular 动态创建组件的封装,因为弹出层是基于动态创建组件,所以肯定水平上弹出层组件的申明周期是自主管制的,而且通过 Overlay 弹出的组件在 DOM 构造上也脱离了原始的文档构造。

Angular 框架下的弹出层技术是框架设计榜样,弹出层技术和框架配合的十分奇妙,开发者应用时也十分棘手,如同代码本该如此。

应用场景

① Dialog – 关上 Wiki 页面详情

代码

② Popover – 关上排序菜单

代码

构造剖析
① CDK Overlay 构造 – Dialog

① CDK Overlay 构造 – Popover

这个 popover 弹出层和 dialog 弹出层共用一个容器,因为他们都是基于 overlay 实现的

② Bootstrap 弹出层构造 – Modal

多个弹出层叠加须要累加 z-index,新的弹出层在上一个弹出层的 z-index 根底上 +50,这个是在 bootstrap 底层保护。

③ Ant 构造 – Modal

③ Ant 构造– Popover

Ant 弹出层的结构设计与 CDK Overlay 一模一样,具体的实现也被抽取到了组件库之外:rc-dialog,然而它的封装水平远不如 CDK Overlay。

弹出层独立性
在后面 [弹出层技术] 中说到了:Angular 的弹出层技术是更独立的。

① 组件独立 – 在后面 [应用场景] 中简略的介绍了 Overlay 弹出层组件是基于全局的服务关上的,用到了 Angular 的动态创建组件,阐明组件的创立、销毁是开发者保护的,肯定水平上脱离 Angular 框架的管制,阐明了 Angular 的弹出层是 组件独立 的。
这个组件独立代表着弹出层组件不会在利用初始化时创立,而是在须要弹出的时候创立,这点是有别于 Ant Design 的,上面能够简略理解下 React 中是如何应用 Modal 和 Popover 的。

Modal 应用

Modal 提醒

Popover 应用

能够看出 React 中针对弹出层这块的应用状态通常是组件,而 Angular 这块则被设计成了服务,我集体感觉基于服务的形式还是比拟优雅的,当然 Modal 也提供了相似服务的全局调用的那种模式,然而限度了应用场景(info、success、error 等),而 Ant Desgin 对于 Popover 的应用则采纳 组件包裹 的模式来组织,这个时候 Popover 组件则相似于一种虚构组件,对包含的 DOM 进行交互加强解决(和 Angular 指令起的作用相似)。

② DOM 独立 – 与 Bootstrap 的构造组织相比,Overlay 实现的弹出层在 DOM 构造上脱离了原始的文档构造,布局不受弹出源的影响。

Bootstrap 的那种 DOM 构造实践上受布局的限度,比方因为布局或者滚动条的起因,可能会在页面中设置 overflow: hidden 款式,那么弹出层的显示就会受到影响,当然也这种问题 Bootstrap 应该也会有解决方案。

③ 地位策略、滚动策略 – 地位策略和滚动策略的起源我感觉应该都是 [② DOM 独立] 的产物。
地位策略 – 最新的 CDK 代码只蕴含 global 和 flexible 两种地位策略,global 比较简单对应全局弹出 Dialog 的场景(这种场景下 DOM 原本就应该是独立的,因为弹框的地位是全局固定的,不是基于某一个曾经存在的 DOM 的绝对地位),flexible 则简单一些,它的地位该当是基于曾经存在的 DOM 的绝对地位,那么它的外围就是解决基于地位源弹出的问题,因为弹出层 DOM 脱离了原始的文档构造,所以弹出地位须要基于原始地位去计算,flexible 就对应这种场景的代码封装。
滚动策略 – 因为弹出层是 [DOM 独立] 的,默认页面滚动时弹出层是不会主动追随的,这点跟 Bootstrap 那种构造有本质区别。所以 Overlay 专门设计了滚动策略解决这个场景,能够配置滚动策略:滚动追随、滚动阻塞、滚动敞开。

能够看出基于 Angular 的 CDK Overlay 是一套残缺的解决方案,它把弹出层的 DOM 构造从原始的文档中提出来,解放了弹出层组件 DOM 与原始文档构造的耦合,而后为此设计了一套这种构造下所带来的问题的解决办法,并且实现了与全局弹框的对立,除了 Dialog、Popover 的弹出层场景,它的利用还包含了 Select 组件、Tootip 组件、Dropdown 组件等,实现底层技术的大对立,这也太强了。

设计的艺术
其实 Overlay 的实质体现的是代码的设计,蕴含:DOM 结构设计、组件结构设计、实例 Ref 结构设计、场景策略设计、款式设计等。

从咱们的实际来看,基于 Overlay 的弹出层技术计划整体是更优雅、问题更少的,也更容易写出松耦合的代码。DOM 构造上的独立性解除了对原始文档布局的依赖,以服务的模式应用也让弹出层的调用更灵便,是十分完满的设计。

总结

零零散散分享了一些不太有体系的货色吧,算是本人的一些高见,心愿能够借此引起大家的一些思考或者共鸣。
总的来说还是心愿大家在理论的开发的过程中,除了要关注根底框架(库)的应用、还要多一些思考,多去看一些优良开源库的架构形式,遇到问题追根溯源,把这些架构、库为本人所用,而不是陷入框架或者逻辑的泥潭。
当初的前端开发曾经不在像纯 JavaScript、HTML 时代那样简略了,当初的技术体系个别都会很简单,比如说咱们公司有自研的组件库、业务组件库、状态治理、微前端,这样一来对公司的每一个前端开发者都有肯定的挑战,产品呈现一个缺点它的问题链排查起来就很长,但这也是时机,越是简单的场景越能扩大开发人员的技术深度。
我印象最深的就是我以前刚学 React 那会无论如何都搞不懂状态治理是咋会事,面试常常被问住,来到咱们公司才算真正搞懂,我感觉最重要的一个点就是理论开发中没有遇到真正匹配的场景,那时候遇到的都是一些可用、可不必的场景,天然了解不到精华。


最初,举荐咱们的智能化研发管理工具 PingCode 给大家。

PingCode 官网

对于 PingCode

PingCode 是由国内老牌 SaaS 厂商 Worktile 打造的智能化研发管理工具,围绕企业研发治理需要推出了 Agile(麻利开发)、Testhub(测试治理)、Wiki(知识库)、Plan(我的项目集)、Goals(指标治理)、Flow(自动化治理)、Access(目录治理)七大子产品以及利用市场,实现了对我的项目、工作、需要、缺点、迭代布局、测试、指标治理等研发治理全流程的笼罩以及代码托管工具、CI/CD 流水线、自动化测试等泛滥支流开发工具的买通。
自正式公布以来,以酷狗音乐、商汤科技、电银信息、51 社保、万国数据、金鹰卡通、用友、国汽智控、智齿客服、易快报等知名企业为代表,曾经有超过 13 个行业的泛滥企业抉择 PingCode 落地研发治理。

正文完
 0