二次封装quasar表格 - 多级表头 - 动态表头 - 多列粘性标题/列

前言:记录二次封装quasar表格 - 多级表头 - 动态表头 - 多列粘性标题/列
个人博客 已更新该文章— 二次封装quasar表格 - 多级表头 - 动态表头 - 多列粘性标题/列

本质上是利用quasar v-slot:header 插槽 控制表头显示双表头。

  • 原生 表格属性 rowspan colspan 达到 多级表头目的
  • 动态表头同样在渲染表格前就动态设置好 quasar表格配置项
  • 多列粘性标题/列 是利用dom原生在初始渲染位置 css控制每个位置
    z-index控制层级

代码结构比较多,每个特殊位置都有注释,认真看一下大家都能懂, 适用于我目前项目所需,大家也可以灵活修改,虽然quasar表格比较弱,但是 tr td 组件 原生渲染 tr td标签 也灵活使用

在这里插入图片描述

数据区

// 默认列表头配置
export const tableColumns: any = [
  {
    name: 'sales_order',
    label: '销售单号',
    field: 'sales_order',
    align: 'center',
    // 原生跨行表格 属性
    rowspan: '2',
  },
  {
    name: 'prod_order',
    label: '工单号',
    field: 'prod_order',
    align: 'center',
    rowspan: '2',
  },
  {
    name: 'total_qty',
    align: 'center',
    label: '订单数量',
    field: 'total_qty',
    rowspan: '2',
  },
  {
    name: 'status',
    align: 'center',
    label: '订单状态',
    field: 'status',
    rowspan: '2',
  },
  {
    name: 'output_qty',
    align: 'center',
    label: '产出数',
    field: 'output_qty',
    rowspan: '2',
  },
  {
    name: 'material_cost',
    label: '材料成本',
    align: 'center',
    field: 'material_cost',
    rowspan: '2',
  },
];

// 模拟 接口获取的数据
export const res = {
  //多级表头下 -- 一级表头 枚举
  columns: [
    { code: '机器贴装', title: '机器贴装' },
    { code: '手工焊接', title: '手工焊接' },
    { code: '波峰焊', title: '波峰焊' },
    { code: '机箱线缆', title: '机箱线缆' },
    { code: '成品检验', title: '成品检验' },
  ],
  //多级表头下 -- 二级表头 枚举
  cost_items: [
    { code: '直接人工', title: '直接人工' },
    { code: '折旧', title: '折旧' },
    { code: '制造费用', title: '制造费用' },
  ],
  // 表格数据
  data: [
    {
      cost_item_code: '直接人工',
      fix_cost: 0,
      id: 129,
      material_cost: 0,
      output_qty: 0.06,
      prod_order: 'LWX220530001N',
      sales_order: 'KSMT20220510_1_TBCG202202222222',
      status: 'in_production',
      total_cost: 0,
      total_qty: 10,
      wc_code: '机器贴装',
      成品检验_制造费用_fix_cost: 0,
      成品检验_折旧_fix_cost: 0,
      成品检验_直接人工_fix_cost: 0,
      手工焊接_制造费用_fix_cost: 0,
      手工焊接_折旧_fix_cost: 0,
      手工焊接_直接人工_fix_cost: 0,
      机器贴装_制造费用_fix_cost: 0,
      机器贴装_折旧_fix_cost: 0,
      机器贴装_直接人工_fix_cost: 0,
      机箱线缆_制造费用_fix_cost: 0,
      机箱线缆_折旧_fix_cost: 0,
      机箱线缆_直接人工_fix_cost: 0,
      波峰焊_制造费用_fix_cost: 0,
      波峰焊_折旧_fix_cost: 0,
      波峰焊_直接人工_fix_cost: 0,
    },
  ],
};

使用表格组件配置

<script lang="ts" setup>
import { onMounted, reactive } from 'vue';
import { tableColumns, res } from './test';
import SecondaryPackagingTable from '../SecondaryPackagingTable.vue';

const state = reactive({
  data: <any>[],
  tableColumns: <any>[],
});

onMounted(() => {
  getData();
});

function getData() {
  //模拟 await下 数据请求  
  let { columns, cost_items, data } = res;
  let summaryColumns = [...tableColumns]; //拷贝数据
  columns?.forEach((colum: { title: string; code: string }) => {
  	//push 表头
    summaryColumns.push({
      name: colum.code,
      label: colum.title,
      field: colum.code,
      align: 'center',
      style: 'display: none', //设置二级表头上一级 是不需要显示数据的 所以使用quasar配置 去掉
      colspan: cost_items.length, //根据 二级枚举控制跨列
    });
	//同时push 二级表头
    cost_items.forEach((res: { title: string }) => {
      summaryColumns.push({
        name: `${colum.title}_${res.title + '_fix_cost'}`,
        label: res.title,
        field: `${colum.title}_${res.title + '_fix_cost'}`,
        align: 'center',
      });
    });
  });
	
  summaryColumns.push({
    name: 'total',
    label: '合计',
    field: 'total_cost',
    align: 'center',
    rowspan: '2',
  });

  state.tableColumns = summaryColumns;
  state.data = data;
}
</script>
<template>
  <div class="" style="width: 900px; height: 600px; position: relative">
  	//使用组件
    <SecondaryPackagingTable
      :left="3" // 粘性列值
      :columns="state.tableColumns"
      :data="state.data"
    />
  </div>
</template>


封装表格组件

<script lang="ts" setup>
import { reactive, watchEffect } from 'vue';
/*
columns: quasar表头配置
data:quasar 表格数据
left: 控制粘性列 数量
*/
const props = defineProps(['columns', 'data', 'left']);
const state = reactive({
  columns: props.columns || [],
  tableData: props.data || [],
});
watchEffect(() => {
  state.columns = props.columns;
  state.tableData = props.data;
  //异步获取  触发函数 获取dom
  setTimeout(() => {
    stickyTitleFn();
  }, 100);
});

// 设置粘性标题函数
function stickyTitleFn() {
	//获取表格中一级表头
  let thead = <Array<HTMLElement>>(
    (<unknown>document.querySelectorAll('.q-table tr:first-child th'))
  );
  //获取表格中  tbody 所有 tr行
  let tbodyTr = <Array<HTMLElement>>(
    (<unknown>document.querySelectorAll('.q-table tbody tr'))
  );

  if (thead.length && props.left) {
    let num = props.left;
    for (let index = 0; index < num; index++) {
      //取出需要粘性表头的 dom元素
      let theadChild = thead[index];
	/*
	 设置 sticky-column-table 类下(position: sticky;) 的 
	 left属性  每格位置
	 z-index  层级
	 最后一个 加 border-right 边框
	*/
      theadChild.style.left = `${theadChild.offsetLeft}px`;
      theadChild.style.zIndex = '10';
      // console.log(theadChild.offsetLeft, index);
      theadChild.classList.add('sticky-column-table');

      if (index == num - 1) {
        theadChild.style.borderRight = '1px solid #ebebeb';
      }
    }
    /*
     同理对 tbody  tr  粘性的td
	 设置 sticky-column-table 类下(position: sticky;) 的 
	 left属性  每格位置
	 最后一个 加 border-right 边框
	*/
    tbodyTr.forEach((res) => {
      let tbodyTrChild = <Array<HTMLElement>>(<unknown>res.childNodes);
      tbodyTrChild.forEach((res, j) => {
      //判断粘性列数量td  阈值
        if (j < num) {
          res.classList.add('sticky-column-table');
          res.style.left = `${res.offsetLeft}px`;
        }
        if (j == num - 1) {
          res.style.borderRight = '1px solid #ebebeb';
        }
      });
    });
  }
}
</script>

<template>
  <q-table
    class="no-box-shadow"
    :rows="state.tableData"
    style="width: 100%; height: 100%"
    :columns="state.columns"
    row-key="name"
    separator="cell"
    virtual-scroll  //设置虚拟滚动 数据太多会导致dom渲染慢
    virtual-scroll-item-size="48"
    virtual-scroll-slice-size="20"
    square
    :rows-per-page-options="[0]"
    hide-bottom //隐藏下面分页栏 位置
    bordered
  >
    <template v-slot:header="props">
    //表格 表头 第一行  渲染配置 col.rowspan || col.colspan 
      <q-tr :props="props" class="head">
        <template v-for="col in props.cols" :key="col.name">
          <q-th
            v-if="col.rowspan || col.colspan"
            :rowspan="col.rowspan"
            :colspan="col.colspan"
          >
            {{ col.label }}
          </q-th>
        </template>
      </q-tr>
      //表格 表头 第二行  渲染没有配置 !(col.rowspan || col.colspan)  
      <q-tr :props="props" class="two-head">
        <template v-for="col in props.cols">
          <q-th
            :props="props"
            v-if="!(col.rowspan || col.colspan)"
            :key="col.name"
            :rowspan="col.rowspan"
            :colspan="col.colspan"
          >
            {{ col.label }}
          </q-th>
        </template>
      </q-tr>
    </template>
  </q-table>
</template>

<style lang="scss" scoped>
//控制表头行的高度
.head,
.two-head {
  height: 36px !important;
  background: #fff;
}

.q-table--cell-separator .two-head th:first-child {
  border-left: 1px rgb(235, 232, 232) solid !important;
}
:deep(.q-table tbody tr:last-child td) {
  border-bottom: 1px rgb(235, 232, 232) solid !important;
}
//粘性类
:deep(.sticky-column-table) {
  position: sticky;
  left: 0;
  z-index: 1;
  background: #fff;
  top: 0;
}

// 固定头
.q-table__container {
  height: 100%;
  max-height: calc(100vh - 90px);
  //控制 竖向滚动下 所有表头粘性
  thead tr th {
    position: sticky;
    z-index: 2;
    background: #fff;
  }
  //控制 竖向滚动下 第一行表头位置
  thead tr:first-child th {
    top: 0;
  }
  //控制 竖向滚动下 第二行表头位置
  thead tr:nth-child(2) th {
    top: 36px;
  }
}
</style>

二次封装quasar表格 - 多级表头 - 动态表头 - 多列粘性标题/列 二次封装quasar表格 - 多级表头 - 动态表头 - 多列粘性标题/列 二次封装quasar表格 - 多级表头 - 动态表头 - 多列粘性标题/列 二次封装quasar表格 - 多级表头 - 动态表头 - 多列粘性标题/列 二次封装quasar表格 - 多级表头 - 动态表头 - 多列粘性标题/列 二次封装quasar表格 - 多级表头 - 动态表头 - 多列粘性标题/列 二次封装quasar表格 - 多级表头 - 动态表头 - 多列粘性标题/列 二次封装quasar表格 - 多级表头 - 动态表头 - 多列粘性标题/列 二次封装quasar表格 - 多级表头 - 动态表头 - 多列粘性标题/列 二次封装quasar表格 - 多级表头 - 动态表头 - 多列粘性标题/列
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值