vue+elementui实现动态多级表头+合并单元格+自适应列宽

1.动态多级表头的实现

因为项目需求是要根据不同查询条件,显示不同的表头,所以需要动态渲染表头
在表格渲染的时候,label和prop要对应起来,简单一点的办法就是让后端传过来,这是我给后端提供的格式

title:[
	 {label:'一级标题1',item:[   //label为表头的内容,prop为对应的字段名(注意字段名要和后端传过来的数据列表的字段名一致)
	 	{label:'二级标题1',item:[
	 		{label:'三级标题1',prop:'value1'},
	 		{label:'三级标题2',prop:'value2'},
	 		{label:'三级标题3',prop:'value3'},
	 		{label:'三级标题4',prop:'value4'},
	 		{label:'三级标题5',prop:'value5'},
	 	]},
	 	{label:'二级标题1',prop:'value6'},
	 	{label:'二级标题2',prop:'value7'},
	 	{label:'二级标题3',prop:'value8'},
	 	{label:'二级标题4',prop:'value9'},
	 	{label:'二级标题5',prop:'value10'},
	 ]},
	 {label:'一级标题2',prop:'value11'},
],

接收到后端传过来的title列表后,在template中渲染
ps:我的表头嵌套最多三层,所以直接这样写了,需要无限嵌套表头的童鞋自行百度吧有很多

<el-table
:data="tableData">
	<el-table-column v-for="(v,idx) in tableHeader" :key="idx"     //tableHeader为后端传过来的title列表
	:label="v.label" :prop="v.prop" :width="v.width" align="center">
		<el-table-column 
			v-for= "(j,i) in v.item" 
			:key="i"
			:prop="j.prop"
			:label="j.label"
			:width="j.width" align="center">
			<el-table-column 
			v-for= "(m,n) in j.item" 
			:key="n"
			:prop="m.prop"
			:label="m.label"
			:width="m.width" align="center">
		</el-table-column>
		</el-table-column>
	</el-table-column>
</el-table>

2.合并单元格

因为表格中的数据可能相邻几行中的前几列内容是一样的,所以需要合并行

<el-table
:data="tableData"
:span-method="arraySpanMethod">   //添加此方法
	<el-table-column v-for="(v,idx) in tableHeader" :key="idx"   
	:label="v.label" :prop="v.prop" :width="v.width" align="center">
		<el-table-column 
			v-for= "(j,i) in v.item" 
			:key="i"
			:prop="j.prop"
			:label="j.label"
			:width="j.width" align="center">
			<el-table-column 
			v-for= "(m,n) in j.item" 
			:key="n"
			:prop="m.prop"
			:label="m.label"
			:width="m.width" align="center">
		</el-table-column>
		</el-table-column>
	</el-table-column>
</el-table>
export default {
	data() {
		return {
			tableData :[],
			spanArr:[],  //需要合并行的个数
			position:0
		}
	}
}
//获取列表数据
getList(page) {
	this.$axios.post('------URL-----').then(res => {
		this.tableData = res.data.data.data;   //接收列表数据
		this.rowspan();   //计算需要合并的行的个数
	});
},
//获得数据相同的行数
rowspan() {
	//每次调用清空数据
	this.spanArr=[];
	this.position=0
	this.tableData.forEach((item,index) => {
		if( index === 0){
			this.spanArr.push(1);
			this.position = 0;
		}else{
			if(this.tableData[index].id === this.tableData[index-1].id ){
				this.spanArr[this.position] += 1;
				this.spanArr.push(0);
			}else{
				this.spanArr.push(1);
				this.position = index;
			}
		}
	})
},
//合并单元格
arraySpanMethod({ row, column, rowIndex, columnIndex }) {  //表格合并行
	if (columnIndex <= 9 ) {   //我项目中需要前9项的行合并
		const _row = this.spanArr[rowIndex] ;   //需要合并多少行
		const _col = _row > 0 ? 1 : 0;   
		return {
			rowspan: _row,
			colspan: _col
		}
	}
},

3.自适应列宽

百度所知elementui是暂不支持根据内容自适应列宽的,fit属性并没有用

export default {
	data() {
		return {
			tableData :[],
			titleList:[],   //调用接口接收到的title列表
			tableHeader:[],  //渲染的列表,已经加上width属性
		}
	}
},
methods:{ 
	//获取列表数据
	getList(page) {
		this.$axios.post('------URL-----').then(res => {
			this.tableData = res.data.data.data;   //接收列表数据
			this.titleList = res.data.data.title;   //接收列表数据
			this.tableHeader = this.getAllItem(this.titleList,this.tableData)  //参数:title列表 数据列表
		});
	},
	//获取每列数据,通过计算加上width属性
	getAllItem(head,data){
		const _this = this
		head.forEach(item => {
			if(item.item){   //递归,判断是否为最后一级标题
				_this.getAllItem(item.item,data)
			}else {
				const arr = data.map(x => x[item.value])  // 获取每一列的所有数据
				arr.push(item.label)  // 把每列的表头也加进去算
				item.width = _this.getMaxLength(arr) + 50 // 每列内容最大的宽度 + 表格的内间距
				return item
			}
		})
		return head
	},
	//使用span标签包裹内容,然后计算span的宽度 width: px
		getTextWidth(str) {
			let width = 0;
			let html = document.createElement('span');
			html.innerText = str;
			html.className = 'getTextWidth';
			document.querySelector('body').appendChild(html);
			width = document.querySelector('.getTextWidth').offsetWidth;
			document.querySelector('.getTextWidth').remove();
			return width;
		},
}	

4.固定表格底部横向滚动条

因为内容过多,当想看表格最后几项内容时,需要把右侧滚动条滑到底部才能看到横向滚动条

<el-table
	:data="tableData"
	:height="table_height"   //给表格添加该属性
	:span-method="arraySpanMethod">   
</el-table>

mounted() {   //在mounted中获取窗口的高,动态计算表格的高
	const that = this;
	that.table_height=document.body.clientHeight-280  //该处减去了头部底部的高度,可按自己需求修改
    window.onresize = function() {
		that.table_height=document.body.clientHeight-280
    };
 },

总体代码

<template>
	<el-table
	:data="tableData"
	:span-method="arraySpanMethod">
		<el-table-column v-for="(v,idx) in tableHeader" :key="idx"   
		:label="v.label" :prop="v.prop" :width="v.width" align="center">
			<el-table-column 
				v-for= "(j,i) in v.item" 
				:key="i"
				:prop="j.prop"
				:label="j.label"
				:width="j.width" align="center">
				<el-table-column 
				v-for= "(m,n) in j.item" 
				:key="n"
				:prop="m.prop"
				:label="m.label"
				:width="m.width" align="center">
			</el-table-column>
			</el-table-column>
		</el-table-column>
	</el-table>
</template>
export default {
	data() {
		return {
			tableData :[],
			titleList:[],   //调用接口接收到的title列表
			tableHeader:[],  //渲染的列表,已经加上width属性
			spanArr:[],
			position:0,
		}
	}
},
mounted() {   //在mounted中获取窗口的高,动态计算表格的高
	const that = this;
	that.table_height=document.body.clientHeight-280  //该处减去了头部底部的高度,可按自己需求修改
    window.onresize = function() {
		that.table_height=document.body.clientHeight-280
    };
 },
methods:{ 
	//获取列表数据
	getList(page) {
		this.$axios.post('------URL-----').then(res => {
			this.tableData = res.data.data.data;   //接收列表数据
			this.titleList = res.data.data.title;   //接收列表数据
			this.tableHeader = this.getAllItem(this.titleList,this.tableData)  //参数:title列表 数据列表
			this.rowspan()
		});
	},
	//获得数据相同的行数
	rowspan() {
		//每次调用清空数据
		this.spanArr=[];
		this.position=0
		this.tableData.forEach((item,index) => {
			if( index === 0){
				this.spanArr.push(1);
				this.position = 0;
			}else{
				if(this.tableData[index].id === this.tableData[index-1].id ){
					this.spanArr[this.position] += 1;
					this.spanArr.push(0);
				}else{
					this.spanArr.push(1);
					this.position = index;
				}
			}
		})
	},
	//合并单元格
	arraySpanMethod({ row, column, rowIndex, columnIndex }) {  //表格合并行
		if (columnIndex <= 9 ) {   //我项目中需要前9项的行合并
			const _row = this.spanArr[rowIndex] ;   //需要合并多少行
			const _col = _row > 0 ? 1 : 0;   
			return {
				rowspan: _row,
				colspan: _col
			}
		}
	},
	//获取每列数据,通过计算加上width属性
	getAllItem(head,data){
		const _this = this
		head.forEach(item => {
			if(item.item){   //递归,判断是否为最后一级标题
				_this.getAllItem(item.item,data)
			}else {
				const arr = data.map(x => x[item.value])  // 获取每一列的所有数据
				arr.push(item.label)  // 把每列的表头也加进去算
				item.width = _this.getMaxLength(arr) + 50 // 每列内容最大的宽度 + 表格的内间距
				return item
			}
		})
		return head
	},
	//使用span标签包裹内容,然后计算span的宽度 width: px
	getTextWidth(str) {
		let width = 0;
		let html = document.createElement('span');
		html.innerText = str;
		html.className = 'getTextWidth';
		document.querySelector('body').appendChild(html);
		width = document.querySelector('.getTextWidth').offsetWidth;
		document.querySelector('.getTextWidth').remove();
		return width;
	},
}	
  • 4
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
### 回答1: Spring Boot 和 Vue 结合使用,可以通过 Element UI 来实现动态路由。 具体步骤如下: 1. 在 Spring Boot 中,定义一个 API 接口,用于返回动态路由的配置信息,例如菜单列表、权限信息等。 2. 在 Vue 中,使用 axios 等工具调用该 API 接口获取动态路由的配置信息。 3. 在 Vue 中,使用 vue-router 来实现路由功能。在路由配置中,使用获取到的动态路由信息来动态生成路由。例如,使用菜单列表来生成菜单路由,使用权限信息来控制路由的访问权限等。 4. 在 Vue 中,结合 Element UI 的组件,可以实现一些常见的路由功能,例如面包屑导航、菜单栏等。 综上所述,通过 Spring Boot、Vue 和 Element UI 的结合,可以实现动态路由功能,从而实现更加灵活、可扩展的前端页面管理。 ### 回答2: Spring Boot是一个开发框架,Vue是一个前端框架,Element UI是一个UI组件库,如何实现动态路由呢? 首先,在Spring Boot后端,需要定义一个接口来获取动态路由的数据。可以使用一个数据库表来存储路由信息,如路由路径、组件名称、图标等。然后,通过编写一个控制器类,来处理获取动态路由数据的请求。在该控制器类中,可以调用相应的服务类或数据访问层来获取路由数据,并返回给前端。 接下来,在Vue前端项目中,可以使用Vue Router来实现动态路由。可以在项目的入口文件(如main.js)中,通过发送请求获取动态路由数据。可以使用axios等库来发送请求,获取后端返回的动态路由数据。获取到数据后,可以通过遍历的方式,动态地把路由配置项添加到Vue Router中。 同时,在项目中引入Element UI组件库,可以使用其中的菜单、导航等组件,来展示动态路由。可以根据获取的动态路由数据,来生成菜单和导航栏的数据,并将其展示在页面中。 为了实现动态路由的跳转,可以使用Vue Router中的路由守卫(如beforeEach),在路由跳转之前判断是否有权限访问该路由。可以根据当前用户的权限信息,来判断是否有权限访问该路由。如果没有权限,则可以跳转到其他页面或者显示相应的提示信息。 总结来说,通过在Spring Boot后端定义接口获取动态路由数据,并在Vue前端项目中将其配置到Vue Router中,配合使用Element UI的菜单、导航组件,就可以实现Spring Boot、Vue和Element UI的动态路由。 ### 回答3: 要实现动态路由,我们可以结合使用Spring Boot、Vue和Element UI。 首先,在Spring Boot后端,我们需要建立一个API接口,用于获取动态路由的数据。这个接口可以返回一个JSON对象,包含了多个路由对象的信息,如路由名称、路径、组件等。 接下来,在Vue前端,我们可以使用Element UI的导航菜单组件来实现动态路由。首先,我们需要在Vue项目中安装Element UI,并引入导航菜单组件。然后,在主页面组件中,我们可以通过调用后端的API接口获取动态路由数据,然后根据返回的数据动态生成导航菜单。可以使用Vue Router来管理路由,并使用 `<router-view>` 标签来展示对应的页面组件。 在生成导航菜单时,我们可以使用递归组件来实现无限嵌套的导航菜单结构。每个导航菜单项可以绑定点击事件,当用户点击菜单项时,可以通过Vue Router进行路由跳转,展示对应的页面组件。 为了保证路由权限控制,我们可以在后端API接口中加入用户权限验证的逻辑。在前端,我们可以根据用户的角色或权限信息动态生成导航菜单,只展示用户有权限访问的路由。 总结来说,使用Spring Boot提供API接口获取动态路由数据,然后在Vue前端使用Element UI的导航菜单组件构建动态路由。通过递归组件生成无限嵌套的导航菜单,并通过Vue Router实现路由跳转。同时,可以结合用户权限信息进行路由权限控制。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值