你好,谈一下自己的经验吧。
组件是一种对界面逻辑进行的抽象,本质上还是对代码的封装,目的是节约代码量,提升工作效率。所以判断某两个组件的子组件是否应该设计成一个统一的,需要思考一下,两个子组件的业务相似率有多高。
在vue下,组件的核心是vModel,methods只是对vModel的修改,而template只是将vModel转换为界面。只要两个子组件的vModel能大致统一,我们就可以把它封装成同一个组件,并提供不同的api给外部使用即可。
我举个我自己项目的例子
一个项目里,表单一定是一个重现率很高的场景。作为一个较大的项目,一定要考虑如何将表单抽象出来,可以换来开发效率的极大提升。但是具体要抽象到什么程度,要看具体场景。
比如我们的移动端项目,在全国有20多个不同版本,具有相似但不同的业务,且各省业务本身还在不断增加,差异会越来越大,无法将项目本身产品化。经观察,业务本身虽然无法被产品化,但是开发环境是可以做到的。所以我们的解决方案就是将界面数据化,由服务端直接配置数据,在前端渲染出完整界面。这个在vue下是很容易实现的
比如我们描述一个简单的界面,他具有一个form,一个tab组件,下边4个tab,各是 一个数据列表,一个图片列表,一个图表,一个处理流程,那我们就可以用数据将界面描述出来
{
form : {
action="xxxx.url",
....
},
tabs : [
{type:"listview",data:[...]} ,
{type:"photoview",data:[...]} ,
{type:"chart",data:[...]} ,
{type:"flow",data:[...]}
]
}
将其作为一个约定,我们前端通过数据就知道应该调用哪些组件对界面进行渲染了。
说回表单,各种表单项的vModel是基本一致的,关键的属性大家都有 ,如:label,name,value,validate。那我们就可以将其抽象为一个配置,再实现为一个统一的组件。
以下是我的表单配置,基本上已经描述了普通表单应该有的功能:
[
{
"name":"orderKey",
"label":"排序",
"type":"radio",
"value":"v1",
"valid" : "required|range(7,10)|async('/xxxx/xxxx.action')",
"options" : [
{value:"v1",label:"v1"},
{value:"v2",label:"v2"},
{value:"v3",label:"v3"}
]
},
{
"name":"MainSn",
"label":"业务号码",
"show" : "form.orderKey==='v1'",
"valid" : "required|range(7,8)",
"type":"text",
"value" : "xxxx"
},
{
"name":"MainSn3",
"label":"禁用",
"type":"select",
"disabled" : true,
"value" : "xxxx",
"options" : [
{value:"xxxx",label:"xxxxx"},
{value:"xxxx",label:"xxxxx"}
]
},
{
"name":"range1",
"label":"range1",
"disabled" : true,
"prefix" : "%",
"value" : 60,
"type":"range"
}
]
可见配置基本上相似率很高,select和radio的配置几乎是一模一样的,但是实际显示效果却相差很大
动手设计前,我们要考虑:它有一个props,以接收表单项配置。然后需要有一个手段将表单产生的结果返回给父组件使用。按现在主流方式,子组件向父组件输送信息,一般是采用vuex等解决方案,我这里由于实际考虑,采用的方式是 子组件接收一个消息,在消息回调中输出表单结果。
由于我们的表单配置有多个配置项,那么我们下一步就要遍历配置项并生成UI,大致是这个样子
下一步,我们只需要根据表单项不同,为其编写不同的交互就行了。
之后我们要取回用户输入的结果
表单提供两个方法,
第一个是个同步方法,不经验证直接返回表单数据
第二个方法是验证表单,如成功,返回表单数据。如验证失败,返回验证信息。这里由于表单验证有成功失败两个状态,且验证项有可能是异步的,所以使用了promise。
布局不同的问题,以上已经解答了,数据不同,要看看能否在传入组件前尽量将其统一。