怎样做自己的的社交网站,网站建设建网站年轻的母亲,wordpress head 优化,郴州市网站建设公司目录#xff1a;
项目中的 Dropdown简要分析需求设计方案Demo 展示验证
项目中的 Dropdown
我公司的项目中实现过不止一个 Dropdown 组件#xff0c;但是普遍存在一些难以解决的痛点。又或者在实现的时候能满足需求#xff0c;但是一旦功能修改了就很难拓展。这也是写这篇文…
目录
项目中的 Dropdown简要分析需求设计方案Demo 展示验证
项目中的 Dropdown
我公司的项目中实现过不止一个 Dropdown 组件但是普遍存在一些难以解决的痛点。又或者在实现的时候能满足需求但是一旦功能修改了就很难拓展。这也是写这篇文章的原因主要是想找出一个比较好的解决方案。
以下我列举一些项目中典型的问题以及它们出现的原因
多份 options 备份多组件复合复杂的组件嵌套
多份 options 备份
这个问题最先出现的原因是我们引入了检索功能。被检索的 options 是不完整的列表当我们需要从列表中筛选出被选中的选项来改变它们的状态时需要一个完整的 options。所以此时就多了一个 filteredOptions。
而后随着功能越来越复杂这类的 options 备份也越来越多甚至曾经一度达到了 4-5 个。
多组件复合
一开始我们只需要实现一个单选下拉框和一个复选下拉框。而后功能增加例如: lazyload options配合其它功能的Switch开关Search 输入框 等。
这就造成了组件的布局问题以及各个功能之间的通信复杂度也上升了。慢慢的 Dropdown 的体量变的越来越大它的维护难度也直线上升。
复杂的组件嵌套
我们一开始实现的单选和多选 dropdown 还是有很多可以复用的组件和样式的。后期二者的区别越来越大共用的组件慢慢变的不再共用。所以项目中出现了很多的 if else 来区分这两个组件的应用范围。
同时这两个组件当时是嵌套在同一个组件中因为它们有类似的数据流可以共享通信过程。但是这也为后期的功能拓展埋下了隐患。综上所述正因为存在这样的问题所以我们需要一个更好的 dropdown。为下次项目重构提前做出准备。
简要分析需求
Dropdown 组件可涵盖的业务非常广泛要具有 和业务解耦扩展性强好维护 等特性。我们列出不同视角下组件的特性和规律方便我们制定方案。
组件有什么
以 Angular component 为例一个组件至少需要以下 4 点
inputoutputUI (html, css)functions (event, method …)
这 4 点可以归纳为
input AND output -- ModelUI -- Viewfunctions -- Controller
如何解耦
由此可见实现一个扩展性强的组件我们需要做的是协调好 mvc 的逻辑明确 mvc 的代码应该放在哪些文件里用什么形式实例化组件。
那么为了实现解耦为了能以 API 热插拔的形式实现组件的拓展就有一个核心的要求Dropdown 中的每一个小功能要以一个 独立的完整的 包含全套 mvc 的组件形式存在。
用代码表示类似于
!-- Dropdown UI --
div classdropdownSearchInput/SearchInputDropdownMenu/DropdownMenuDropdownBtns/DropdownBtns
/div只有功能完整且独立才能不受到其它功能的影响这是目前我能想到的唯一的解耦方式。
设计方案
上一步已经分析出了实现组件要遵循的核心原则方案设计要敲定实现的方式。
我实现了两个方案第一个方案在实现后有缺陷所以废弃了最后采纳了第二个方案。
第一次方案的实现
实现方式要考虑到以下几个问题
组件布局各个功能之间的交互热插拔怎么实现
有两个方案能满足上述要求
使用动态创建组件
它们各自的优缺点ng-content
● 优点直观实现简单
● 缺点限制太多性能消耗动态组件
● 优点更加灵活复用性强拓展性好
● 缺点动态组件的创建和管理增加代码复杂度const components [{name: menu,input: {props: {...}},output: {changes: () {...}},component: MyComponent}
]ng-content 直观而且可以减少组件的嵌套但是 ng-content 的限制太多而且在多组件嵌套情况下性能也不好。不应该有条件地包含带有if, for或switch的。即使该占位符被隐藏Angular总是实例化并为渲染到占位符的内容创建DOM节点。有关组件内容的条件渲染请参阅模板片段。第一次方案决定采用动态组件渲染即将组件和配置信息以 Input 形式传入 dropdown 组件在 dropdown 组件中使用 ViewContainerRef.createComponent 来创建组件。
虽然能实现但是除了上面提到的代码复杂度以外还存在几个问题
渲染的时机要先渲染 dropdown 中的占位元素然后才能 createComponent增加了渲染流程的复杂度更新数据因为传入的数据比较复杂在改变其中数据的时候可能无法触发 Angular 的 OnChange
以上问题导致虽然实现了 dropdown 组件但是维护难度太大所以放弃这个方案。
第二次方案
核心要求不变使用 ngTemplateOutlet 来实现 dropdown 组件。
相比于上面的两个选择ngTemplateOutlet 实现的代码简洁而且直观。同时它比 ng-content 指向性强安全性好。
Demo 展示
使用 Angular 19 进行 Demo 的展示。
利用 angular-cli 生成了标准的 angular 项目插件增加了angular/material 和 lodash其它未作改动
dropdown.html
div classmy-dropdown-container!-- Dropdown Trigger --div classmy-dropdown-triggerng-container *ngTemplateOutlettrigger/ng-container/div!-- Dropdown Menu --div classmy-dropdown-menung-container *ngTemplateOutletmenu/ng-container/div
/divdropdown.ts
import { Component, Input, TemplateRef } from angular/core;
import { NgTemplateOutlet } from angular/common;Component({selector: my-dropdown,templateUrl: ./myDropdown.component.html,styleUrls: [./myDropdown.component.less],imports: [NgTemplateOutlet]
})
export class MyDropdownComponent {Input({ required: true }) trigger!: TemplateRefany;Input({ required: true }) menu!: TemplateRefany;
}分别实现了三个组件 search-inputdropdown-menudropdown-btns。把这些组件封装成了一个标准组件 standard-dropdown
standardDropdown.html
my-dropdown [trigger]triggerTmp [menu]menuTmpng-template #triggerTmpdropdown-trigger/dropdown-trigger/ng-templateng-template #menuTmpsearch-input [placeholder]Search... (valueChange)handleSearchChange($event)/search-inputdropdown-menu [options]options | filterOptions : args (optionSelected)handleValuesChange($event)/dropdown-menudropdown-btns (eventClick)handleEventClick($event)/dropdown-btns/ng-template
/my-dropdown效果如下dropdown 只负责渲染在 standard-dropdown 根据需求定制不同的内部组件。search-inputdropdown-menudropdown-btns 都是独立的组件与外部解耦。
我们可以根据不同的需要来创建不同的 dropdown为它分配不同的功能。如多选、单选、条件选择、懒加载 等。
验证
这部分比对一开始表述的项目中的问题来看看我们实现的组件是不是能解决问题。
1. 多份 options 备份
我们的 standardDropdown 只维护一个 options检索的结果直接以 pipe 形式过滤出合法值传入 dropdown-menu。
如果有其它需要按条件检索 options 的情况将方法封装入 service 中在使用的时候调用方法过滤 options而不是提前存储一个处理过的 filteredOptions
2. 多组件复合
ngTemplateOutlet 的方式本身拓展性就很好。每个组件只需要考虑它自己的功能而与业务有关的代码则放入外层的 standardDropdown 中。那么当我需要增加或者修改组件的时候只要替换它就行了。
3. 复杂的组件嵌套
按这种方式实现的dropdown就像积木一样我只需要考虑如何拼接它。
不再需要复杂的嵌套只需要一个外层组件来组合并且处理业务逻辑。而这个外层组件直接控制它内部的小组件需要什么功能就添加什么组件。目前来看它比较好的解决了我们一开始提出的问题。