为了便于理解,前端以下代码示例采用的代码的种都是 React + rdeco 编写,设计模式本身是设计高度抽象的,并不局限于某一类特定的模式框架 组件模式是我们用的最多的或者说目前大家都唯一能够理解的模式,组件模式的前端特点是,予以每个组件独立的代码的种上下文,组件和组件之间有严格的设计代码隔离,通常在不考虑全局变量的模式影响下组件之间是完全无潜在交互的。 const Table = createComponent({ name:table,前端 state:{ data:[], }, view:{ render(){ return( return d })} ) } } }) const Page = createComponent({ name:page, view:{ render(){ return( ) } } }) 复制代码 这种模式我们都很熟悉,Page 和 Table 是代码的种两个拥有独立上下文的组件,在不同的设计 UI 框架里有不同的组件交互方式,亿华云计算在 React 中,模式Page 如果要和 Table 进行交互,前端可以使用 props 传递,代码的种或者借助 Context 来共享一部分上下文。设计 但是这种模式在很多场景下并不是完全有效的,只有当我们非常明确两个组件之间的边界时,模式和实际情况才是相符合的,例如考虑这样一种场景: const HeadTitle = ({ text})=>{ return( { text} ) } const Page = createComponent({ name:page, state:{ text:page, }, view:{ render(){ } } }) 复制代码 在这个示例中,乍看是没啥问题,平时我们都会将一些无状态的 UI 提取为无状态的函数组件,但经过实践你会发现实际上,HeadTitle 大概率仅服务于 Page,也就是说 HeadTitle 并不是为了复用而被提取,更多是因为大型组件的文件需要拆解从而减小体积,降低管理难度。 但是以此为目的进行组件化拆解会破坏原有组件的完整性,云服务器导致大量的参数传递,这和我们过度提取代码到函数其实是一个效果。 function print(name){ console.log(name) } function main(){ const name = main print(name) } // 如果 print 在 main 函数内部则不需要再次传递 name function main(){ const name = main function print(){ console.log(name) } print(name) } // 因此对于 main 来说 print 是一个独立函数?,还是一个代码片段? 复制代码 为了解决组件提取导致的上下文隔离问题,我们实践了一种模式,我们称之为组合模式。 和组件模式相比,组合模式是一种轻量化的方案,相比组件模式两者有明显的区别。 参照以上区别我们来看看的代码示例: const table = createCompose({ view:{ renderTable(){ return( return d })} ) } } }) const head = createCompose({ state:{ text:page }, view:{ renderHead(){ return( { text} ) } } }) const Page = createComponent(compose({ name:page, state:{ data:[] }, view:{ render(){ <> { this.view.renderHead()} { this.view.renderTable()} } } },[table, head])) 复制代码 现在 head 和 table 都成了组合体,通过组合变成了 page 的一部分,为此他们可以共享彼此的上下文,而不用额外通过 props 或者 Context 来传递或者共享参数。 除了组合模式,我们还总结了第三种模式,membrane 模式,这种模式我在早期的文章中有提到过,今天我们将其简化。 和组合模式相比,membrane 模式具有一些共通性,例如同样没有独立的上下文,不需要命名标识,不过两者也有极大的区别。 membrane 是一种抽象模式,和组合模式相比,每个 membrane 只能有一个模板。 compose 和 membrane 可以联合使用。 const pageTemplate = () => { return { state:{ name:, }, service:{ init(){ } }, controller:{ onMount(){ this.service.init() } }, view:{ render(){ return( ) } } } } const Page1Membrane = createMembrane(pageTemplate(), { name:page-1-membrane, service:{ init(){ this.setter.name(page-1-membrane) } } }) const Page1Membrane = createMembrane(pageTemplate(), { name:page-1-membrane, service:{ init(){ this.setter.name(page-2-membrane) } } }) const Page1 = createComponent(Page1Membrane) // render Page1 name === page-1-membrane const Page2 = createComponent(Page2Membrane) // render Page2 name === page-2-membrane 复制代码 如果你熟悉面向对象设计,那么可能会很快联想到 membrane 和 抽象类的特性有些相似,不过相比抽象类,membrane 可以包含具体的实现,因此两者也不完全等价,但是从设计上是有一定的共通性的 在实际实践中,我们结合上述三种模式,借助类似 mermaid 这样的 UML 图形库,在日常迭代中增加了前端设计相关的内容,从实际结果看我们认为这些模式有助于改善前端设计的粗糙和非专业性,同时可以改善前端代码的标准化程度,利用 UML 图更好的代替注释和文字文档来描述业务代码的组成关系。组件模式
组合模式
Membrane 模式