likes
comments
collection
share

基于vue3+tsx,一文搞懂单元格合并原理前言 最近开发的一个移动端项目使用的技术栈是vue3+vant4,需求开发中

作者站长头像
站长
· 阅读数 55

前言 最近开发的一个移动端项目使用的技术栈是vue3+vant4,需求开发中需要以表格的形式展示信息,在vant官方文档找了半天没看到table组件,移动端就不该展示表格?再重新引入一个ui框架有点小题大作,于是动手封装一下表格组件,table组件常用功能的封装在上一篇文章已经讲过了,本篇文章主要分享的是单元格合并功能。

实现效果

合并行

基于vue3+tsx,一文搞懂单元格合并原理前言 最近开发的一个移动端项目使用的技术栈是vue3+vant4,需求开发中

列合并

基于vue3+tsx,一文搞懂单元格合并原理前言 最近开发的一个移动端项目使用的技术栈是vue3+vant4,需求开发中

仓库地址

Gitee: gitee.com/sz-liunian/…

需求分析

elementui表格合并实现方法: 通过给table传入span-method方法可以实现合并行或列,方法的参数是一个对象,里面包含当前行row、当前列column、当前行号rowIndex、当前列号columnIndex四个属性。该函数可以返回一个包含两个元素的数组,第一个元素代表rowspan,第二个元素代表colspan。 也可以返回一个键名为rowspancolspan的对象。

我们也参照elementui绑定一个方法mergeCellMethods来实现单元格合并

使用方法

 <table-list
  :columns="titleList"
  :data="dataList"
  showBorder
  @mergeCellMethods="mergeCellMethods"
>
  <template #slotDate="{item, titleItem}">
    <div class="user-info">
      <span 
        class="ellipsis"
      >{{ titleItem.title }}</span>
    </div>
  </template>
</table-list>
<script setup lang="ts">
import Mock from 'mockjs'
import { useRouter } from 'vue-router'
const router = useRouter()
import tableList from '@/components/tablePro/index.vue'
import { setData } from '@/utils/getTableData.ts'
const titleList = [
    {
      title: '日期',
      width: 100,
      key: 'date',
      ellipsis: true,
      fixed: 'left',
      slotHeader: 'slotDate'
    },
    {
      title: '基本信息',
      key: 'baseInfo',
      children: [
        {
          title: '姓名',
          width: 95,
          key: 'name',
          sort: 2,
          fieldName: 1,
          align: 'right',
          commaSplice: true,
          // formatter
        },
        {
          title: 'other',
          key: 'other',
          children: [
            {
              title: '年龄',
              width: 95,
              key: 'age',
              sort: 2,
              fieldName: 1,
              align: 'right'
            },
            {
              title: '公司',
              width: 95,
              key: 'company',
              sort: 2,
              fieldName: 1,
              align: 'right'
            },
          ]
        }
      ]
    },
    {
      title: '岗位',
      width: 95,
      key: 'work',
      sort: 2,
      fieldName: 1,
      align: 'right',
      commaSplice: true,
    },
    {
      title: '城市',
      width: 130,
      key: 'city',
      align: 'right',
      commaSplice: true,
      sort: 0,
      fieldName: 3,
      ellipsis: true,
      // fixed: 'right',
    }
  ]
  const dataObj = {
    date: '@date',
    name: "@cname",
    age: '@integer(24, 65)',
    company: '@pick(["阿里", "腾讯", "字节"])',
    work: '@pick(["产品", "运营", "ui", "前端", "后端", "测试", "运维"])',
    city: '@city()'
  }
  const dataList = setData(Mock.mock('@natural(50, 100)'), dataObj)
  // 单元格合并
  const mergeCellMethods = function(row, column, rowIndex, columnIndex) {
  // 合并单元格行
    if (rowIndex % 2 === 0) {
      if (columnIndex === 1) {
        return [1, 2];
      } else if (columnIndex === 2) {
        return [0, 0];
      }
    }
  }
  // 合并单元格列
  // const mergeCellMethods = function(row, column, rowIndex, columnIndex) {  
  //   if (columnIndex === 1) {
  //     if (rowIndex % 2 === 0) {
  //       return {
  //         rowspan: 2,
  //         colspan: 1
  //       };
  //     } else {
  //       return {
  //         rowspan: 0,
  //         colspan: 0
  //       };
  //     }
  //   }
  // }
 </script>

实现原理

list.vue文件更改tdCell方法,使用hasMergeCellMethods方法之前要先判断一下该方法是否存在,具体实现请查看源码

    // 是否有单元格合并方法
    const hasMergeCellMethods = getValueType(attrs?.onMergeCellMethods) === 'Function'
    // 单元格样式
    const tdCell = (v: Object, rowIndex: Number) => {
      return props.columns.map((item, index, arr) => {
        let [rowspan, colspan] = [1, 1]
        // 单元格合并方法
        if (hasMergeCellMethods) {
          let spans = [1, 1]
          let columnIndex = index
          if (props.fixedCol === 'center') {
            // 中间列的索引需要加上左侧固定的列数
            columnIndex = props.fixedLeftLength + index
          } else if (props.fixedCol === 'right') {
             // 右侧列的索引要加上中间滚动列数和左侧固定的列数
            columnIndex = props.fixedLeftLength + props.centerColumnLength + index
          }
          spans = attrs.onMergeCellMethods(v, item, rowIndex, columnIndex) || [1, 1]
          if (getValueType(spans) === 'Array') {
            rowspan = spans[0]
            colspan = spans[1]
          } else if (getValueType(spans) === 'Object') {
            rowspan = spans.rowspan
            colspan = spans.colspan
          }
        }
        if (rowspan === 0 && colspan === 0) {
          return false
        }
        let val = ![null, undefined, ''].includes(v[item.key]) ? v[item.key] : ''
        return (
          <td
            key={item.key}
            rowspan={rowspan}
            colspan={colspan}
            class={[
              'li-cell',
              item.key,
              { 'show-border': props.showBorder },
              { 'border-bottom': props.borderBottom },
              { 'column-last': item.isLastCol }
            ]}
            style={{
              'text-align': item.align || 'left'
            }}
            onClick={e => emit('handlerCellClick', v, item, e)}
          >
            {cellContent(item, v, index)}
          </td>
        )
      })
    }

Table 属性

参数说明类型默认值
showTitle是否展示表头booleantrue
showList是否展示列表booleantrue
columns表格列的配置描述见下表array[]
data列表数据array[]
showBorder是否显示单元格边框booleanfalse
isHeaderFixed表头是否吸顶booleantrue
headerFixedTopValue页面划动,表头吸顶top值Number88 (单位px)
height行高度number、string50(单位px)

columns属性

参数说明类型默认值
title表头展示内容string (支持传html)''
width单元格宽度number70(单位px)
widthAuto宽度自适应,会把剩余宽度按比例分配给设置了该字段的列booleanfalse
key当前列要展示的字段string 每一个 表头选项,key要保持惟一-(无默认值)
fixed列是否固定,可选 'left' 'right'string-(无默认值)
align单元格对齐方式, 可选 left、center、 rightstringleft
ellipsis超过宽度将自动省略booleanfalse
slotHeadertitle 插槽key,可使用此字段添加插槽string-
headerBackground表头背景色string'#fff'
formatter列表单元格格式化函数Function(h, row, column, index)-
util单位number、string

插槽: 表头插槽使用 columns 属性 slotHeader自定义表头内容 内容插槽使用 columns 属性key自定义单元格内容

事件

参数说明类型
handlerClickrow 点击事件Function(row, index)
handlerCellClickcell 点击事件Function(row, column)
mergeCellMethods合并单元格方法,用法同element-uifunction(v, item, rowIndex, columnIndex)
转载自:https://juejin.cn/post/7425603008414154763
评论
请登录