17.Vue技术栈开发实战-可编辑表格的实现

通过对iview的table表格的封装,实现如何自定义表格的内容。实现一个可编辑的表格。

为了节省时间,首先已经做了一些准备
首先是已经创建了table页

然后写了一个api,用来获取表格数据。

然后在mock里面也进行了处理。返回了数据的响应

tools里面封装了一个方法doCustomTImes

times是循环的次数,callback是回调函数。


执行循环5次,根据template生成5条数据记录。

最后在table页调用访问api的方法

可编辑表格组件

创建edit-table组件。

index.js内,引入并导出组件

组装封装,只用到iview里面的table组件。外面不用包裹顶层的div直接用Table就可以了。

有两个需要传的重要的属性,一个是定义列的数组,一个是数据的数组。在table.vue里面我们已经定义好了。 


key就是绑定的字段值,title就是列的标题。editable是我们自定义的属性,并不是iview的属性。

引入组件并注册

组件内定义属性 columns是一个空的数组,数组设置默认值,要写一个回调函数,返回一个空数组。


把属性传入Table组件。

给表格添加可编辑的按钮

要给这个表格添加一个可编辑的按钮。是不是要在columns里面给这个列添加一个render回调函数呢?如果你在这里要自己写的话,是要加一个render,然后传入一个回调函数。

我们既然要封装一个可编辑表格,那么这个工作肯定是要内部做了。
所以在哪去处理,这里列数组的东西呢?
首先在计算属性里面 我们拿到了列

在这里我们就要会columns做处理了。在这里定义一个indiseColumns,因为我们不能直接修改父组件传递过来的数据的。如果要修改就必须抛出一个事件,在父组件内接收事件,在事件的绑定回调函数里面去做数据的修改。 

这里我们用map做映射

如果传入的列有render函数,说明在外面自定义了render

只要是没有自带render,并且editable为true的情况下。

这里是一个解构赋值的形式

第一个参数是组件名,第二个参数是可配置的属性,第二个参数是可选的。

如果没有需要可设置的值,就把它删掉。

第三个参数是当前这个节点的子节点,如果里面就写一个字符串。它渲染出来的就是包含这个字符串的div


如果你是一个组件,第三个参数就是一个数组,比如我们渲染之前封装的CountTo组件,然后后面定义相关的属性。
第三个参数一定是一个数组或者是字符串。这是render函数的写法。

jsx

为了简介简便,我们用jsx的写法。直接返回一个括号,在括号里面要渲染我们的标签。

这里必须有一个最外层的div包裹。任何东西都包在这个div里面。


点击这里就编程一个输入框。点击保存输入框小时,文字显示了。这里应该是一个v-if和v-else的逻辑
 
但是在jsx里面我们没法用v-if这些指令。所以我们要通过js去判断这个逻辑。我们的逻辑和变量都要用花括号来包裹。

先点击第一行编辑  第一个22就编程输入框,再点击20的数字,20这里编程输入框。同时只能编辑一个单元格。那么我可以给每个单元格一个标志。当我点击某个单元格的编辑按钮的时候,让那个全局的值,变成党员个格的值,通过这个全局的标志来判断当前哪个单元格应该显示输入框。

定义全局的变量。这个edittingId,表格里面每一行都有一个行号。每一列都有一个key值。我们通过行号和key值就能确定单元格。我们的这个edittingId就是行号和key拼接起来,就能代表一个单元格。

先把这三个值打印出来,看一下

表格里最后用的是insideColumns



需要定义这个变量





打印出来的值。

第三个值

这样就获取到这一列的单元格

接下来要加一个按钮,iview的组件呢在jsx里面 要用i-的形式。

增加编辑按钮。

接下来要判断点击的是哪个单元格的按钮。iview里面的button有自带的click事件,所以这里要用on-的前缀 后面拼上click

直接没有传参数的调用,记得要用大括号,括起来。


传参数要用.bind去执行,要在this上去执行,第一个参数是this

对象结构赋值的形式去写。传入row、index、column


方法这里就要以同样的方式去接收






拼接edittingId

当点击的时候,要把默认的数据填进去





加个样式


内容和输入框是二选一的形式
如果当前的拼接的edttingId是当前的,那么显然input标签。



把input标签的代码移到这里

点击才会显示输入框

给input绑定事件。input我们平时用的时候是用v-model去绑定。v-model就相当于绑定value值同时绑定一个input事件,通过input事件修改这个value值。在这里我们要接收这个input事件

定义一个全局的变量去接收它

这样每次修改内容的时候,就把它绑定到到这个edttingContent变量里面。

把这提取出来一个常量。



点击编辑后,这里编程保存。

判断,当前点击是编辑状态

否则就让处于编辑状态。

我们要修改传入的tableData。所以这里改成用 v-model去绑定tableData

那么组件内属性就要用value了。这是固定的写法

这里需要把value值深拷贝一份去修改深拷贝后的数组,然后把这个数组通过emit传到父组件内。

深拷贝

深拷贝我们安装一个插件 。自己安装。

先引进来



修改后点保存,只是console输出了。

修改后把this.edittingId变成一个空的字符串

这样这个内容就编辑好了

再添加一个事件,我们一般是需要获取你编辑的是哪一行哪一列。on-edit把编辑的信息都导出去。

再增加一个NewValue告诉 父组件,更新后的值是什么

保存后,把这个edittingContent也变成空

父组件内接收这个事件

接收这四个值,并打印出来。

编辑--保存后--

编辑后的值

后端如果获取了新的数据,如果表头也发生了变化。所以我们要监听columns的更新

用watch监听。首先把这套逻辑提取出来封装成一个方法。

监听columns,如果更新了我们再执行一下

这样我们编辑单个单元格就完成了

封装第二个表格

可以同时编辑多个单元格

引入这个组件

传的数据还是这两个


刚才是编辑一个单元格,可以通过唯一的id去实现的。没个单元格都可以变为同时编辑的状态,所有的都显示输入框,那么就不能通过这个唯一id来实现了。所以这个时候,应该是两份数据,把传进来的表格数据copy一份,然后在这个上面,给这个数据对象做数据,每一行都来维护一个编辑状态。
比如第一行,它是一个对象,里面有三个字段。我把编程编辑状态的这一列key传进去放在一个数组里。通过判断当前的key,这一行的key在不在这个数组里 ,来判断它是不是显示状态。

实际操作开始

我们还是在之类进行改造。首先还是判断这个columns,判断当前有没有可编辑的。

数据字段上给他一个新的字段keyArray

每一行的数据对象上添加edittingKeyArr

如果行数据对象上有这个keyArr这个字段,

并且当前这个column.key在这个数组里,那就说明你这一行这一列是编辑状态下,那么我们就显示这个输入框。

下面同样的判断条件



这里先深拷贝一份

我们要判断当前行数据是 有没有的, 如果有就取里面的edittingKeyArr如果没有就是空的数组[]

数据变了的时候,要把value重新拷贝一下。所以监听value值的变化,值变的时候也执行下this.handleColumns()方法

取当前行上的edittingKeyArra.如果有这个值说明是点击过当前行按钮的 。因为我们点一下会把这个key传进去。

还是先来写没有这个edittingKeyArra的情况吧。
判断rowObj这个对象上有edittingKeyArr属性并且,edittingKeyArr.lenhth表示里面是有东西的,这里也就是length不为0的意思,

那么我们就把edittingKeyArr里面拆分出来 ,通过三个点的操作符,并且把column.key当前行的key值,也放到这个数组里面。


没有这个字段,那么就把当前column.key添加进去。



这样还不够,这样修改这个数组,还不是一个深度的watch

使用splice才会触发这个视图的更新。
splice会在你这个index索引的位置上,第二个参数传入要删除几个元素,第三个参数是你要添加的元素。删掉一个添加一个相当于是一个替换

这里为0,先来测试下

点击都可以编辑了

点击保存,变成编辑状态

我们要判断当前行的key在不在数组里。在的话,说明它是编辑状态,

如果有这个数组,

那么就取索引号,

没有这个数组,直接就-1

如果大于-1 说明在这个数组里面找到了当前这个单元格的key。说明他就是编辑状态。



把修改后的对象替换到insideData里。用splice方法删一个,然后替换一个。

通过提交一个input事件

来触发父组件的v-model 来替换传进来的tableData数据。

同时触发on-edit事件

下面两行代码删掉。删掉后如下。

测试修改后,没有替换

输出值,看下实际的有没有被改变


值没有被改变 ,还是21


是因为我们的handleInput还没有修改。文本框的值改变了要触发handleInput事件

用bind来绑定,传入三个值row、index、column这三个值



第四个参数就是原来默认传入的值。前三个就是上面传入的值。

修改后视图更新了

注意事项


在封装这个组件的时候,有些人会遇到这么个问题,直接去修改这个value值。

修改的时候你不是修改的insideData。而是你通过一个事件

通过input事件每次修改的时候,都触发新的值,你是在handleInput里面去做input,然后去提交。然后父组件修改tableData

这样就会有问题了。你每次在文本框内修改内容的时,其实都是通过input事件把修改后的东西,修改之后然后再新的表格数据那个数组,推送到父组件,父组件值改变之后,你绑定的这个tableData改变之后呢,他其实是会重新渲染这个组件,因为数据变了。视图也要变化。
 

那你这个时候重新渲染,输入框就被重新渲染了,你现在是编辑的状态,是获取焦点了。重新渲染的焦点就消失了。你再继续输入就没法输入了。所以你就需要输入一次,点一下文本框旁边的空白,点击获取焦点输入一下。

演示这个效果

在这个地方触发input

输入一下焦点就失去了,是因为这个表格组件重新渲染了。再点击文本框才能输入,但是再输入一次,又没法输入了。

所以这个地方不是在这里去触发input,而是在点完保存之后,再去重新触发视图的渲染。这个时候就不会有问题了。



那么可以同时编辑多个单元的组件,我们就封装完成了 

注意点

就是在jsx里面没法使用v-if 等这些指令的,


要通过在花括号里写原生的js逻辑


绑定事件的时候呢,不需要传参数就可以直接这样

如果需要传参数,就需要用bind方法,绑定到这个this上。

箭头函数的方式传值

 

本节代码



 

结束

 

posted @ 2020-07-05 23:52  高山-景行  阅读(1476)  评论(4编辑  收藏  举报