Vue3指令篇 -- 自定义指令实现表格填充剩余空间

场景描述

PC端网页开发时,表格的CRUD是我们逃不掉的宿命。在渲染表格时,往往是默认 10 | 15 | 20 作为表格请求的长度,但是由于显示屏和电脑设置等等导致的差异,有时候会导致表格下方出现大量空白。这时候我们可以根据屏幕的剩余空间去动态改变 pageSize 的值,以达到较好的效果。因为无法保证每一行都是占用一行,所以出现滚动条是很正常的。

具体实现

计算每页数量

基于 el-table 的自定义指令,el-table 每一行默认的高度为 40 ;根据自己的场景,表格距离底部的一个距离,一般底部都是有分页组件的。实现 resize 函数,在该函数内实现表格的第一次请求。

// 默认表格每一行的高度
const defaultRowHeight = 40
// pageination的高度50 + mg-top:12 + 页面的padding20
const bottomHeight = 82

const resize = (el, bind) => {
    const { value } = bind
    const {
        params,
        getTableData,
    } = value

    const height = window.innerHeight - el.getBoundingClientRect().top
    el.style.height = 'auto'

    // 获取表头的高度
    const elTableHeaderDom = el.querySelector('.el-table__header-wrapper')
    // delSize是除去表头的行数
    const delSize = elTableHeaderDom && Math.ceil(elTableHeaderDom.clientHeight / defaultRowHeight)

    // 分页表格
    const autoSize = Math.ceil((height - bottomHeight) / defaultRowHeight) - delSize
    params[sizeKey] = autoSize <= 0 ? 1 : autoSize
    getTableData && getTableData()
}
监听屏幕变化,动态改变 size
const setObserver = (el, bind) => {
    el.resizeObserver = new ResizeObserver(
        // 这是lodash库的节流函数
        _.throttle(() => {
            resize(el, bind);
        }, 500)
    );
    // 监听body的变化
    el.resizeObserver?.observe(document.body);
}
清除observer
const clearObserver = el => {
	el.resizeObserver?.disconnect()
	delete el.resizeObserver
}
指令实现

注意 keep-alive 的组件

export default {
    mounted(el, bind) {
        setObserver(el, bind)
    },
    beforeUpdate(el, bind) {
        // keep-alive组件activated
        if (el.isConnected && !el.resizeObserver) {
            setObserver(el, bind)
        }

        // keep-alive组件deactivated
        if (!el.isConnected && el.resizeObserver) {
            clearObserver(el)
        }
    },
    // 非keep-alive组件卸载
    beforeUnmount(el) {
        clearObserver(el)
    },
}
完整代码

为了避免重复提交请求,新增个判断 – 2024.2.2

/**
 * @description: 表格填充剩余空间
 * @param {Object} value - 指令的绑定值
 * @param {Object} value.params - 请求列表的参数-必传
 * @param {String} value.sizeKey - 请求列表的参数-可选,默认为size
 * @param {Function} value.getTableData - 请求列表的方法-可选-根据具体页面而定,因为涉及到缓存
 * eg:
 * <el-table v-fill-space="{ params, sizeKey: 'pageSize', getTableData }"></el-table>
*/
import _ from 'lodash';

// 默认表格每一行的高度
const defaultRowHeight = 40
// pageination的高度50 + mg-top:12 + 页面的padding20
const bottomHeight = 82
// 避免重复发送相同请求
let isRepeatSubmit = false

// 重新计算高度
const resize = async (el, bind) => {
	const { value } = bind
	const {
		params,
		sizeKey = 'size',
		getTableData,
	} = value

	const height = window.innerHeight - el.getBoundingClientRect().top
	el.style.height = 'auto'

	// 获取表头的高度
	const elTableHeaderDom = el.querySelector('.el-table__header-wrapper')
	// delSize是除去表头的行数,如果表头有多行,需要传入delSize
	const delSize = elTableHeaderDom && Math.ceil(elTableHeaderDom.clientHeight / defaultRowHeight)

	// 分页表格
	const autoSize = Math.ceil((height - bottomHeight) / defaultRowHeight) - delSize
	params[sizeKey] = autoSize <= 0 ? 1 : autoSize
	if (getTableData && !isRepeatSubmit) {
		isRepeatSubmit = true
		await getTableData()
		isRepeatSubmit = false
	}
}

// 设置observer
const setObserver = (el, bind) => {
	el.resizeObserver = new ResizeObserver(
		_.throttle(() => {
			resize(el, bind);
		}, 500)
	);
	// 监听body的变化,不可监听el的变化
	el.resizeObserver?.observe(document.body);
}

// 清除observer
const clearObserver = el => {
	el.resizeObserver?.disconnect()
	delete el.resizeObserver
}

export default {
	mounted(el, bind) {
		setObserver(el, bind)
	},
	beforeUpdate(el, bind) {
		// keep-alive组件activated
		if (el.isConnected && !el.resizeObserver) {
			setObserver(el, bind)
		}

		// keep-alive组件deactivated
		if (!el.isConnected && el.resizeObserver) {
			clearObserver(el)
		}
	},
	// 非keep-alive组件卸载
	beforeUnmount(el) {
		clearObserver(el)
	},
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值