惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

A
About on SuperTechFans
Y
Y Combinator Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Microsoft Security Blog
Microsoft Security Blog
aimingoo的专栏
aimingoo的专栏
I
InfoQ
C
Check Point Blog
IT之家
IT之家
MyScale Blog
MyScale Blog
Apple Machine Learning Research
Apple Machine Learning Research
Vercel News
Vercel News
Last Week in AI
Last Week in AI
GbyAI
GbyAI
P
Proofpoint News Feed
量子位
Stack Overflow Blog
Stack Overflow Blog
Microsoft Azure Blog
Microsoft Azure Blog
月光博客
月光博客
阮一峰的网络日志
阮一峰的网络日志
人人都是产品经理
人人都是产品经理
B
Blog
T
The Blog of Author Tim Ferriss
H
Help Net Security
云风的 BLOG
云风的 BLOG

小松鼠的博客

记录一次线上k8s工作节点无法创建容器的问题排查思路与解决办法 记一次线上GoLang项目OOM排查过程 从LastPass转向拥抱开源KeePass的心路历程 故障定位与 AI 结合前后端编码实践 FileBeat收集nginx-ingress-controller日志 K8s云原生环境下文件描述符占用过高查询思路 2024年最新关闭火绒安全工具的开机自启方法 Kubernetes任务调度实践-Go语言实现Job和CronJob对比分析 离线更新k8s环境下的trivy漏洞库方法 使用Go语言接入Choerodon实现基于OAuth2的统一身份认证登录 在Vue2中自定义Switch组件并实现父子组件双向数据绑定 关于docker jdk1.8镜像中的GB18030-2022标准支持及验证 Go框架gin中的session存储gin-contrib-sessions和go-session 关于修改node_module中的源码问题记录 docker-compose网络和内网服务IP冲突问题 慎用存储过程:一条语句引发的数据库存储100%占用 Spring Boot中4种文件下载方法的实现 避坑-不能将specific类型的gitlab-runner改变为share类型 Docker compose中的MySQL主从复制模式和percona-toolkit工具使用 在minio中开启https访问以及使用rclone备份minio桶 在多机Docker环境下部署Choerodon的解决方案 Prometheus中Monitor添加对SpringBoot Actuator的Basic认证 在Nginx的容器镜像中隐藏Nginx的Server响应头 K8s中的两种nginx-ingress-controller及其区别 两个docker工具:runlike和whaler Grafana中的邮件报警和截图插件grafana-image-enderer K8s中externalName-service和services-without-selectors maven配置文件settings.xml中的一些概念总结 K8s中flexvolume插件驱动的安装 K8s中的coredns无法解析svc问题排查
Element-UI中实现可动态增加行列和可编辑单元格的表格
ycyin · 2020-06-27 · via 小松鼠的博客

2020年6月27日大约 5 分钟前端技术VueAHPElement-UIel-table动态表格


前言

基本需求场景:使用层次分析法(AHP)时,需要前端实现一个可动态添加表格行列、且单元格可编辑的表格。关于层次分析法可查看另一篇博客:层次分析法(AHP)分析步骤与计算方法

使用到的技术主要是vueelement-uielement-ui官方文档:https://element.eleme.cn/#/zh-CN/component/tableel-table组件不支持动态增加列,增加行则可以通过增加数据行实现,并且并不支持单元格的编辑,唯一可用到的就是可以监听单元格的双击/单击事件。

实现效果

可访问CodePen在线查看代码和效果展示:https://codepen.io/yyc007/pen/abdyNeb

效果展示
效果展示

基本思路

动态增加行列: 动态增加行可以巧妙地改变数据的行数即可实现。而动态增加列只能自己写了,实现方式是将表格的列组件el-table-column使用v-for指令循环渲染,根据列的数量确定循环次数以此来确定表头。

表格重新渲染: 上面提到当表格的列数量变化时表头也会随着数量的变化而变化,这时需要为表格设置key值,并且在列数量变化时修改key值以保证表格每次都会重新渲染。(后来发现没必要这么做)。

每一个单元格能够有唯一的key值: 因为还需要实现单元格的编辑(单击单元格可编辑)和表格右上三角不可编辑两个功能,所以需要唯一地确定每一个单元格(需要确定是哪个单元格被点击、哪个单元格不可编辑/点击),而el-table组件的单击回调方法参数cell中的cellIndex无法唯一确定单元格,需要自定义一下每个单元格的索引值。同时,单元格编辑时的input也要随着单元格确定一个key值。

表格右上三角不可编辑: 每个单元格的唯一索引确定了,这个就好做了,只需要设置一下单元格样式,并且当点击右上三角的单元格(column.index > row.index)时不做任何反应即可。

代码实现

部分核心代码和讲解。完整代码和效果可访问上面的codepen查看。

  • 先来看看当表格的行列数量值发生改变时(动态增加行列)需要做些什么。从下面的代码中可以看出主要就是初始化数据和表头。
handlerSelectChange(value) { // value就是表格的行列数量
    let tempTableThead = []
    let tempTableData = []
    let tableObjData = {}
    // 生成初始行数据
    for (let i = 1; i <= value; i++) {
        tableObjData['item' + i] = 1
    }
    // 初始化第一列表头
    tempTableThead.push({
      key: 'item0',
      label: ''
    })
    // 动态添加行和列
    for (let i = 1; i <= value; i++) {
      let temp = {}
      //添加列[表头]
      tempTableThead.push({
        key: 'item' + i,
        label: '因素' + i
      })
      //为每一行的第一列添加不用的因素名(值)
      temp['item0'] = '因素' + i
      // 复制属性
      Object.assign(temp, tableObjData)
      //添加行
      tempTableData.push(temp)
    }
    this.tableData = tempTableData
    this.formThead = tempTableThead
}

HTML核心代码:

<el-table :key="key" :cell-class-name="tableCellClassName" :data="tableData" @cell-click="handleCellClick" :show-header="true" border :header-cell-style="tableHeadCellStyle" :cell-style="tableCellStyle">
    <el-table-column v-for="item in formThead" :key="item.key" :label="item.label">
       <template slot-scope="scope">
          <div :class="[inputClass]">
             <el-input ref="inputVal" size="small" @blur="handleInputBlur" v-model="scope.row[item.key]" :row-index=scope.$index @change="handleEdit($event,scope.row,scope.column)">
                </el-input>
           </div>
           <span :class="[spanClass]">{{ scope.row[item.key] }}</span>
        </template>
      </el-table-column>
</el-table>
  • 使用data 属性为表格提供数据,需要动态生成行时改变数据行数即可。

  • 使用header-cell-stylecell-style 分别为表格的表头和右上三角的所有单元格设置样式(背景色)。

// 表头单元格样式
tableHeadCellStyle({row,column,rowIndex,columnIndex}) {
   return 'background: #DCDCDC'
},
// 表格单元格样式
tableCellStyle({row,column,rowIndex,columnIndex}) {
   if (columnIndex > rowIndex) return 'background: #DCDCDC'
}
  • 使用v-for 标签生成表格的列el-table-column , 需要动态生成列时改变formThead (即存放表头的数组)即可。

  • 使用单元格的 className 的回调方法 cell-class-name 为每一个单元格设置唯一索引。

// 给行列索引赋值,为了在点击单元格时可以唯一确定单元格
tableCellClassName({row,column,rowIndex,columnIndex}) { //注意这里是解构
    //利用单元格的 className 的回调方法,给行列索引赋值
    row.index = rowIndex;
    column.index = columnIndex;
}
  • 每一个单元格中存放一个divspan 标签,默认显示span,通过动态改变它们的class来改变css样式控制它们显示还是隐藏。需要为input设置ref值,方便确定到底是哪一个input以获得input焦点。可以看出有多个ref值为inputVal的input,因为单元格有唯一索引,所以根据单元格的索引就可以确定是哪个input 当单击单元格时,隐藏span,显示input并获取焦点;当input失去焦点时显示span,隐藏input。使用cell-click 事件监听单元格的单击。

  • 使用cell-click 事件监听单元格点击,此时主要做的就是控制表格右上三角不可点击,同时需要显示input,并让input 获取焦点:

handleCellClick(row, column, cell, event) {
   // cell中的cellIndex无法唯一确定单元格,我们自己定义
   // const cellIndex = cell.cellIndex
   const cellIndex = (this.form.value + 1) * row.index + column.index
   // 不让点击表格右上三角(包括对角线,其中对角线column.index-1 = row.index)
   if (column.index > row.index) {
       return
   }
   //显示input,隐藏span
   cell.childNodes[0].firstChild.className = "box-item-block"
   cell.childNodes[0].lastChild.className = "box-item-none"
   // 获取input焦点
   this.$nextTick(() => {
      // 获取到对应的第cellIndex个ref并获取焦点  
      this.$refs.inputVal[cellIndex].$el.querySelector('input').focus()
   })
}
  • 在input框组件上使用blur事件监听失去焦点,此时隐藏input,显示span:
handleInputBlur(event) {
   const _event = event
   const ev = _event.target.offsetParent.offsetParent.childNodes[0]
   if (_event && _event.target && _event.target.offsetParent &&
       _event.target.offsetParent.offsetParent && ev.firstChild &&
       ev.lastChild) {
         const inputElement = ev.firstChild
          const spanElement = ev.lastChild
          // 隐藏input,显示span
          inputElement.className = "box-item-none"
          spanElement.className = "box-item-block"
    }
}

参考:

  1. Element-UI官方文档
  2. Element-UI可编辑表格的实现
  3. 获取elementUI Table单击的一个单元格的列和行