- Taro多端开发权威指南:小程序、H5与App高效开发实战
- 李佩忠编著
- 1724字
- 2021-05-19 18:01:17
2.2 组件化
长期以来,前端开发者都在探索如何更好地管理项目模块,都在思考如何设计各模块中类似的UI及逻辑以达到高效复用的目的。早期我们通过定义通用代码文件,在项目中通过script标签引入方式完成复用,这种方式确实能在一定程度上实现通用代码复用、对应模块版本管理等需求,但在大型项目中,这种方式会显得很脆弱,模块之间的依赖管理能力欠缺。后来,有了Bower、Grunt、Gulp等,解决了模块文件或依赖间的控制问题。再后来,有了Webpack,有了各种模块化规范,如AMD、CMD、Commonjs、ES module等,前端开发才进入一个新的世纪。一路进化,最终组件化、MVC、面向对象编程、函数式编程等思想才得以迸发。
2.2.1 初识组件
首先来看一个例子,下图是京东商城首页,我们站在开发者的角度来分析一下这个网页的页面结构。
![](https://epubservercos.yuewen.com/D79B16/20118172101010406/epubprivate/OEBPS/Images/40906_46_1.jpg?sign=1739534850-Eyn47WToQUM9k651QB2s6YZ7KtgobibP-0-b7d2cc3a7c17047cf09806a74360d416)
在使用Taro开发这个页面时,首先考虑将页面内容拆分为图中标注的6个模块,设计好模块间的数据与UI交互之后,便可以单独开发每个模块,最终组合各个模块,完成开发。这里拆解的6个部分,正是6个独立组件。
2.2.2 组件定义
Taro中的组件分为两种,一种是基于类创建的组件,被称为类组件;一种是基于函数创建的组件,被称为函数组件。
1.类组件
定义类组件是一件很容易的事情,你只需要定义一个类,这个类继承自Taro.Component,且在组件中定义render方法并返回值即可,代码示例如下:
![](https://epubservercos.yuewen.com/D79B16/20118172101010406/epubprivate/OEBPS/Images/40906_47_1.jpg?sign=1739534850-3JGqkqwY2RqxspOOZZ8Xnx0mXOJ0kE7C-0-763c7c264896ca859618757b3095e178)
当然,还有为了做优化提供的另一种类组件,关于该组件的原理与用法,我们将在实战优化部分进行详细介绍,代码示例如下:
![](https://epubservercos.yuewen.com/D79B16/20118172101010406/epubprivate/OEBPS/Images/40906_47_2.jpg?sign=1739534850-asvdFwRZIe5FxaCsupGHg2iURvdgrZNq-0-1a6d041873c3020096e8ea5b93c3e087)
2.函数组件
函数组件相较于类组件,定义更便捷,使用更灵活,尤其搭配Hooks使用能够在某些场景下替代类组件。函数组件的定义如下:
![](https://epubservercos.yuewen.com/D79B16/20118172101010406/epubprivate/OEBPS/Images/40906_48_1.jpg?sign=1739534850-98TqqKtub1rJXpaPHpIplQ4tIXWfNISH-0-edcfd21afc8cfa3e15d1c467b5e3a9cc)
或者使用箭头函数,写法如下:
![](https://epubservercos.yuewen.com/D79B16/20118172101010406/epubprivate/OEBPS/Images/40906_48_2.jpg?sign=1739534850-fjaosQgjdnTzxUwqcOp1zytPeeJpM8Wm-0-df3aa83556b3ca6c5c72b3fccf1263f3)
注:在组件中,无论是否使用Taro这个对象,都应该将@tarojs/taro包引入。无论组件返回值多么简单,都尽量使用@tarojs/components提供的组件包裹,而不应该直接返回数字或字符串等。
定义好组件后,最终需要将最上层组件也就是根组件挂载到DOM节点上:
![](https://epubservercos.yuewen.com/D79B16/20118172101010406/epubprivate/OEBPS/Images/40906_48_3.jpg?sign=1739534850-PdOUhctLzT2qKc3OBmCRRS3dI4R3BWsk-0-9939bd07446261fb678b962c7781f531)
为了方便讲解,后续章节将统一使用类组件,当然我们也会在Hooks章节详细介绍函数组件的知识。
2.2.3 props
很多时候,组件中使用的某些数据可能需要外部提供,就像我们使用HTML中的图片标签时,需要设置src属性才能显示对应图片。假如现在定义了一个名叫Timg的类似图片img的组件,组件内部应该怎样获取外部传入的属性数据并使用呢?答案是使用props,代码示例如下:
![](https://epubservercos.yuewen.com/D79B16/20118172101010406/epubprivate/OEBPS/Images/40906_49_1.jpg?sign=1739534850-YlRgyk29XcIo6Tp3k4wLvfdgQCKLsTQ7-0-79537c711e16fa281235a7e74ef18912)
效果如下图所示。
![](https://epubservercos.yuewen.com/D79B16/20118172101010406/epubprivate/OEBPS/Images/40906_49_2.jpg?sign=1739534850-5yoPkkCWh7lpxLs74M65STgJ1ZQITZ2r-0-755adf93b86f6c10f15b0db69298436a)
通过props,可以将数据传递给组件,组件内部通过this.props获取对应的属性数据,渲染即可。
有时,某些属性数据并不一定是外部必须传入的,因此我们在定义组件时,可以设置默认属性数据,如上例:
![](https://epubservercos.yuewen.com/D79B16/20118172101010406/epubprivate/OEBPS/Images/40906_50_1.jpg?sign=1739534850-FD2v87LtmkLH6DaEqpLLn7Kd4X34xbCy-0-6fdea231651242b5cac10c19a6692690)
若在使用Timg组件时不传入src属性,则Timg组件会使用我们通过defaultProps设置的src属性的默认数据渲染页面。反之,Timg组件会使用外部传入的src属性数据进行渲染。
2.2.4 state
组件中还有一类数据,它具备以下几个特征:
· 数据私有,仅供组件内部使用。
· 数据需要根据某些操作发生更改,并触发视图更新。
这些特征正是组件状态state期望具备的,满足这些特征的数据一般都要考虑放入组件状态state中。
我们现在想设计一个组件,组件中有一个状态count,该值每过一秒增加1,并在增加后显示在页面中。代码设计如下:
![](https://epubservercos.yuewen.com/D79B16/20118172101010406/epubprivate/OEBPS/Images/40906_50_2.jpg?sign=1739534850-4yjCZSvhiLZQFkcXFnD3hXeBZaOSwMLk-0-d7d8aff4290ce31411ddcc06f87b2990)
![](https://epubservercos.yuewen.com/D79B16/20118172101010406/epubprivate/OEBPS/Images/40906_51_1.jpg?sign=1739534850-kr4gXHasuoIxpXyMnbMx0JFaNgfyZbsn-0-9b87fc595cf045a83bbf23054c2972e9)
通过这个示例,我们可以总结出state的用法:
· 类组件中有一个名叫state的预定义属性,该属性为对象,对象中记录了关于该组件的所有状态。如上例中,状态count的初始值为1。
· 在需要更改这个状态时,调用组件的setState方法,这个方法继承自Taro.Component。
· 在JSX中,通过this.state获取对应状态值并使用。
注:任何时候都不要通过赋值的形式直接修改state,如上例中,this.state.count=this.state.count+1这种赋值方式是错误的,正确的操作应该是用this.setState更新指定状态。
2.2.5 样式
看了以上与组件相关的例子,对于组件,你是否有种似曾相识的感觉?其实从某种角度来看,组件类似HTML中的标签,这样类比后,关于组件的很多问题都能迎刃而解。组件中样式的使用方法和HTML中一致,也分为两种:内联样式和外部样式。
1.内联样式
组件的内联样式通过style属性指定。与HTML标签的style属性不同的是,组件的style属性接收一个对象:
![](https://epubservercos.yuewen.com/D79B16/20118172101010406/epubprivate/OEBPS/Images/40906_52_1.jpg?sign=1739534850-7juJozPLGGQOnN1AjkTnVoNi3mFtjVvD-0-fc32c0e716f2547bff5ae54c4e7310ee)
使用内联样式需要注意以下几点:
· 如果不指定尺寸单位,则会默认解析为px,如前面代码中的width:100,会被解析为width:'100px'。
· 属性名改为驼峰式命名,如background-color改为backgroundColor。
2.外部样式
外部样式可以使用CSS、Less、Sass等文件定义样式,然后在对应的模块文件中引入。我们以Less为例:
![](https://epubservercos.yuewen.com/D79B16/20118172101010406/epubprivate/OEBPS/Images/40906_52_2.jpg?sign=1739534850-xhzHpA7ORIHESDYQtqi4tKtctqrfM1da-0-c34dd1cb970885bb9d24b11e0b189454)
![](https://epubservercos.yuewen.com/D79B16/20118172101010406/epubprivate/OEBPS/Images/40906_53_1.jpg?sign=1739534850-9ldVbYURIuaMpwSub6Qo3RqS3ClluLrM-0-5bb8bd70403e356ed5f6bd243b8b19ca)
注:我们前面就有提到,因为class为JavaScript关键字,不能出现在JSX中,所以需要使用className替代class。