首頁  >  文章  >  web前端  >  UniApp實戰之開發一個複雜場景的表格組件

UniApp實戰之開發一個複雜場景的表格組件

青灯夜游
青灯夜游轉載
2022-01-07 19:12:286303瀏覽

這篇文章跟大家分享一個UniApp實戰,動手實作一個複雜場景的表格元件(UniApp),希望對大家有幫助!

UniApp實戰之開發一個複雜場景的表格組件

是一個成熟的程式猿了,要懂得自己造輪子(uniApp的插件市場找了一遍都沒發現符合需求的插件,沒有辦法了,只能自己動手造輪子)。本文旨在複盤 記錄。
使用場景: uniApp 、 行動裝置(相容小程式、App、H5)

#依需求整理下特定功能:

需求整理

  • #表格名稱

    • 可配置背景

    • 字體樣式可修改(大小、顏色)

    • 選單按鈕(需要對外暴露事件)

  • #表頭

    • 支援多層表頭

    • 表頭固定

    • 表頭行支援自訂名稱

  • #表格

    • 支援設定單元格寬度

    • #固定首列

    • #支援樹形資料

    • 內容支援圖片、連結

    • 內部實作排序

    • 內部實作分頁

    #內部運算總計行

    對於整個組件的一些思考
  • 功能比較複雜,擠在一個文件不太優雅並且會比較亂-> 按大的方向分成幾個模組(細化粒度)

  • 需求比較多,直覺就是需要傳遞的參數也非常多-> 依照模組定義,將參數也分類

    參數比較多,怎樣更優雅的管理,減少上手難度? -> 設定檔config.js並在其中設定預設值,起到欄位說明

  • 預設狀態管理
  • 的作用

    #其中會涉及一些圖示的使用 -> 選取
  • iconfont
圖示庫

技術實作困難由於使用環境限制:uniApp實現的表格相關元件比較簡單,對於非H5環境限制比較大(例如無法設定rowspan

colspan ),使用起來也顯得比較麻煩,達不到專案的需求,最後決定自己造個輪子。

表頭部分

主要困難在於多層表頭的處理,怎麼樣做到根據資料來驅動顯示。剛開始是打算按html table 的方式實現,開發過程中遇到的問題比較多,首先資料處理比較麻煩,要計算有多少行、每行單元格的colspanrowspan

。而且沒有

td, tr等元件,需要自己額外實作。

columns的資料是樹狀的,如下

columns = [
    { "title": "区域", "dataIndex": "区域" },
	{
		"title": "广州一区",
		"children": [
			{ "title": "销售", "dataIndex": "广州一区销售"},
			{ "title": "计划销售", "dataIndex": "广州一区计划销售" },
			{ "title": "达成", "dataIndex": "广州一区达成"}
		]
	},
    // ...
]

#似乎用flex 佈局就能實現了每個格子設定垂直居中,如果存在children則遍歷遞歸渲染,由於需要遞歸呼叫渲染,把遞歸的部分在分出來一個元件:titleColumn

。先貼個程式碼(程式碼已發佈到社區,有興趣可以去看看

傳送門):

#table-header.vue

UniApp實戰之開發一個複雜場景的表格組件

titleColumn.vueUniApp實戰之開發一個複雜場景的表格組件

#這裡有個坑 在正常的vue

中遞迴元件是不需要引入的,在

uniApp

#則需要。

// titleColumn.vue
import titleColumn from "./title-column.vue"
UniApp實戰之開發一個複雜場景的表格組件樣式方面不展開了,不好寫。直接看看效果(自我感覺很好,哈哈哈):

#表格內容

這裡先要處理下columns

的資料(要考慮到多層表頭情況),根據上面的
    columns
  • ,得到實際要渲染的欄位:

    新建一個變數
  • dataIndexs
  • ,用來儲存需要實際渲染的列資料

    遞迴處理
  • columns
拿到最終的葉子節點並保存起來。

######關鍵程式碼:###
// 根据Column 获取body中实际渲染的列
fmtColumns(list) {
    // 保存叶子节点
    this.dataIndexs = []
    if (!list || !list.length) return
    // 获取实际行
    this.columnsDeal(list)
},

// 
columnsDeal(list, level = 0) {
    list.forEach(item => {
        let { children, ...res } = item
        if (children && children.length) {
            this.columnsDeal(children, level + 1)
        } else {
            this.dataIndexs.push({ ...res })
        }
    })
},

接下来就是处理列表数据中的树形结构了。

先看看数据结构 tableData:

tableData = [
    {
		"key": 1,
		"区域": "广州",
		"销售": 100,
		"计划销售": 200,
		"达成": "50.0%",
		"达成排名": 1,
		"GroupIndex": 1,
		"GroupLayer": 1,
		"GroupKey": "广州",
		"children": [{
				"key": 11,
				"区域": "广州一区",
				"小区": "广州一区",
				"销售": 60,
				"计划销售": 120,
				"达成": "50.0%",
				"达成排名": 1,
				children: [{
					"key": 111,
					"区域": "广州一区1",
					"小区": "广州一区1",
					"销售": 60,
					"计划销售": 120,
					"达成": "50.0%",
					"达成排名": 1,
				}]
			},
			{ "key": 12, "区域": "广州二区", "小区": "广州二区", "销售": 40, "计划销售": 80, "达成": "50.0%", "达成排名": 1 },
		],
	},
]

树形的结构,key是唯一值。

有想过使用递归组件的方式实现,但是考虑到会涉及到展开、收起的操作。也是比较麻烦。

最终的方案是把数据扁平化处理,为每条数据添加 层级、是否子数据、父级ID 等属性。并通过一个数组变量来记录展开的行,并以此控制子数据的显示与否。处理后的数据存放在 dataList

扁平化处理函数:

// 递归处理数据,tree => Array
listFmt(list, level, parentIds = []) {
    return list.reduce((ls, item) => {
        let { children, ...res } = item
        // 错误提示
        if (res[this.idKey] === undefined || !res[this.idKey] === null) {
            // console.error(`tableData 数据中存在 [idKey] 属性不存在数据,请检查`)
        }
        let nowItem = {
            ...res,
            level,
            hasChildren: children && children.length,
            parentIds,
            children,
            [this.idKey]: res[this.idKey] && res[this.idKey].toString()
        }
        ls.push(nowItem)
        if (children && children.length) {
            this.isTree = true
            ls = ls.concat(this.listFmt(children, level + 1, [...parentIds, nowItem[this.idKey]]))
        }
        return ls
    }, [])
},

最终得到的数据如下:

UniApp實戰之開發一個複雜場景的表格組件

数据处理完可以渲染了,

需要嵌套两层遍历:

第一层 遍历 dataList 得到行

第二层 遍历 dataIndexs 得到列

最终完成渲染:

UniApp實戰之開發一個複雜場景的表格組件

固定首列,固定表头

使用css属性:position: sticky实现。粘性定位元素(stickily positioned element)。大家都是成熟的前端程序猿啦~~,就不具体介绍了。说说一些需要注意的细节:

兼容性

UniApp實戰之開發一個複雜場景的表格組件

uniapp中小程序模式、App模式是支持的!!!

限制

  • 设置了position:sticky之后必现指定top  left  right  bottom其中任一,才会生效。不设置的话表现和相对定位相同。topbottom 或者 leftright 同时设置的情况下,topleft的优先级高。

  • 设定为 position:sticky 元素的任意父节点的 overflow 属性必须是visible,否则 不会生效 (都不能滚动还能咋办)。

其他

造个轮子不难,造个好用的轮子不易。

涉及一些布局上和css部分的东西在文章中不好表达,不细说了,有兴趣的可以拉代码看看。传送门

开发过程中也遇到过不少的问题,都是一路修修补补过来,前期没有构思好会导致后面的开发磕磕碰碰(刚开始模块、参数没有划分好,整个东西逻辑都比较乱,后面停下来从新思考调整了,有种豁然开朗的痛快)

搬砖去了~

原文地址:https://juejin.cn/post/7083401121486045198

作者:沐夕花开

推荐:《uniapp教程

以上是UniApp實戰之開發一個複雜場景的表格組件的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:juejin.cn。如有侵權,請聯絡admin@php.cn刪除