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