복잡한 시나리오를 위한 테이블 구성요소의 UniApp 실무 개발
이 기사에서는 UniApp복잡한 시나리오에서 테이블 구성 요소(UniApp)를 실제로 구현하는 방법이 모든 사람에게 도움이 되기를 바랍니다.
이제 성숙한 프로그래머가 되었으니 나만의 휠을 만드는 법을 알아야 합니다. 하지만 직접 바퀴를 만드는 것입니다). 이번 글은 리뷰 + 기록을 목적으로 합니다.
사용 시나리오: uniApp, 모바일 단말기(미니 프로그램, Apps, H5와 호환 가능)
특정 기능은 필요에 따라 구성됩니다.
필수 구성
-
테이블 이름
구성 가능한 배경
글꼴 스타일 수정 가능(크기, 색상)
메뉴 버튼(외부 이벤트에 노출 필요)
-
Header
다단계 헤더 지원
Header 고정
머리글 행은 사용자 정의 이름을 지원합니다
-
table
셀 너비 설정을 지원
첫 번째 열 고정
트리 데이터 지원
-
콘텐츠는 이미지와 링크를 지원합니다
-
Others
정렬의 내부 구현
페이징의 내부 구현
총 행의 내부 계산
전체 구성 요소에 대한 몇 가지 생각
-
기능 상대적으로 복잡하고 하나로 압축됩니다. 파일이 그다지 우아하지 않고 지저분해질 것입니다. -> 일반적인 방향에 따라 여러 모듈로 나눕니다(세분성 조정)
요구사항도 많고, 직관적으로 매개변수도 많습니다. -> 모듈 정의에 따라 매개변수도 분류됩니다
매개변수를 더 우아하게 관리하고 시작의 어려움을 줄이는 방법은 무엇인가요? ->
config.js
구성 파일에 기본값을 설정합니다. 이는config.js
并在其中设定默认值,起到字段说明及默认状态管理的作用其中会涉及一些图标的使用 -> 选定
iconfont
图标库
技术实现难点
由于使用环境限制:uniApp
实现的表格相关组件比较简单,对于非H5环境限制比较大(例如不能设置rowspan
,colspan
),使用起来也显得比较麻烦,达不到项目的需求,最后决定自己造个轮子。
表头部分
主要难点在于 多级表头的处理,怎么样做到根据数据来驱动显示。刚开始是打算按 html table
的方式实现,开发过程中遇到的问题比较多,首先数据处理比较麻烦,要计算有多少行、每行单元格的colspan
、rowspan
。而且没有td, tr
等组件,需要自己额外实现。
columns
的数据是树形的,如下
columns = [ { "title": "区域", "dataIndex": "区域" }, { "title": "广州一区", "children": [ { "title": "销售", "dataIndex": "广州一区销售"}, { "title": "计划销售", "dataIndex": "广州一区计划销售" }, { "title": "达成", "dataIndex": "广州一区达成"} ] }, // ... ]
似乎用 flex
布局就能实现了
每个格子设置垂直居中,如果存在children
则遍历递归渲染,由于需要递归调用渲染,把递归的部分在分出来一个组件:titleColumn
。先贴个代码(代码已发布到社区,有兴趣可以去看看 传送门):
table-header.vue
titleColumn.vue
这里有个坑 :
在正常的vue
中递归组件是不需要引入的,在 uniApp
则需要。
// titleColumn.vue import titleColumn from "./title-column.vue"
样式方面不展开了,不好写。直接看看效果(自我感觉很好,哈哈哈):
表格内容
这里先要处理下columns
的数据(要考虑到多级表头情况),根据上面的columns
,得到实际要渲染的列:
新建一个变量
dataIndexs
,用于保存需要实际渲染的列数据递归处理
및columns
필드 설명 기본 상태 관리
iconfont
아이콘 라이브러리🎜🎜🎜🎜기술적 구현 어려움🎜🎜🎜사용 환경 제한으로 인해: uniApp</code > 구현된 Table 관련 구성요소는 상대적으로 단순하지만 H5가 아닌 환경에서는 상대적으로 큰 제한이 있어(예: <code>rowspan
, colspan
설정 불가)) 이 역시 번거롭습니다. 사용하고 프로젝트의 요구 사항을 충족할 수 없습니다. 마침내 내 자신의 휠을 만들기로 결정했습니다. 🎜🎜🎜헤더 부분🎜🎜🎜가장 어려운 점은 🎜다단계 헤더🎜를 처리하고 데이터를 기반으로 디스플레이를 구동하는 방법입니다. 처음에는 html 테이블
방식으로 구현하려고 했는데, 우선 데이터 처리 과정에서 많은 문제가 발생했습니다. 각 행에 있는 셀의 colspan<, <code>rowspan
. 그리고 td, tr
및 기타 구성요소가 없으므로 직접 구현해야 합니다. 🎜🎜아래와 같이 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 })
}
})
},
로그인 후 복사로그인 후 복사🎜flex
레이아웃을 사용하면 가능한 것 같습니다🎜각 그리드는 수직 중앙에 위치하도록 설정되어 있습니다 , 자식
이 있는 경우 🎜재귀 렌더링🎜을 순회합니다. 렌더링은 재귀적으로 호출해야 하므로 재귀 부분은 titleColumn
구성 요소로 분리됩니다. 먼저 코드를 게시하세요. (코드는 커뮤니티에 공개되었습니다. 관심이 있으시면 포털 🎜): 🎜🎜table-header.vue
🎜🎜🎜
🎜🎜titleColumn.vue
🎜🎜
🎜🎜🎜여기 구덩이가 있습니다🎜: 🎜🎜일반적인 vue
에서는, 재귀 구성 요소를 도입할 필요가 없습니다. 예, uniApp
에는 필요합니다. 🎜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 },
],
},
]
로그인 후 복사로그인 후 복사🎜문체가 전개가 안되어 쓰기가 어렵네요. 효과를 직접 확인해보세요(기분이 참 좋아요 ㅎㅎㅎ): 🎜🎜
🎜🎜🎜테이블 콘텐츠🎜🎜🎜여기서는 열</을 처리해야 합니다. code> 첫 번째 데이터(다중 레벨 헤더를 고려해야 함) 위의 <code>열
에 따라 렌더링할 실제 열을 가져옵니다. 🎜🎜🎜🎜새 변수 dataIndexs< 만들기 /code> 실제로 렌더링해야 하는 열 데이터 🎜🎜🎜🎜는 <code>column
을 재귀적으로 처리하여 최종 리프 노드를 구하고 저장합니다. 🎜🎜🎜🎜키 코드: 🎜// 根据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
}, [])
},
로그인 후 복사最终得到的数据如下:

数据处理完可以渲染了,
需要嵌套两层遍历:
第一层 遍历 dataList
得到行
第二层 遍历 dataIndexs
得到列
最终完成渲染:

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

uniapp中小程序模式、App模式是支持的!!!
限制
设置了position:sticky
之后必现指定top left right bottom
其中任一,才会生效。不设置的话表现和相对定位相同。top
和 bottom
或者 left
和 right
同时设置的情况下,top
、 left
的优先级高。
设定为 position:sticky
元素的任意父节点的 overflow
属性必须是visible
,否则 不会生效 (都不能滚动还能咋办)。
其他
造个轮子不难,造个好用的轮子不易。
涉及一些布局上和css部分的东西在文章中不好表达,不细说了,有兴趣的可以拉代码看看。传送门
开发过程中也遇到过不少的问题,都是一路修修补补过来,前期没有构思好会导致后面的开发磕磕碰碰(刚开始模块、参数没有划分好,整个东西逻辑都比较乱,后面停下来从新思考调整了,有种豁然开朗的痛快)
搬砖去了~
原文地址:https://juejin.cn/post/7083401121486045198
作者:沐夕花开
推荐:《uniapp教程》
위 내용은 복잡한 시나리오를 위한 테이블 구성요소의 UniApp 실무 개발의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!
// 根据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 = [ { "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 }, ], }, ]
// 根据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
是唯一值。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 }, []) },

dataList
得到行dataIndexs
得到列
css
属性:position: sticky
实现。粘性定位元素(stickily positioned element)。大家都是成熟的前端程序猿啦~~,就不具体介绍了。说说一些需要注意的细节:
设置了position:sticky
之后必现指定top left right bottom
其中任一,才会生效。不设置的话表现和相对定位相同。top
和 bottom
或者 left
和 right
同时设置的情况下,top
、 left
的优先级高。
设定为 position:sticky
元素的任意父节点的 overflow
属性必须是visible
,否则 不会生效 (都不能滚动还能咋办)。
造个轮子不难,造个好用的轮子不易。
原文地址:https://juejin.cn/post/7083401121486045198
作者:沐夕花开

핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

AI Hentai Generator
AI Hentai를 무료로 생성하십시오.

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

뜨거운 주제











WebStorm에서 UniApp 프로젝트 미리보기를 실행하는 단계: UniApp 개발 도구 플러그인 설치 장치 설정에 연결 WebSocket 실행 미리보기

일반적으로 복잡한 기본 기능이 필요할 때는 uni-app이 더 좋고, 단순하거나 고도로 맞춤화된 인터페이스가 필요할 때는 MUI가 더 좋습니다. 또한 uni-app에는 1. Vue.js/JavaScript 지원 2. 풍부한 기본 구성 요소/API 3. 좋은 생태계가 있습니다. 단점은 다음과 같습니다. 1. 성능 문제 2. 인터페이스 사용자 정의가 어렵습니다. MUI에는 다음이 포함됩니다. 1. 머티리얼 디자인 지원 2. 높은 유연성 3. 광범위한 구성 요소/테마 라이브러리. 단점은 다음과 같습니다. 1. CSS 종속성 2. 기본 구성 요소를 제공하지 않습니다. 3. 소규모 생태계.

UniApp은 크로스 플랫폼 개발 프레임워크로서 많은 편리함을 가지고 있지만 단점도 분명합니다. 하이브리드 개발 모드로 인해 성능이 제한되어 열기 속도, 페이지 렌더링 및 대화형 응답이 좋지 않습니다. 생태계가 불완전하고 특정 분야의 컴포넌트와 라이브러리가 적어 창의성과 복잡한 기능 구현이 제한됩니다. 다양한 플랫폼에서의 호환성 문제로 인해 스타일 차이와 일관되지 않은 API 지원이 발생하기 쉽습니다. WebView의 보안 메커니즘은 기본 애플리케이션과 다르므로 애플리케이션 보안이 저하될 수 있습니다. 동시에 여러 플랫폼을 지원하는 애플리케이션 릴리스 및 업데이트에는 여러 컴파일과 패키지가 필요하므로 개발 및 유지 관리 비용이 증가합니다.

uniapp 개발에는 다음과 같은 기초가 필요합니다: 프론트엔드 기술(HTML, CSS, JavaScript) 모바일 개발 지식(iOS 및 Android 플랫폼) Node.js 기타 기초(버전 제어 도구, IDE, 모바일 개발 시뮬레이터 또는 실제 머신 디버깅 경험)

UniApp과 네이티브 개발 중에서 선택할 때는 개발 비용, 성능, 사용자 경험 및 유연성을 고려해야 합니다. UniApp의 장점은 크로스 플랫폼 개발, 빠른 반복, 쉬운 학습 및 내장 플러그인이며, 네이티브 개발은 성능, 안정성, 네이티브 경험 및 확장성이 뛰어납니다. 구체적인 프로젝트 요구사항에 따라 장단점을 따져보세요. UniApp은 초보자에게 적합하고, 네이티브 개발은 고성능과 원활한 경험을 추구하는 복잡한 애플리케이션에 적합합니다.

UniApp은 Vue.js를 기반으로 하고 Flutter는 Dart를 기반으로 하며 둘 다 크로스 플랫폼 개발을 지원합니다. UniApp은 풍부한 구성 요소와 쉬운 개발을 제공하지만 WebView로 인해 성능이 제한됩니다. Flutter는 뛰어난 성능을 갖춘 기본 렌더링 엔진을 사용하지만 개발이 더 어렵습니다. UniApp에는 활발한 중국 커뮤니티가 있고 Flutter에는 대규모 글로벌 커뮤니티가 있습니다. UniApp은 빠른 개발과 낮은 성능 요구 사항이 있는 시나리오에 적합합니다. Flutter는 높은 사용자 정의 및 고성능을 갖춘 복잡한 애플리케이션에 적합합니다.

소규모 프로그램 개발을 위한 uniapp용 권장 구성 요소 라이브러리: uni-ui: uni에서 공식 제작한 기본 구성 요소와 비즈니스 구성 요소를 제공합니다. vant-weapp: Bytedance에서 제작되었으며 심플하고 아름다운 UI 디자인을 자랑합니다. taro-ui: JD.com에서 제작하고 Taro 프레임워크를 기반으로 개발되었습니다. fish-design: 머티리얼 디자인 디자인 스타일을 사용하여 Baidu에서 제작했습니다. naive-ui: Youzan이 제작했으며 현대적인 UI 디자인, 가볍고 사용자 정의가 쉽습니다.
