之前写了个小组件, 首先感谢大佬们提的意见, 今天我要总结一下关于开发过程中, 什么情况下我们要去封装自己的组件, 当然这个我自己一步步感觉出来的, 大家可能也有自己的经验, 如果大家有更好的方法, 也希望大家可以不吝赐教留言给我和不小心进来的同学
好了不多bb, 这次我是来解析封装多行编辑组件的
多行编辑组件, 一般在管理系统的大表单中出现的几率比较大, 而且业务越复杂的表单越有几率出现他的身影, 部分人可能还没听过这个东西, 我先介绍一下吧, 这个东西也叫"动态增减表单项", 就是这个东西
再element-ui中是这样的
网上对这个东西的介绍只能算一般多吧, jquery封装的组件可能多一点, 框架的UI虽然也有封装, 但是功能都偏少
好了现在又到了我们会1+1, 就要算微积分了的时候了, 当然我们也不能凭空去算, 至少看一下前人的经验, 我看过稍微完整一点的就是Ant Design Pro管理系统模板的, 当然这个是react的, 但是无所谓是用的什么框架, 我们先看一下他的
功能挺多的了, 而且他是在表格中实现的, 看起来比较整齐, 当然用Layout布局也可以, 都没什么问题, 我这次就站在巨人肩膀上用element-ui的表格布局实现以下他这个吧, 毕竟我们要做vue的多行编辑功能, 先总结他的已有功能吧, 然后我再添加点
总结:
a. 有个表头, 或者叫列名, 当然我们在接下来的输入框中我们还会继续给他提醒
b. 要有一个操作列, 5种功能
i. 添加: 当一个新的一行出现的时候展示, 填完信息后点击添加变为不可编辑状态
ii. 删除: 删除当前行
iii. 编辑: 当已经点过添加, 变为不可编辑装填展示, 点击后变为可编辑状态
vi. 保存: 编辑后进行保存数据
v. 取消: 取消当前编辑的内容, 类似于一个还原, 然后并变为不可编辑状态
c. 要有一个添加一行的功能
d. 最主要的就是中心编辑展示部分, 一种是展示状态, 不可编辑, 纯文本, 一种是输入框状态, 可编辑
好, 有了整理我们就很清楚了, 具体什么用什么功能的组件, 但是这些并不能满足我们的需求, 我们还要再添加一点功能
新增:
a. 表单验证功能, 其实就是element-ui的那个多行编辑的验证功能, 让他稍微变得灵活一点
b. 增加日期框, 数字输入框, select框, 查询回显框(就用我之前写的那个), 不过这样会让这两个组件绑定言重, 但是这个对于我的业务来说是很有必要的, 虽然严重但是对我构建项目来说却更加便利
这里也引出一个点, ui库已经给你封装好了你就复制粘贴嵌套一下就好了, 为什么还要多此一举?
我大体来回答一下, 我们的开发与封装就是要基于业务和开发便利以及便于维护为目的, 而ui框架的开发更多的是为了去适应更多的人使用, 更加便利易懂
打个比喻: ui库不是做出一个个"人", 而是要做出一个个骨架, 一种种外貌, 让我们自己去捏人捏脸, 让我们自己拼接
而融入到业务中, 我们在这样是不能够达到最大方便的, 我们在业务中就是要吧这些零散的骨架适当组装, 组装出可能用到的各种腿, 各种胳膊, 身子, 美丽且满满头发的脑袋瓜, 我们再去拿这些拼人就好了, 原来我们要ui的零散的好多拼成一个页面, 现在我们只要拿几个稍大的功能组件一组就够了, 可能很多人在自己的开发中已经应用了这种方法, 没问题, 我觉得这么做有点棒棒的
开始操作起来, 不过我相信你已经明白该怎么做了, 下面还是按照上一篇文档的节奏来写, 我们现在已经总结完功能了, 接下来我们就是要设计基本的结构
1. 基本结构
<div>
<table>
<!-- 表头 -->
<thead>
<td></td> *n
</thead>
<!-- 内容 -->
<tr>
<td> *n
<input>
</td>
<!-- 控制列 -->
<td>
<button>确认</button>
<button>取消</button>
<button>删除</button>
<button>编辑</button>
</td>
</tr>
</table>
<button>新增一行</button>
</div>
*n的地方代表了接下来我们要用循环创建
把结构一屡, 没多少东西, 接下来我们就要确定哪些东西是要外部控制的
2. 外部传输的方法
先插入一点原理, 这个多行编辑是怎么实现的
再vue中, 我们通过v-for循环创建一组对应的标签, 所以如果我们对循环的那个变量不断的push新的值自然就会被v-for渲染到页面, 好了继续整理
a. 首先传入一个新增一行的方法, 上面介绍了, 我们只要给v-for遍历的那个变量push就好了
b. 要传入控制当前行状态的方法, 这个添加就是要当我们完成单行编辑的时候, 先去验证是否必填的已经填完了, 然后让此行变成确定状态, 不可再编辑, 也可反之变为可编辑状态
c. 传入一个删除的方法, 删除就是从那个遍历的参数中把当前行的内容删除就可以了, 我们可以通过给每一行多定义一个隐藏参数为时间戳, 让每一行保持独立
d. 传入取消的方法, 我们当再修改途中, 想还原之前填写的状态用, 所以我们还要暂存一下当前点击修改的那行初始值
简单写一下这个
methods:{
pushlist() {
//添加一行
},
editstatus(index){
//控制单行的开关状态
},
delrow(index) {
//删除本行
},
cancelrest(index, sw, row) {
//取消时恢复本行
},
}
整理了方法, 我们就要看看这些方法中, 以及应用中要用到哪些从外部传入的参数呢
3. 外部传入参数
a. 要传入一个表头的数组
b. 要传入一个单行内要有几列, 也就是一行有几个输入框的数组, 这个比较麻烦我们要慢慢整理
c. 要传入整个多行编辑数据, 初始就是个空数组
4. 接下来把结构补全
<div id="inputList">
<!-- 因为要做rule验证, 所以要有form -->
<el-form :model="listModel">
<!-- 表格, tableData为多行编辑的数据, 我们要用他的长度渲染表格有几行所以要绑定data -->
<el-table :data="listModel.tableData" style="width: 100%" size="mini">
<!-- 在element-ui中的table是自动绑定列名称的,所以就合成一个数组rowTable中 -->
<el-table-column v-for="(item,index) in rowTable" :key="index" :label="item.label" :width="item.width">
<!-- 要获取单行数据进行处理, 所以要绑定scope -->
<template slot-scope="scope">
<!-- 当只展示时, 用span进行展示 -->
<span v-show="scope.row.status">{{ scope.row[item.prop] }}</span>
<!-- 编辑时, 用form + input等方式编辑 -->
<el-form-item v-show="!scope.row.status" :prop="'tableData.'+scope.$index+'.'+item.prop" :rules="item.rule"
:ref="'tableData.'+scope.$index+'.'+item.prop">
<el-input size="mini" v-model="listModel.tableData[scope.$index][item.prop]"
v-if="item.type == 'text' || !item.hasOwnProperty('type')" :disabled="item.disabled"></el-input>
</el-form-item>
</template>
</el-table-column>
<!-- 单独一列, 操作列 -->
<el-table-column label="操作">
<template slot-scope="scope">
<el-button size="mini" @click="handleEdit(scope.$index, scope.row.status, scope.row)">
{{scope.row.status?'编辑':'确定'}}</el-button>
<el-button size="mini" type="danger" @click="handleDelete(scope.$index)">删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 新增一行操作 -->
<el-button size="mini" @click="addRowList" class="addBtn">新增一行</el-button>
</el-form>
</div>
5. 把需要循环创建的参数提取出来设计参数
a. rowTable, 看看循环他我们需要从中拿到那些数据来用, 把这些数据一总结放到个对象里, 这个就创建完了
{
//显示的名称
label: "邮箱",
//input宽度
width: "180",
//绑定prop
prop: "email",
//验证规则
rule: [{ required: true, message: "年龄不能为空" }],
//input类型 "number", "date", "text", "search", "select", 暂时想了这么多, search就是上一篇的类型
type: "number",
//是否允许编辑, 有的内容是只由别的带出来, 只能看或者修改别的框改变这个, 所以此框禁用
disabled: false
},
b. tableData这个是自动绑定的, 我们要思考除了表格内容我们还要什么参数
// form绑定的数据
listModel: {
//表格绑定的数据
tableData: [
{
//表格一行的数据
email: "email1@qq.com",
email1: "",
email2: "email2@qq.com",
email3: "email3@qq.com",
email4: "email4@qq.com",
email5: 123,
//开关, 决定是否是展示状态还是编辑状态, disabled禁用属于编辑状态
status: false,
//确定每一行唯一的key
key: new Date().getTime()
}
]
}
6. 由于这个功能相对复杂, 我们还需要内部定制一个参数用于临时使用
a. 当我们点编辑的时候要暂存这个数据, 以备用户点击取消的时候恢复使用, 因为用户可能一次点了好几个编辑, 我们都要存储, 又因为我们有一个key值可以当我们的索引, 我们只需要把用户点击编辑的数据push一个数组就够了
cancelListData:[
{
//表格一行的数据
email: "email1@qq.com",
email1: "",
email2: "email2@qq.com",
email3: "email3@qq.com",
email4: "email4@qq.com",
email5: 123,
status: false,
//确定每一行唯一的key
key: new Date().getTime()
}
]
7. 好了基本需要的东西我们都准备完了, 接下来还要实现组件里的方法
methods:{
addRowListJudge(){
// 判断是否有未操作完的行, 然后才允许新增一行, 也是为了提交表单时判断更为简便
},
handleEdit(){
// 调用传入的修改状态的方法
},
handleCancel(){
// 调用传入的取消方法
},
handleDelete(){
// 调用传入的删除行的方法
},
}
8. 最后一步就是实现各个方法就可以了, 这里就不细写了, 具体还是直接看代码吧, 代码放在:https://github.com/wqliusong/happy/tree/master/rowList, 有可以直接运行的单页面下载就可以看, 也希望各位路过的朋友能给提点意见, 先谢过
总结: 最后来说一下自己遇到的一些家长里短的问题
a. 第一个就是浅拷贝深拷贝的问题, 有很多人说浅拷贝深拷贝有啥用, 平时也基本遇不到, 这里就给了一个例子, 代码中有注释, 具体会遇到什么问题, 我在这里说一下, 当我在从不可编辑变为可编辑的时候我要先备份一下当前行, 便于点取消的时候能够恢复, 如果我用了浅拷贝, 这个数组里的内容指向的还是同一个地址, 当我改变当前行的时候, 其实我备份的那个也已经变了, 所以就不能恢复了, 即一个动, 全都动, 所以这里要画个重点
b. 第二个就是vue视图更新的问题, 数组内容更新, vue视图是不会自动更新的, 具体可以查看官网的https://cn.vuejs.org/v2/guide/reactivity.html, 所以用splice去处理数组, 当然还有好多办法, splice比较简单
c. 关于业务封装组价的问题, 因为每个人的业务是不同的, 做出符合各种功能的组件是很难的, 所以各个ui库会尽量的把功能拆分的细小一点, 也会更加灵活, 而我们在实际业务开发中, 我们想要的是更加节省时间, 所以在原有细小的基础上做一些相对功能丰富一点, 而且更易于配置的组件, 像这个组件, 我们除了在开发中调用它, 我们甚至只要几个空间, 在数据库中配置这个大json就可以了, 而不用每次都要在前端配置
当然不同的公司也会有不同的考虑, 还是希望大家都能有所进步, 也可以把你们的想法告诉我, 带我这个渣渣一起进步, 再次感谢