从您的描述看来,您正在尝试构建仪表板系统或 HTML WYSIWYG 编辑器。这是一个相当广泛的架构问题,方法将很大程度上取决于您的项目的要求/时间框架等...我的第一个建议是进行搜索,看看是否有任何工具已经可以满足您的需求。即具有自定义功能的 Ck 编辑器是否满足您的需求? ...
找不到一个,如果您需要自己动手,这里有一些从我的经验中吸取的教训。
- 要么创建一个使用原生 HTML 拖放的自定义指令,要么使用提供拖放功能的 Angular 库之一(即材料拖放等...)
- 定义您的页面模型的外观。
- 利用 Observables 确保各个组件保持相互隔离。还可以使用共享服务/可观察对象在彼此之间进行通信
- 将尽可能多的通用“属性”组合在一起,并使其成为您的基类的一部分。
定义您的页面模型的外观
- 您将如何存储用户所做操作的表示?在 HTML、JSON 中?
- 我们在内部就使用 HTML 而不是 JSON 进行了争论,但最终我们选择了 JSON,因为团队认为它更适合他们。但您也可以使用 HTML 作为模型。
例如:
export interface Widget {
name: string;
type: string;
style: CSSProperties;
widgets?: Widget[];
}
export interface Text extends Widget {
textContent: string;
}
export interface Image extends Widget {
url: string;
}
export interface Table extends Widget {
source: string;
}
您可以随时扩充您的界面,但至少要花足够的时间了解结构的外观。如果完成属性,添加具有自己接口的新组件变得轻而易举。在某些方面,这就是使用 HTML 作为模型可能更有意义的地方。
但是有了这个模型,你的“TextComponent”可以期望提供一个符合“Text”接口的数据。图片、表格等也一样...
您可以使用您希望使用的特定属性标记组件的 html。即对于 TextComponent,您只需在 HTML 中使用 "{{textContent}},因为它是该组件接口的属性。
拖放
- 了解是否需要支持嵌套拖放?
- 根据您的项目要求,找到一个具有您可以使用的拖放功能的库(材料拖放等...)
- 或者创建一个指令来实现 HTML 5 的原生拖放功能
无论您采用哪种方法,所有拖放都有一个“drop”事件。当用户停止拖动时触发此事件。大多数拖放工具还允许您在“拖动”期间传递数据,即使“拖放”事件处理程序可以处理它。
定义模型后,您可以在拖动事件中传递当前组件的模型。在“Drop”上,您可以检查传递的数据的widget.type。这将允许您确定您正在处理的组件类型。
利用 Observables 确保各个组件之间保持隔离
- 一开始,当您只有少数几个组件时,允许您的各种组件直接相互交互会很诱人。甚至可能修改彼此的状态和/或数据。
- 但是,随着组件列表的增长,并且您开始需要组件交互,您将很快开始发现问题。即在组件 A 中选择日期范围还需要更新组件 B 中显示的数据
我们最终采用了状态管理解决方案 (NgRX),以帮助将状态与布局分开。由于我们是在中途进行的,所以一开始很痛苦,但是一旦完成,添加新组件就会变得更快。仅供参考:你不需要使用 NgRx,一个服务或共享的 observable 将跟踪你的各种组件的数据也可以。例如,使用 RxJS BehaviorSubject 允许延迟订阅者获取当前值
这允许处理诸如
之类的场景
- 组件 B 依赖于组件 A
- 当组件 A 发生更改时,组件 B 订阅存储并更改自己的属性,而不是组件 A 循环遍历所有组件以查找依赖项,并更改组件 A 更改的属性
- 这使我们能够将应用程序中的布局逻辑与业务逻辑分开。即,每当 A 公司更新商店时,如果要应用业务逻辑,则在显示组件之外进行处理。这有助于我们的组件列表不断增加。
- 这使我们能够处理多组件事件。即,如果用户按住 shift 并选择多个组件,并且想要更改所有选定组件的背景颜色。背景颜色的选定组件 css 属性在商店 (NgRX) 中更新,组件(通过订阅和更改检测)自动在屏幕上更新。
最终,这种方法使我们能够将组件的表示逻辑与数据逻辑分离。
这可能会变得非常复杂,具体取决于您需要的复杂程度。如果这是一个项目,您只需要快速而肮脏地完成某些事情,那么当然要做您必须做的事情。但是,如果您有时间专注于此,我建议您花一些时间来了解您的模型以及组件交互将是什么。
我希望其中的一些内容对您有所帮助。祝你好运。