element-plus 表格实现最小列宽

背景

产品要求表格的每一列的宽度为该列中的文字的长度,使其中的文字不换行.

技术方案

借鉴 juejin.cn/post/686584...

对table中的cell增加不换行滚动样式(注意样式穿透),让我们能够通过scrollWidth获得cell内的元素宽度

css 复制代码
::v-deep(.cell) {
        white-space: nowrap;
        overflow: auto;
        display: inline-block;
}

编写vue定义指令(v-fit-colums),获取table每一列元素的宽度的最大值,将该值设置为该一列的宽度

js 复制代码
export default function fitColumns(app) {
	app.directive('fit-columns', {
		mounted(el) {
			setTimeout(() => {
				adjustColumnWidth(el)
			}, 300)
		},
		updated(el) {
			setTimeout(() => {
				adjustColumnWidth(el)
			}, 300)
		},
		unmounted(el) {
		},
	})
}

function adjustColumnWidth(table) {
	console.log('2222333', table)
	const colgroup = table.querySelector('colgroup')
	const colDefs = [...colgroup.querySelectorAll('col')]
	colDefs.forEach((col) => {
		const clsName = col.getAttribute('name')
		const cells = [
			...table.querySelectorAll(`td.${clsName}`),
			...table.querySelectorAll(`th.${clsName}`),
		]
		// 忽略加了"leave-alone"类的列
		if (cells[0]?.classList?.contains?.('leave-alone')) {
			return
		}
		const widthList = cells.map((el) => {
			return el.querySelector('.cell')?.scrollWidth || 0
		})
		const max = Math.max(...widthList)
		const padding = 32
		table.querySelectorAll(`col[name=${clsName}]`).forEach((el) => {
			el.setAttribute('width', max + padding)
		})
	})
}

但是由于公司的搜索栏是可收缩的,搜索栏一改变会导致table的大小发生改变(这个时候不会调用updated生命周期),因此需要给el添加resizeObserver,同时将resizeObserver注册到el中,方便unmounted的时候卸载

js 复制代码
export default function fitColumns(app) {
	app.directive('fit-columns', {
		mounted(el) {
			const resizeObserver = new ResizeObserver((entries) => {
				for (let entry of entries) {
					setTimeout(() => {
						adjustColumnWidth(entry.target)
					}, 300)
				}
			})
			resizeObserver.observe(el)
			el.resizeObserver = resizeObserver
			setTimeout(() => {
				adjustColumnWidth(el)
			}, 300)
		},
		updated(el) {
			setTimeout(() => {
				adjustColumnWidth(el)
			}, 300)
		},
		unmounted(el) {
			el.resizeObserver.unobserve(el)
			el.resizeObserver = null
		},
	})
}

按照 参考文章中评论说到的 table表头在大屏幕中会错乱的问题,这是由于表头(.el-table__header-wrapper)的样式 overflow 为hidden,这个时候只需要将其设置为scroll,同时将滚动条隐藏

css 复制代码
::v-deep(.el-table__header-wrapper) {
			overflow: scroll;
			scrollbar-width: none; /* Firefox 隐藏滚动条 */
			-ms-overflow-style: none; /* IE 和 Edge 隐藏滚动条 */
			&::-webkit-scrollbar {
				display: none;
			}
		}

在table过宽的情况下,会出现滚动表单内容表头不会同时滚动,这个应该是element内部处理的问题,将header和body分开来,这个时候需要在v-fit-colums 中为table的表单内容绑定滚动事件(由于表头隐藏了不需要在表头绑定),同时采用requestAnimationFrame代替防抖进行性能优化

js 复制代码
export default function fitColumns(app) {
	app.directive('fit-columns', {
		mounted(el) {
			const resizeObserver = new ResizeObserver((entries) => {
				for (let entry of entries) {
					setTimeout(() => {
						adjustColumnWidth(entry.target)
					}, 300)
				}
			})
			resizeObserver.observe(el)
			el.resizeObserver = resizeObserver
			setTimeout(() => {
				adjustColumnWidth(el)
			}, 300)
			const wrap = el.querySelector('.el-scrollbar__wrap')
			const header = el.querySelector('.el-table__header-wrapper')
			wrap.addEventListener('scroll', () => {
				requestAnimationFrame(header.scrollTo(wrap.scrollLeft, 0))
			})
		},
		updated(el) {
			setTimeout(() => {
				adjustColumnWidth(el)
			}, 300)
		},
		unmounted(el) {
			el.resizeObserver.unobserve(el)
			el.resizeObserver = null
			const wrap = el.querySelector('.el-scrollbar__wrap')
			wrap.removeEventListener('scroll')
		},
	})
}
相关推荐
0思必得04 小时前
[Web自动化] Selenium处理动态网页
前端·爬虫·python·selenium·自动化
东东5165 小时前
智能社区管理系统的设计与实现ssm+vue
前端·javascript·vue.js·毕业设计·毕设
catino5 小时前
图片、文件的预览
前端·javascript
layman05287 小时前
webpack5 css-loader:从基础到原理
前端·css·webpack
半桔7 小时前
【前端小站】CSS 样式美学:从基础语法到界面精筑的实战宝典
前端·css·html
AI老李7 小时前
PostCSS完全指南:功能/配置/插件/SourceMap/AST/插件开发/自定义语法
前端·javascript·postcss
_OP_CHEN7 小时前
【前端开发之CSS】(一)初识 CSS:网页化妆术的终极指南,新手也能轻松拿捏页面美化!
前端·css·html·网页开发·样式表·界面美化
啊哈一半醒7 小时前
CSS 主流布局
前端·css·css布局·标准流 浮动 定位·flex grid 响应式布局
PHP武器库7 小时前
ULUI:不止于按钮和菜单,一个专注于“业务组件”的纯 CSS 框架
前端·css
电商API_180079052477 小时前
第三方淘宝商品详情 API 全维度调用指南:从技术对接到生产落地
java·大数据·前端·数据库·人工智能·网络爬虫