欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

html原生table實現合并單元格以及合并表頭的示例代碼

  發(fā)布時間:2023-04-28 16:59:23   作者:一個想成為全棧的前端開發(fā)   我要評論
表格是常見的數據統(tǒng)計的一種形式,合并單元格及合并表頭經常在復雜表格中遇到,本文主要介紹了html原生table實現合并單元格以及合并表頭的示例代碼,感興趣的可以了解一下

前言

因為公司業(yè)務越來越復雜,有些頁面PC和app其實是一樣的,我們肯定不想寫兩套代碼,所以我們看看能不能寫一個同時支持PC和app的table組件

思路

首先肯定想到的是原生table進行封裝,因為我早就想這么干了,想通過原生的一些基礎組件去封裝成咱們可用的組件庫。說搞就搞,先實現table的一些簡單功能,因為公司用的js框架是vue,所以基于vue3去封裝。

實現的功能

  • 表頭分組
  • 合并單元格
  • 滾動條
  • 單元格放組件

表頭分組

表頭分組這個概念也是ant-design-vue中看來的,反正我的理解就是合并單元格,但是它叫表頭分組,可能專業(yè)些,好吧,已經復制了它的叫法。
通過配置去生成分組的表頭,首先要對原生table的一些配置要比較熟練,介紹兩個最重要的配置

  • rowspan 表格橫跨的行數
  • colspan 表格橫跨的列數

配置

copy了一份ant的較為復雜的結構,然后稍微改一了一下標識字段,方便我們自己組件使用

const columns: columnsType[] = [
        { prop: 'index', label: '', width: 3 },
        {  
            label: 'Other',
            children: [
                {
                    prop: 'age', label: 'Age',
                },
                {
                    label: 'Address',
                    children: [
                        {
                            label: 'Street',
                            prop: 'street'
                        },
                        {
                            label: 'Block',
                            children: [
                              {
                                label: 'Building',
                                prop: 'building',
                              },
                              {
                                label: 'Door No.',
                                prop: 'number',
                              },
                            ],
                          },
                    ]
                }
            ]
        },
 ]

主體代碼

// 頭部
 <thead>
        <tr v-for="(row, index) in renderHeaderList" :key="index">
          <th
            v-for="columnsItem in row"
            :key="columnsItem.prop"
            :rowspan="computedHeaderRowSpan(columnsItem)"
            :colspan="computedHeaderColSpan(columnsItem)"
            :class="`width-${columnsItem.width} height-${tableHeaderHeight} header-b`"
          >
            // 使用組件的原因是方便擴展其他業(yè)務需求
            <headerCell :columnsItem="columnsItem"></headerCell>
          </th>
        </tr>
</thead>

橫跨的行數

首先肉眼看到的肯定是表頭橫跨了4行。但是我們也不能寫死成4行,我們需要通過計算得到這個表頭最終橫跨的幾行。表頭行數跨不跨行的判斷依據是有無children。所以我這里是通過遞歸去扁平化這個數組,最終得到表格橫跨了幾行。

 /**
     * @description 遞歸扁平化配置數組,得到渲染表頭的數組以及橫跨的的行數
     * @param columns children
     */
    function handleRenderHeaderList(columns:columnsType[]) {
        // 用于記錄深度
        headerIndex.value += 1
       if (renderHeaderList.value.length <= headerIndex.value) {
            renderHeaderList.value.push(columns)
       } else {
            renderHeaderList.value[headerIndex.value] = [...renderHeaderList.value[headerIndex.value],...columns]
       }
       // 用于記錄是否重置深度
       let isClearIndex = true
        columns.forEach((item: columnsType) => {
            // 判斷是否還有子集
            if (item.children && item.children.length > 0 ) {
                isClearIndex = false
                handleRenderHeaderList(item.children)
            }
        });
        if(isClearIndex){
            headerIndex.value = 0
        }
    }
    /**
     * @description 單獨rowspan的計算
     * @param columnsItem 單元格的配置
     * @return 單元格的列數 
     */
   function computedHeaderRowSpan(columnsItem:columnsType){
    if(!columnsItem.children){
        return renderHeaderList.value.length
    }
    return 1
    }

橫跨的列數

這個列數也是不固定的,也需要去通過收集對應的children里面的項數來統(tǒng)計,因為我們是無法確認這個children的深度的,所以我這邊用深度遍歷來處理子集的收集問題。因為用遞歸此時vue會報警告,實際上我們也需要知道遞歸多了,內存就消耗的多,所以我們能不用遞歸就盡量不用遞歸。

   /**
     * @description 單獨colSpan的計算
     * @param columnsItem 單元格的配置
     * @return 單元格的列數
     */
    function computedHeaderColSpan(columnsItem:columnsType){
        if(!columnsItem.children){
            return 1
        }
        return flatColumnsItemChildren(columnsItem.children).length
    }
    /** 
     * @description 深度遍歷扁平化數組獲取單元格所占的列數
     * @param columnsItem 單元格的配置
     * @return 返回扁平化后的數組
     */
    function flatColumnsItemChildren(columnsItem:columnsType[]){
        // 深度遍歷,扁平化數組
        let node, list = [...columnsItem], nodes = []
        while (node = list.shift()) {
            // 要過濾一下沒有prop的,沒有prop的列不參與最終的寬度計算
            if(node.prop){
                nodes.push(node)
            }
            node.children && list.unshift(...node.children)
        }
        return nodes
        // 遞歸會報警告,占內存
        // if(columnsItem.length === 0){
        //     return
        // }
        // columnsItem.forEach((item:columnsType)=>{
        //     if(item.children){
        //         flatColumnsItemChildren(item.children)
        //     }else{
        //         flatChildrenList.value.push(item)
        //     }
        // })
    }

實現效果圖

合并單元格以及單元格放組件

合并單元格稍微簡單些,只需要把每個單元格的colspan和rowspan寫成一個函數并且暴露出來就能處理

配置

const columns: columnsType[] = [
        {
            prop: 'monitor',
            label: '班次',
            customCell: (_?: rowType, index?: number, columns?: columnsType) => {
                if (index === 2 && columns?.prop === 'monitor') {
                    return { colspan:3 };
                }
                if (index === 0 && columns?.prop === 'monitor') {
                    return { rowspan:2 };
                }
                if (index === 1 && columns?.prop === 'monitor') {
                    return { rowspan:0 };
                }
                return {colspan:1,rowspan:1};
            },
        },
        {
            prop: 'taHao',
            label: '塔號',
            customCell: (_?: rowType, index?: number, columns?: columnsType) => {
                if (index === 2 && columns?.prop === 'taHao') {
                    return {colspan : 0};
                }
                return  {colspan:1};
            },
        },
        {
            prop: 'materialNum',
            label: '投料量',
            customCell: (_?: rowType, index?: number, columns?: columnsType) => {
                if (index === 2 && columns?.prop === 'materialNum') {
                    return {colspan : 0};
                }
                return  {colspan:1};
            },
        },
        { prop: 'temperature', label: '沸騰罐溫度', rowSpan: 2 },
        {
            prop: 'steamPressure',
            label: '蒸汽壓力'
        },
        {
            prop: 'steamPressure1',
            label: '蒸汽壓力2'
        },
        { prop: 'oxygen', label: '真空度' },
        { prop: 'productNum', label: '成品產量' },
        {
            prop: 'operatorName',
            label: '操作人'
        },
        {
            prop: 'operatorTime',
            label: '操作時間'
        },
    ];

主體代碼以及單元格放組件

<tbody>
        <tr v-for="(item, index) in tableData" :key="index">
          <template
            v-for="(headerItem, headerIndex) in renderDataList"
            :key="headerIndex"
          >
            <td
              v-if="
                computedTdColspan(item, index, headerItem) !== 0 &&
                computedTdRowspan(item, index, headerItem) !== 0
              "
              align="center"
              :class="`height-${tableCellHeight} cell-b`"
              :colspan="computedTdColspan(item, index, headerItem)"
              :rowspan="computedTdRowspan(item, index, headerItem)"
            >
              // 動態(tài)組件提前寫好組件去渲染對應的組件,此時的table單元格擴展性就變得非常強,不                  僅可以做展示用,也可以放輸入框,下拉選擇器之類的組件。
              <component
                :is="components[headerItem.type]"
                :ref="(el:unknown) => setComponentRef(el, headerItem.prop)"
                :form-item="headerItem"
                :value="item"
              ></component>
            </td>
          </template>
        </tr>
      </tbody>

橫跨的行數

每個單元格渲染的時候,暴露一個函數出去,此函數的返回值有rowspan以及colspan,這樣能準確的知道渲染每個單元格時此單元格占位多少。

 /**
     * @description 計算單元格rowspan的占位
     * @param item 單元格一行的值
     * @param index 索引
     * @param columns 當前的單元格配置
     * @return colspan
     */
    function computedTdRowspan(item: rowType, index: number, columns: columnsType): number|undefined {
        if (columns.customCell) {
            let rowspan: number| undefined = 1
            if(columns.customCell(item, index, columns).rowspan ===0){
                rowspan = 0
            }
            if(columns.customCell(item, index, columns).rowspan){
                rowspan = columns.customCell(item, index, columns).rowspan
            }
            return rowspan
        }
        return 1;
    }

橫跨的列數

每個單元格渲染的時候,暴露一個函數出去,此函數的返回值有rowspan以及colspan,這樣能準確的知道渲染每個單元格時此單元格占位多少。

/**
     * @description 計算單元格colspan的占位
     * @param item 單元格一行的值
     * @param index 索引
     * @param columns 當前的單元格配置
     * @return colspan
     */
    function computedTdColspan(item: rowType, index: number, columns: columnsType): number|undefined {
        if (columns.customCell) {
            let colspan: number| undefined = 1
            if(columns.customCell(item, index, columns).colspan ===0){
                colspan = 0
            }
            if(columns.customCell(item, index, columns).colspan){
                colspan = columns.customCell(item, index, columns).colspan
            }
            return colspan
        }
        return 1;
    }

實現效果圖

滾動條

table自身是響應式的,按照一定規(guī)則自動去分配寬度和高度的,如果不在table外面包裹一層元素的話,table會一直自適應,沒法帶有滾動條,我們需要給外層元素設置一個寬度或者高度,然后table也設置一個固定的寬度或者是高度,這樣內部的table就會在限定的寬度或者高度下具有滾動條。

總結

為了更好的在特定場景去控制table的高寬以及單元格的高寬,我們可以將他們的樣式設定為動態(tài)的,我們可以通過配置去動態(tài)的改變他們的樣式。然后就是處理一些無法確認層級的樹形結構數據,我們也可以不通過遞歸去實現,節(jié)省內存。

到此這篇關于html原生table實現合并單元格以及合并表頭的示例代碼的文章就介紹到這了,更多相關html table合并單元格及表頭內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持腳本之家!

相關文章

  • 使用html5實現表格實現標題合并的實例代碼

    在前端開發(fā)中經常會遇到標題合并的需求,今天小編給大家?guī)砹耸褂胔tml5實現表格實現標題合并的實例代碼,感興趣的朋友跟隨小編一起看看吧
    2019-05-13
  • HTML表格合并的具體實現方式

    表格是日常常用的工具,很多時候需要用到單元合并,本文主要介紹了HTML表格合并的具體實現方式, 具有一定的參考價值,感興趣的可以了解一下
    2023-01-05
  • HTML中table表格拆分合并(colspan、rowspan)

    這篇文章主要介紹了HTML中table表格拆分合并(colspan、rowspan),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編
    2021-04-07
  • html+css合并表格邊框的示例代碼

    這篇文章主要介紹了html+css合并表格邊框的示例代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習
    2021-03-31
  • 詳解html中表格table的行列合并問題解決

    這篇文章主要介紹了詳解html中表格table的行列合并問題解決,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來
    2020-07-28

最新評論