手记

基于数据驱动设计复杂页面

背景介绍:

最近公司启动了一个新的版本,我负责的一个的模块中有一个很复杂的新建的页面,表格里嵌套表格,三层数据,数据级联,组件较多.交互复杂,

下面是我做的一个简略图,为了保密我已将需求细节隐藏.(PS:没有table组件的墨刀,掩面苦笑,真难用)

从整个页面上分析,整体分为二部分,表单FA列表和表格TA

表单FA列表可以新增,删除,设为默认,其中一些表单项要求可以边输入边检索,选中选项后,自动将其他表单项填充

表格TA 首先是行内编辑,其次是行内的表单项之间存在级联关系,就是说,必须选中前一个行内表单,下一个表单项才有备选项,每个表单的备选项都是根据前面表单项变化而变化.

以上是表单TA的一条记录的行内编辑,这条记录的操作列有一个编辑按钮和删除按钮,点击编辑在此条记录的下方展示一个表单FB,

表单FB又包含一个表格TB和一个表单FC列表 表格TB可以增加记录,删除记录,记录中是行内编辑,编辑项也是级联的表单项

表达FC列表也是可以增删的. 表单FB有一个保存和取消按钮, 取消可以还原上次数据.

分析设计:

背景和要求都介绍清楚了,下面我们来分析一个这个页面,

刚刚拿到这个页面设计图的时候真的是一脸懵逼,多个表格嵌套还不算难,但是点击表格中编辑操作在此条记录下显示编辑的表单,这个要怎么实现.因为每条记录都是用 <tr> 在二个<tr>中夹在一个表单,这可能会破坏table的标签结构,导致table渲染错误,而且非常不好处理记录与表单的关联关系. 当时我的内心是一万个拒绝的.但是,但是,但是.....我没有当面拒绝而是先默不作声,会后再下去搜索资料,分析方案.虽然产品的要求很奇葩,而且这样设计也可能有很大风险,比如,页面逻辑不清,操作复杂,用户不会操作,但是内心有一个声音在向我说明,你进度的机会来了,你不是做够了那些只要拷贝一份就能满足要求的页面了吗?这个页面就当你晋级的考验吧.去满足它吧,满足那个频繁修改原型的产品.虽然这东西做出来也不一定见得好用.

闲话就聊到这里,我来说一下查的资料,我们使用的技术栈是vue,ele 于是我去看了一下ele的table组件,发现了这个

看了这种效果确实是可以实现的,于是F12开始分析表格结构

由此可见,在表格的tr中 第一个tr是正常的表格行,紧跟着的第二行是扩展表单,使用<td colspan="4"> 合并列,使其呈现出非表格样式,既然是这样的话,那我们在渲染表格的时候,就需要二条数据渲染成一条记录,另外一条在点击编辑按钮后显示.这个难题解决了...

接下来开始设计数据结构,别慌在这之前我想先谈一下前端数据驱动的页面设计

数据驱动:

关于数据驱动有的人解释为:当数据发生变化的时候,用户界面发生相应的变化,开发者不需要手动的去修改dom

相比以往jquery那种拿到数据后再使用选择器,操作dom的方法渲染页面,数据驱动有很好的扩展性和效率,要想改变页面,直接操作数据,多一条,少一条都可以直接在页面上反应出来.这也是得益于目前前端框架的飞速发展.这种数据驱动的方法解放了前端开发人员的双手,很少再去使用append,inserBefore等方法去去操作dom,直接在数组push一条数据就能立即在页面上体现出来.大大提高了效率和可维护性,扩展性.同时对于复杂页面也要求开放人员有一定的数据接口知识.

数据结构:

根据分析我设计的页面的大致数据结构为

const FAList = [] // FA表单列表对象const TATable = [{ // 正常tr对象formItem: {}, // 其他表单项expandContent: { // 扩展内容formItem: {}, // 其他表单项TBTable: [], // TB 表格数据FCForm: [] // FC 表单列表数据},expand: false, // 是否是扩展show: true // 是否显示},{ // 合并tr 扩展对象formItem: {}, // 其他表单项expandContent: { // 扩展内容formItem: {}, // 其他表单项TBTable: [{firstFormItem: '', // 选择的第一级数据secondFormItem: '', // 选择的第一级数据thirdFormItem: '', // 选择的第三级数据secondArr: [], // 备选的第二级数据thirdArr: [] // 备选第三级数据}], // TB 表格数据FCForm: [] // FC 表单列表数据},expand: true, // 是否是扩展show: true // 是否显示}]

 

第一条数据与第二条数据唯一的区别在expand属性,这个属性表示是否是扩展, 第二条始终是扩展对象,并且是否显示使用show这个属性来控制.由于每个级联的待选项都是独立的,所以直接将其设计到表单项里是比较稳妥的,虽然这会使数据对象庞大,更新缓慢,索引问题.

开发:

到了实际开发的时候

使用

<tr v-for="(item,index) in TATable" :key="index"><template v-if="!item.expand"><td></td>    <td></td>    <td></td>    <td></td>    <td></td></template><template v-if="item.expand && item.show"><td colspan="5"></td></template>
这段代码很重要,使用template标签做判断,在渲染时是不会渲染出来的,所以不会影响table的结构.

由于数据层层嵌套所以在渲染的时候需要特别注意一下 关于索引的问题,在处理添加,删除的函数了必要要用到索引,要注意是用的那一层的索引,还是二层的索引都需要.索引的维护也是一件很头疼的事.

另外有的时候事件处理函数可以直接传递对象 如更改firstFormItem 第一级数据,需要动态更改修改第二级第三级相关的数据,这个是时候就可以在dom上这样注册事件

<tr v-for="(serviceItem,serIndex) in methodBoList" :key="serIndex"><td><el-select placeholder="第一级"@change="changeInnerBusinessLine(serviceItem)" v-model="serviceItem.businessLine" clearable><el-option v-for="(litem,lindex) in bigComprehensive" :label="litem.bigClassName":value="litem.bigClassCode":key="lindex"></el-option></el-select></td>....</tr>

 

直接将serviceItem传入到处理函数中,在处理函数中将第二级,第三级相关数据改变.这样页面也会刷新

在开发中还遇到了一个问题,让我重新思考vue框架的父子组件的传值方式是否能否扩展,这个问题是这样的

在表单FA列表中有一个这样的表单项,能够输入,能够选,选择一个后,需要将其他表单项自动填充,由于是表单列表,在选择后.必然需要在回调函数里确定是当前列表中的那个对象.但是子组件注册回调函数时却不能包含父组件的变量,而且也不能在函数名后加括号(),

<child @cb="cb"></child>
<child @cb="cb()"></child>

第二种写法会报错.

最后实在没办法了,只能在点击子组件时获取索引保存起来,然后在选择后的回调函数中使用保存的索引找到要操作的对象进行更新数据.

不知道路过的大佬有什么好的办法,指点一下...... 这个问题可以总结为 在子组件的回调函数中如何添加父组件变量?

效果图:

效果图等我做个简单demo在放吧,最近忙着赶产品经理修改的需求

总结:

  • 数据结构真的很重要

  • 在拒绝之前要有理由说服自己,这个确实不能实现 或许真就是你晋级的机会

  • 设计的时候多考虑一下扩展性,因为你的产品经理很快就会改需求

  • 想要超越自我,就去实现一个能根据机壳自动调整手机主题的功能,

   谢谢阅读.如果觉得对你有帮助请记得点赞或收藏.欢迎留言讨论.你的支持是我出产优秀博客的动力.

2人推荐
随时随地看视频
慕课网APP

热门评论

图片挂了啊,看不到,我们也经常有这种需求,求作者能把图片弄出来,我也想看看大神怎么做的

图片看不到

太复杂了太复杂了点吧 这个

查看全部评论