1.写得比较早现在的web开发通过前后端分离的技术,分为web后台开发和web前端开发。值得指出的是,Web前端开发已经不再是传统意义上的开发模式。它已成为一个网络客户端开发。有过客户端开发经验的同学应该知道两者的区别。客户端开发侧重于:应用程序生命周期组件开发模型和封装方法。组件化是客户端开发最重要的方面。重要内容,设计一个复用性高、可扩展性好的组件系统,可以显着提高开发效率,降低后期维护成本。2.一个笔记组件的设计案例以我正在使用的笔记应用为例。上图所示的note的读写区域,如何将这个区域抽象成一个组件呢?让我们一步一步来分析。1.最简单的api我们给这个组件起个名字(名字很重要),我们就叫它Note吧。不管是阅读状态还是编辑状态,组件都必须显示笔记的内容,因为笔记对象要通过组件的接口传入,因为我们为这个组件设计了第一个api:属性描述类型是否为必填datanoteobject数据对象接下来,我们简单使用一下这个组件:为了兼容vue和react的读者,本页面使用了JSX语法constnote={title:Howtomakeacomponent?.md,content:}这样一个最简单api的笔记组件就做好了。它的界面非常简单。只需要提供一个数据属性就可以显示笔记的内容,点击编辑就可以进入书写状态。一般来说,如果没有更多的需求,我们的笔记组件设计就可以在这里完成。**在设计组件的时候,一定要遵循最小化的原则,也就是尽可能少的丢掉接口。**因为可能有很多用户在使用组件,一旦组件作者不小心抛出一个不合理的接口,以后几乎不可能修改(只能通过标记过时的方法来提醒用户,但这种做法往往是一种绝望的行为)。2.满足各种情况的数据获取现在组件用户可以通过一个非常简单的API来使用这个笔记组件,但是现在一个问题出现了:有些组件用户只是获取了笔记的id,想直接使用该组件通过传入id。这个时候作为组件的作者,我们评估这个需求是合理的,所以我们扩展了笔记组件的api:是否需要属性描述类型,默认值数据笔记对象对象为nulldataId笔记对象idstringisnull现在可以传入id来使用组件:constnoteId=123请注意api中的两个属性不是必须的,因为用户传入哪个属性是未知的,对于程序的严谨性,组件应该验证这两个参数没有被传递,并通过抛出错误的方式通知调用者。这是组件设计的一个技巧,通过支持多数据源,让调用变得更简单。然而,这种设计也有其缺点。如果这种兼容性扩展太多,组件内部逻辑会变得复杂,API也会变得难以理解。因此,对API扩展的兼容性要谨慎,不要过火。.3.兼容不同模式组件的使用一如既往的优雅和简单,但是现在有用户提出了新的需求:因为这个组件支持阅读和编辑两种模式,所以在使用的时候,不能编辑别人的注意,在指定场景下只能支持一种阅读模式吗?笔记组件同时支持阅读和编辑,因为它内部支持两种模式。所以调用者只想使用一种模式是合理的。于是,我们继续扩展组件的API:属性表示是否需要类型,默认值mode模式,数组第一项作为初始模式,参数不能为空。用户可以这样调用:constnote={}constmode=[read]在设计API的时候,我们在满足需求的前提下支持更多的情况。首先,用户可能只使用编辑模式,因为模式参数支持各种模式的任意组合,所以这种情况也可以满足。另外,如果以后组件扩展更多的模式,api还是可以满足要求的,只需要在mode数组中增加更多的模式项即可。这里比较好的设计是,当使用多种模式时,还需要判断哪种模式是初始模式。因此,在多个模式中使用模式数组的第一项作为初始模式,既满足了要求,又实现了最小化api设计的原则。现在,我们扩展了用户的需求,不仅仅只支持阅读模式,还支持各种模式的任意组合和初始模式,但这还不够,组件的设计者应该考虑更长远的情况根据需求,对于本例,我们还可以为组件扩展一个模式改变事件,这样调用者就可以捕捉到笔记组件从阅读->编辑或者编辑->阅读切换的瞬间(随着模式的扩展,这个组合会更多):事件说明回调参数modeChange在模式切换时触发(from:string,to:string)from表示切换前的模式,to表示切换后的模式。调用者在捕获到模式切换事件时可能会做一些特定的工作:functionhandleModeChange(from,to){//...}4.在编辑器中编辑笔记更多支持html或markdown类型,笔记组件支持将笔记导出为PDF文档。因此,在设计时,我们可以将组件的一些能力抽象成api,将组件的api再次扩展:方法说明参数exportPDF将笔记导出为PDF文件-toggleFullscreen切换全屏显示(value:boolean)是否显示组件在全屏设计的时候,我们可以将可预见范围内的组件的能力设计成API。需要注意的是,方法的参数和返回值也是API的一部分,需要慎重设计。除了扩展组件的功能,我们还可以扩展组件的视图。有没有注意到阅读按钮右侧的工具栏?我们假设这部分view不属于note组件,而是通过api扩展渲染的。这是组件的子视图设计。在Web前端的组件化中,称为slot。我们可以为便签组件扩展一个工具栏插槽:插槽描述参数toolbartoolbarsubview{data}当调用者想要扩展便签组件的工具栏时,可以这样使用:constnote={}这样调用者就可以根据自己的需要在工具栏上渲染出自己想要的内容。3.组件设计的四要素以上案例描述了组件设计的全过程。通过分析用户的需求(或者未来可能出现的需求),逐步设计出一个复用性高、扩展性好的组件。如果你是组件设计的新手,应该如何去思考和设计一个优秀的组件?1.先设计,后实现我们整篇文章都在讨论组件设计,但是在实际操作中,很多朋友会体会到,通过侧面设计的方式来完成一个组件的制作是不合理的,因为自身能力所限和愿景,实现可能会干扰您的设计。关于以下两个经典矛盾,希望读者可以选择后者来追求合理的性事。这样实现比较方便,为什么不抛出这个参数让用户传入呢!这样设计比较合理,虽然实现难度可能比较高,但是我可以通过文档学习,请教别人实现,或者让别人直接实现。**提出问题比解决问题更难。**设计难实现,你应该把70%的时间花在设计上而不是实现上。有的设计者甚至不参与实现,设计者和实现者的身份随时转换,善于思考的实现者本身就是设计者。2.组件设计的四大要素AttributesMethodsEventsSubviews(slots)以上案例基本涵盖了这四大要素,这四大要素共同构成了组件的API。需要注意的是,除了基本的四个元素,我们还需要注意这些也是组件api的一部分:属性类型,是否必填,默认值(属性类型为determined),方法参数,返回值(需要考虑Changes)在设计事件回调函数的参数槽可以获取的局部参数时,我们要谨慎面对各个API的元素,以及其中的任何设计缺陷任何链接对来电者来说都是棘手的。4.终极思维:面向对象虽然我们通过一系列的理论描述了组件设计的方法,但是对于初学者来说设计一个优秀的组件还是有难度的。设计一个优秀的组件需要大量的经验。初学者往往考虑不周,或者由于对需求的无知,无法预测未来的变化。即便如此,初学者还是需要耐心学习元器件的设计,步步为营,方能行至千里。经过一段时间的积累,总结出了设计组件的终极思路。将面向对象的思想应用到组件设计中,会事半功倍。在发展领域,学会思考比努力更重要。我们在组件设计中使用这个理论,如何通过面向对象的思想来设计一个组件呢?虽然我们强调用面向对象的思想来设计组件,但似乎面向对象的思想比组件设计更深入,当然我们不会推荐我们用更晦涩的理论来指导组件的设计。在这里,我们将面向对象拟人化,提炼出一种联想自然界的思维方式。接下来,我们将使用这个方法来设计一个快递小哥的组件:首先,快递小哥有他的基本信息,也就是组件的属性。基本信息包括雇主、工作年限、姓名、联系方式等。另外快递小哥还有一些特有的行为,比如发快递,收包裹等,我们可以把这部分提取出来作为一个组件方法,比如我们调用快递小哥的收包方法,这个方法有两个参数,第一个第一个参数是我要寄的东西,也就是包裹,第二个参数是couriernote,描述的是寄送的相关信息。除了基本信息和一些行为,快递组件还有一些特有的事件。当我们的包裹到达时,他会打电话给我们。这里,组件抛出一个快递到达的事件,该事件的参数为courier快递单上描述的是包裹的派送信息,包裹就是快递单上描述的收件人的东西。最后,courier组件是否有子视图?是的。快递组件除了我们普通用户会调用外,快递公司也会调用。不同的快递公司会对快递进行不同的包装(例如通过不同的服装和不同的标志)。所以快递公司在调用这个组件的时候,会将快递员的衣服传入一个名为attire的子视图中,这样不同公司的快递员就会有不同的着装。你可以用自然世界联想的方法来思考所有与面向对象和组件化相关的问题。只要计算机世界还是由人类构建的,我们就仍然可以按照自然界的规律来感知计算机世界。二进制的世界从来就没有冷酷无情,每一个二进制字符串都融入了coder的思维方式和价值观。5、最后回到开头的问题,为什么说今天的web前端开发变成了web客户端开发呢?因为组件化是所有客户端开发的核心概念,只要这一端大部分时间都在做组件抽象工作,我们就可以认为自己在从事客户端开发。最后,组件化不是灵丹妙药,不会为你解决任何实际问题,它只是一种思维方式。