草庐IT

【移动端表格组件】uniapp简单实现H5,小程序,APP多端兼容表格功能,复制即用,简单易懂【详细注释版本】

接口写好了吗 2023-04-03 原文

前言:

由于最近需要做移动端的项目
有个pc端的后台系统里面需要移一部分页面过来
而里面就有很多的表格,我就开始惯例网上先找前人栽的树,我好乘凉
然后找了一圈发现,不管是主流的移动端ui库或者网上自己写的帖子,或者uniapp的插件网站
都没有看到符合我要求的表格,然后如果要改别人的源码那我看代码都要看很久,好切有些还奇奇怪怪的bug不兼容
可能是别人使用了某些组件和插件之类的。导致我很多设置不生效。没错,我也改过别人的源码了,后来放弃了。
所以我就直接手写了一个简单的表格展示组件,配上一些我需要的功能。可以先用着了。
重点是我是原生的标签写的,不是引入一大堆的插件之类的,uniapp可以直接用。
想修改源码也简单。我都注释好了

效果图

小程序页面兼容,可以看到点击按钮之后会拿到对应行的数据

H5页面的,也是一样兼容的可能,也能拿到数据

移动端,手机预览效果,展示了数据和点击生效,滚动到底部可以触发方法,可以在这里写加载第二页表格的方法



功能:

1,数据展示:只需要往组件内传入表头和列表数据就能展示,列表数据和elementul的表格一样。表头要自己配置
2,固定表头:上滚动的时候表头会定位在上面不动
3,固定列:表头内配置属性,可以让这一列固定左边不动。目前只能固定一列
4,行底纹:就是给一行的单元格加上背景色,需要在tabledata列表中添加一个字段bgcolor就可以了
5,列底纹:同上,区别是在表头内添加一个字段bgcolor
6,单元格文字颜色改变:这是我们项目的要求,需要拿到每个单元格的数据和指标对比大小来标红。这里在父组件就可以配置
7,操作列:表头添加操作列,key给edit就会出现一个编辑和删除的列。不写就没有这一列。点击按钮会触发父组件的方法
8,滚动到底部:滚动到底部会触发父组件方法。可以做业务操作,比如拿第二页的表格
9,自动列宽:根据表格内单元格内容的宽度来动态赋值几个宽度,宽度是提前定义好的。由于表头和表体需要宽度一致,所以提前设置几个档次的固定宽度。具体使用是自动根据表体或者表头哪一个长,用哪一个的宽。保证数据的展示完全。当数据过长的时候会自动隐藏并省略号显示。这里我就没有加其他的功能了,后期可以自行更改,把这个文字加一个组件包裹,就是点击可以显示全部文字的弹框那个。

引入组件

uniapp可以直接使用,整体就引入了一个组件,uniapp带有的scroll-view组件。需要去uniapp文档内引入一下,直接插件市场下载一下就好了

代码:

组件部分:
写一个tableDiv的vue文件,当然名字随便你换

然后把代码复制进去。

<template>
	<view class="wrap">
		<!-- @scrolltolower:滚动到底部触发  lower-threshold:距离底部多少距离触发@scrolltolower -->
		<scroll-view class="scroll-view_H" scroll-x="true" scroll-y="true" @scrolltolower='scrollBottom'
			:lower-threshold='2'>
			<view class="top" id="top" :style="{width:tableWidths+'px'}">
				<view v-for="(h,n) in header" :key='n' :class="{'header_dyg':true,'flexs':h.flxe}"
					:style="{width:h.hWidth+'px'}">
					{{h.name}}
				</view>
			</view>
			<view class="bottom" :style="{maxHeight: tableHeight+'px',width:tableWidths+'px'}">
				<view class="tablebox" v-for="(t,s) in tableData" :key='s' @click="jumpDetailed(t)">
					<view v-for="(h,n) in header" :key="n"
						:class="{'table_dyg':true,'tdColClass':h.bgcolor,'tdRowClass':t.bgcolor,'flexs':h.flxe}"
						:style="{width:h.hWidth+'px'}">
						<!-- 不等于操作列就显示文字 -->
						<text v-if="h.key!=='edit'" :style="{color:getColor(t,h)}">{{t[h.key]}}</text>
						<!-- 操作列显示按钮,后期用插槽 -->
						<view class="uni-group" v-else style="background-color: #fff;">
							<button class="uni-button" size="mini" type="primary" style="margin-right: 5px;"
								@click="editTable(t)">编辑</button>
							<button class="uni-button" size="mini" type="warn" @click="deleteTable(t)">删除</button>
						</view>
					</view>
				</view>
			</view>
		</scroll-view>
	</view>
</template>

<script>
	// 表头配置:flxe(固定列),bgcolor(列底纹)
	// 表体配置:bgcolor(行底纹)
	export default {
		props: {
			data2: {
				type: Array,
				required: true,
				default: function() {
					return [];
				}
			},
			head: {
				type: Array,
				required: true,
				default: function() {
					return [];
				}
			},
			tableHeight: {
				required: true,
				type: [Number, String],
				default: function() {
					return 0;
				}
			}
		},
		data() {
			return {
				//表体
				tableData: [],
				//表头
				header: [],
				// 表格总长度
				tableWidths:0
			}
		},
		watch:{
			// 监听列表
			'data2'(a,b){
				this.tableData = a
			},
			// 监听表头
			'head'(a,b){
				this.header = a
				//计算列宽
				this.tableWidth()
			},
		},
		created() {
			//#ifdef H5
			this.tableData = this.data2 //列表
			this.header = this.head //表头
			this.tableWidth()
			// #endif
		},
		methods: {
			// 返回行数据
			jumpDetailed(row){
				this.$emit('rowData',row)
			},
			// 滚动到底部,调用父组件方法
			scrollBottom(e) {
				// 滚动到底部才触发,滚动到右边不触发
				if (e.detail.direction == "bottom") {
					this.$emit('scrollBottom')
				}
			},
			// 颜色对比
			getColor(row, col) {
				let color = 'black'
				// 传值给父组件,通过父组件的方法内计算判断当前单元格数据是否需要标红,然后通过回调函数,返回一个color值来渲染
				this.$emit('getTextColor', row, col, val => {
					color = val
				})
				return color
			},
			// 修改按钮
			editTable(val) {
				this.$emit('getEdit', val)
			},
			// 删除按钮
			deleteTable(val) {
				this.$emit('getDelete', val)
			},
			// 计算单元格宽度
			tableWidth() {
				let w=0 //计算表格长度
				this.header.forEach((head, index) => {
					let hw = head.name.length //表头单元格宽度
					let dw = 0 //列表单元格宽度
					this.tableData.forEach(data => {
						// 如果是操作列,就直接给十个字符长度,也就是列宽自动150,不是操作列的统一看字符串长度决定宽度
						let a = (head.key == 'edit' ? '1234567891' : (data[head.key]?data[head.key].toString():'1'))
						let tw = (head.key == 'edit' ? 10 : a.length)
						// 这里每次循环找出更大的数赋值,确保dw中是表体单元格这一列中最大宽度,根据最大宽度来判断单元格显示
						if (dw < tw) {
							dw = tw
						}
					})
					// 表体单元格内容宽度小于表头内容时,以表头的宽度为主。根据表头的字符长度来区分宽度
					if (dw <= hw) {
						if (hw <= 3) {
							head['hWidth'] = 50
						} else if (hw <= 5) {
							head['hWidth'] = 80
						} else {
							head['hWidth'] = 130
						}
					} else {
						// 表体内容宽度大于表头内容宽度时,以表体宽度为主。根据表头的字符长度来区分宽度
						if (dw <= 3) {
							head['hWidth'] = 50
						} else if (dw <= 5) {
							head['hWidth'] = 80
						} else {
							head['hWidth'] = 130
						}
					}
					w+=head['hWidth'] //叠加表格总长度
				})
				this.tableWidths=w   //给表格赋值总长度
			}
		}
	}
</script>

<style lang="scss">
	.wrap {
		width: 100%;
	}

	// 表头
	.top {
		display: flex;
		position: sticky; //表头向上滚动时固定住
		top: 0;
		//width: 750px; //左右滚动时不会把固定的表头滚动走
		z-index: 100; //滑动时表头不被覆盖

		.header_dyg {
			height: 40px;
			text-align: center;
			line-height: 40px;
			border-top: 1px solid #ccc;
			border-right: 1px solid #ccc;
			border-bottom: 1px solid #ccc;
			padding: 0 5px;
			background-color: #f5f5f6;
			font-size: 14px;
			font-weight: bold;
			color: #2b2b2b;
			flex-shrink: 0;
		}

		// 列定位固定单元格
		.flexs {
			position: sticky;
			left: 0;
			background-color: #f5f5f6;
			z-index: 10;
		}
	}

	// 表格列表
	.bottom {
		//width: 750px;

		.tablebox {
			display: flex;
			font-size: 14px;

			.table_dyg {
				height: 30px;
				text-align: center;
				line-height: 30px;
				white-space: nowrap;
				overflow: hidden;
				text-overflow: ellipsis;
				border-right: 1px solid #ccc;
				border-bottom: 1px solid #ccc;
				padding: 0 5px;
				flex-shrink: 0;
			}

			// 列定位固定单元格
			.flexs {
				position: sticky;
				left: 0;
				background-color: #fff;
				z-index: 10;
			}
		}
	}

	// 列的颜色
	.tdColClass {
		background-color: #d9edf7;
	}

	// 行的颜色
	.tdRowClass {
		background-color: #afdfe4;
	}
</style>


然后父组件引入子组件使用

<template>
	<view class="box">
			<!-- 表格组件:参数解释:@getTextColor:调用方法判断数据后返回对比颜色,可以改变单元格文字的颜色 -->
			<!-- @getEdit:点击表格中编辑按钮会触发的方法  @getDelete:点击表格中删除按钮会触发的方法  @scrollBottom:滚动到底部时触发 @rowData:获取点击行的数据-->
			<!-- data:列表数据,格式和elementul表格一样,head:表头数据,格式[{name:'列名',key:'对应列表的key',bgcolor:1代表这一列添加背景色,flxe:1代表这一列固定}],tableHeight:表格表体高度 -->
			<mytable @scrollBottom='scrollBottom' @getTextColor='getRedText' @getEdit='editTable'
				@getDelete='deleteTable' @rowData='getRow' :data2='tableData' :head='header' :tableHeight='310'>
			</mytable>
		</view>
</template>

<script>
	import tableDiv from './tableDiv.vue'
	export default {
		components: {
			tableDiv
		},
		data() {
			return {
				//表体
				tableData: [{
					"date": "2020-09-01",
					"name": "11",
					"address": "上海市普陀区金沙江路 1518 弄",
					"age": "18",
					bgcolor: 1
				}, {
					"date": "2020-09-02",
					"name": "22",
					"address": "上海市普陀区金沙江路 1517 弄",
					"age": "18"
				}, {
					"date": "2020-09-03",
					"name": "33",
					"address": "上海市普陀区金沙江路 1519 弄",
					"age": "18"
				}, {
					"date": "2020-09-04",
					"name": "44",
					"address": "上海市普陀区金沙江路 1516 弄",
					"age": "18"
				}, {
					"date": "2020-09-05",
					"name": "55",
					"address": "上海市普陀区金沙江路 1518 弄",
					"age": "18"
				}, {
					"date": "2020-09-06",
					"name": "66",
					"address": "上海市普陀区金沙江路 1517 弄",
					"age": "18"
				}, {
					"date": "2020-09-06",
					"name": "66",
					"address": "上海市普陀区金沙江路 1517 弄",
					"age": "18"
				}, {
					"date": "2020-09-06",
					"name": "66",
					"address": "上海市普陀区金沙江路 1517 弄",
					"age": "18"
				}, {
					"date": "2020-09-06",
					"name": "66",
					"address": "上海市普陀区金沙江路 1517 弄",
					"age": "18"
				}, {
					"date": "2020-09-06",
					"name": "66",
					"address": "上海市普陀区金沙江路 1517 弄",
					"age": "18"
				}, {
					"date": "2020-09-06",
					"name": "66",
					"address": "上海市普陀区金沙江路 1517 弄",
					"age": "18"
				}, {
					"date": "2020-09-06",
					"name": "66",
					"address": "上海市普陀区金沙江路 1517 弄",
					"age": "18"
				}, {
					"date": "2020-09-06",
					"name": "66",
					"address": "上海市普陀区金沙江路 1517 弄",
					"age": "18"
				}],
				//表头
				header: [{
					name: '日期',
					key: 'date',
					flxe: 1 //固定的列,只能有一个列
				}, {
					name: '姓名',
					key: 'name',
					bgcolor: 1 //列底纹
					
				}, {
					name: '地址',
					key: 'address'
				}, {
					name: '年龄',
					key: 'age'
				}, {
					name: '年龄',
					key: 'age'
				}, {
					name: '操作',
					key: 'edit'
				}]
			}
		},
		methods: {
			// 自定义事件方法,业务逻辑判断是否需要标红,然后回调给子组件颜色
			getRedText(row, col, callback) {
				let color = 'black'
				// 判断值是否需要标红
				if (row[col.key] == '22') {
					color = 'red'
				} else {
					color = 'black'
				}
				// 通过回调函数返回值
				callback(color);
			},
			// 编辑按钮
			editTable(val){
				console.log(val,'编辑');
				uni.showToast({
					title: val.date+'编辑'
				})
			},
			// 删除按钮
			deleteTable(val){
				console.log(val,'删除');
				uni.showToast({
					title: val.date+'删除'
				})
			},
			// 滚动到底部
			scrollBottom(){
				uni.showToast({
					title: '滚动到底部了'
				})
				console.log('滚动到底部了');
			}
		}
	}
</script>

<style lang="scss">

</style>

注意点:

由于小程序不支持直接vue那种父子组件传参形式。拿不到数据,所以这里需要用watch监听一下props变化及时更新子组件。

H5页面是可以支持vue的原本写法的。直接进来拿props就可以使用了。所以这里直接created内赋值一下就可以了

有关【移动端表格组件】uniapp简单实现H5,小程序,APP多端兼容表格功能,复制即用,简单易懂【详细注释版本】的更多相关文章

  1. ruby - 在 Ruby 程序执行时阻止 Windows 7 PC 进入休眠状态 - 2

    我需要在客户计算机上运行Ruby应用程序。通常需要几天才能完成(复制大备份文件)。问题是如果启用sleep,它会中断应用程序。否则,计算机将持续运行数周,直到我下次访问为止。有什么方法可以防止执行期间休眠并让Windows在执行后休眠吗?欢迎任何疯狂的想法;-) 最佳答案 Here建议使用SetThreadExecutionStateWinAPI函数,使应用程序能够通知系统它正在使用中,从而防止系统在应用程序运行时进入休眠状态或关闭显示。像这样的东西:require'Win32API'ES_AWAYMODE_REQUIRED=0x0

  2. ruby - 如何指定 Rack 处理程序 - 2

    Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

  3. ruby - 在 Ruby 中编写命令行实用程序 - 2

    我想用ruby​​编写一个小的命令行实用程序并将其作为gem分发。我知道安装后,Guard、Sass和Thor等某些gem可以从命令行自行运行。为了让gem像二进制文件一样可用,我需要在我的gemspec中指定什么。 最佳答案 Gem::Specification.newdo|s|...s.executable='name_of_executable'...endhttp://docs.rubygems.org/read/chapter/20 关于ruby-在Ruby中编写命令行实用程序

  4. ruby-on-rails - Rails 应用程序之间的通信 - 2

    我构建了两个需要相互通信和发送文件的Rails应用程序。例如,一个Rails应用程序会发送请求以查看其他应用程序数据库中的表。然后另一个应用程序将呈现该表的json并将其发回。我还希望一个应用程序将存储在其公共(public)目录中的文本文件发送到另一个应用程序的公共(public)目录。我从来没有做过这样的事情,所以我什至不知道从哪里开始。任何帮助,将不胜感激。谢谢! 最佳答案 无论Rails是什么,几乎所有Web应用程序都有您的要求,大多数现代Web应用程序都需要相互通信。但是有一个小小的理解需要你坚持下去,网站不应直接访问彼此

  5. ruby - 无法运行 Rails 2.x 应用程序 - 2

    我尝试运行2.x应用程序。我使用rvm并为此应用程序设置其他版本的ruby​​:$rvmuseree-1.8.7-head我尝试运行服务器,然后出现很多错误:$script/serverNOTE:Gem.source_indexisdeprecated,useSpecification.Itwillberemovedonorafter2011-11-01.Gem.source_indexcalledfrom/Users/serg/rails_projects_terminal/work_proj/spohelp/config/../vendor/rails/railties/lib/r

  6. ruby-on-rails - Rails 应用程序中的 Rails : How are you using application_controller. rb 是新手吗? - 2

    刚入门rails,开始慢慢理解。有人可以解释或给我一些关于在application_controller中编码的好处或时间和原因的想法吗?有哪些用例。您如何为Rails应用程序使用应用程序Controller?我不想在那里放太多代码,因为据我了解,每个请求都会调用此Controller。这是真的? 最佳答案 ApplicationController实际上是您应用程序中的每个其他Controller都将从中继承的类(尽管这不是强制性的)。我同意不要用太多代码弄乱它并保持干净整洁的态度,尽管在某些情况下ApplicationContr

  7. ruby-on-rails - 项目升级后 Pow 不会更改 ruby​​ 版本 - 2

    我在我的Rails项目中使用Pow和powifygem。现在我尝试升级我的ruby​​版本(从1.9.3到2.0.0,我使用RVM)当我切换ruby​​版本、安装所有gem依赖项时,我通过运行railss并访问localhost:3000确保该应用程序正常运行以前,我通过使用pow访问http://my_app.dev来浏览我的应用程序。升级后,由于错误Bundler::RubyVersionMismatch:YourRubyversionis1.9.3,butyourGemfilespecified2.0.0,此url不起作用我尝试过的:重新创建pow应用程序重启pow服务器更新战俘

  8. ruby-on-rails - 在 ruby​​ .gemspec 文件中,如何指定依赖项的多个版本? - 2

    我正在尝试修改当前依赖于定义为activeresource的gem:s.add_dependency"activeresource","~>3.0"为了让gem与Rails4一起工作,我需要扩展依赖关系以与activeresource的版本3或4一起工作。我不想简单地添加以下内容,因为它可能会在以后引起问题:s.add_dependency"activeresource",">=3.0"有没有办法指定可接受版本的列表?~>3.0还是~>4.0? 最佳答案 根据thedocumentation,如果你想要3到4之间的所有版本,你可以这

  9. ruby-on-rails - 如何在我的 Rails 应用程序 View 中打印 ruby​​ 变量的内容? - 2

    我是一个Rails初学者,但我想从我的RailsView(html.haml文件)中查看Ruby变量的内容。我试图在ruby​​中打印出变量(认为它会在终端中出现),但没有得到任何结果。有什么建议吗?我知道Rails调试器,但更喜欢使用inspect来打印我的变量。 最佳答案 您可以在View中使用puts方法将信息输出到服务器控制台。您应该能够在View中的任何位置使用Haml执行以下操作:-puts@my_variable.inspect 关于ruby-on-rails-如何在我的R

  10. ruby - 简单获取法拉第超时 - 2

    有没有办法在这个简单的get方法中添加超时选项?我正在使用法拉第3.3。Faraday.get(url)四处寻找,我只能先发起连接后应用超时选项,然后应用超时选项。或者有什么简单的方法?这就是我现在正在做的:conn=Faraday.newresponse=conn.getdo|req|req.urlurlreq.options.timeout=2#2secondsend 最佳答案 试试这个:conn=Faraday.newdo|conn|conn.options.timeout=20endresponse=conn.get(url

随机推荐