如何封装业务组件 多行编辑功能

以前写了个小组件, 首先感谢大佬们提的意见, 今天我要总结一下关于开发过程当中, 什么状况下咱们要去封装本身的组件, 固然这个我本身一步步感受出来的, 你们可能也有本身的经验, 若是你们有更好的方法, 也但愿你们能够不吝赐教留言给我和不当心进来的同窗html

好了很少bb, 此次我是来解析封装多行编辑组件的前端

多行编辑组件, 通常在管理系统的大表单中出现的概率比较大, 并且业务越复杂的表单越有概率出现他的身影, 部分人可能还没听过这个东西, 我先介绍一下吧, 这个东西也叫"动态增减表单项", 就是这个东西vue

再element-ui中是这样的react

网上对这个东西的介绍只能算通常多吧, jquery封装的组件可能多一点, 框架的UI虽然也有封装, 可是功能都偏少jquery

好了如今又到了咱们会1+1, 就要算微积分了的时候了, 固然咱们也不能凭空去算, 至少看一下前人的经验, 我看过稍微完整一点的就是Ant Design Pro管理系统模板的, 固然这个是react的, 可是无所谓是用的什么框架, 咱们先看一下他的git

功能挺多的了, 并且他是在表格中实现的, 看起来比较整齐, 固然用Layout布局也能够, 都没什么问题, 我此次就站在巨人肩膀上用element-ui的表格布局实现如下他这个吧, 毕竟咱们要作vue的多行编辑功能, 先总结他的已有功能吧, 而后我再添加点github

总结:

a. 有个表头, 或者叫列名, 固然咱们在接下来的输入框中咱们还会继续给他提醒
b. 要有一个操做列, 5种功能
i. 添加: 当一个新的一行出现的时候展现, 填完信息后点击添加变为不可编辑状态
ii. 删除: 删除当前行
iii. 编辑: 当已经点过添加, 变为不可编辑装填展现, 点击后变为可编辑状态
vi. 保存: 编辑后进行保存数据
v. 取消: 取消当前编辑的内容, 相似于一个还原, 而后并变为不可编辑状态
c. 要有一个添加一行的功能
d. 最主要的就是中心编辑展现部分, 一种是展现状态, 不可编辑, 纯文本, 一种是输入框状态, 可编辑

好, 有了整理咱们就很清楚了, 具体什么用什么功能的组件, 可是这些并不能知足咱们的需求, 咱们还要再添加一点功能数据库

新增:

a. 表单验证功能, 其实就是element-ui的那个多行编辑的验证功能, 让他稍微变得灵活一点
b. 增长日期框, 数字输入框, select框, 查询回显框(就用我以前写的那个), 不过这样会让这两个组件绑定言重, 可是这个对于个人业务来讲是颇有必要的, 虽然严重可是对我构建项目来讲却更加便利

这里也引出一个点, ui库已经给你封装好了你就复制粘贴嵌套一下就行了, 为何还要画蛇添足?element-ui

我大致来回答一下, 咱们的开发与封装就是要基于业务和开发便利以及便于维护为目的, 而ui框架的开发更多的是为了去适应更多的人使用, 更加便利易懂 打个比喻: ui库不是作出一个个"人", 而是要作出一个个骨架, 一种种外貌, 让咱们本身去捏人捏脸, 让咱们本身拼接 而融入到业务中, 咱们在这样是不可以达到最大方便的, 咱们在业务中就是要吧这些零散的骨架适当组装, 组装出可能用到的各类腿, 各类胳膊, 身子, 美丽且满满头发的脑壳瓜, 咱们再去拿这些拼人就行了, 原来咱们要ui的零散的好多拼成一个页面, 如今咱们只要拿几个稍大的功能组件一组就够了, 可能不少人在本身的开发中已经应用了这种方法, 没问题, 我以为这么作有点棒棒的json

开始操做起来, 不过我相信你已经明白该怎么作了, 下面仍是按照上一篇文档的节奏来写, 咱们如今已经总结完功能了, 接下来咱们就是要设计基本的结构

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. 最后一步就是实现各个方法就能够了, 这里就不细写了, 具体仍是直接看代码吧, 代码放在:github.com/wqliusong/h…, 有能够直接运行的单页面下载就能够看, 也能够预览wqliusong.github.io/happy/rowLi…, 也但愿各位路过的朋友能给提点意见, 先谢过

总结: 最后来讲一下本身遇到的一些家长里短的问题

a. 第一个就是浅拷贝深拷贝的问题, 有不少人说浅拷贝深拷贝有啥用, 平时也基本遇不到, 这里就给了一个例子, 代码中有注释, 具体会遇到什么问题, 我在这里说一下, 当我在从不可编辑变为可编辑的时候我要先备份一下当前行, 便于点取消的时候可以恢复, 若是我用了浅拷贝, 这个数组里的内容指向的仍是同一个地址, 当我改变当前行的时候, 其实我备份的那个也已经变了, 因此就不能恢复了, 即一个动, 全都动, 因此这里要画个重点

b. 第二个就是vue视图更新的问题, 数组内容更新, vue视图是不会自动更新的, 具体能够查看官网的cn.vuejs.org/v2/guide/re…, 因此用splice去处理数组, 固然还有好多办法, splice比较简单

c. 关于业务封装组价的问题, 由于每一个人的业务是不一样的, 作出符合各类功能的组件是很难的, 因此各个ui库会尽可能的把功能拆分的细小一点, 也会更加灵活, 而咱们在实际业务开发中, 咱们想要的是更加节省时间, 因此在原有细小的基础上作一些相对功能丰富一点, 并且更易于配置的组件, 像这个组件, 咱们除了在开发中调用它, 咱们甚至只要几个空间, 在数据库中配置这个大json就能够了, 而不用每次都要在前端配置

固然不一样的公司也会有不一样的考虑, 仍是但愿你们都能有所进步, 也能够把大家的想法告诉我, 带我这个渣渣一块儿进步, 再次感谢

相关文章
相关标签/搜索