1 动态计算表格组件的高度
1.1 说明
作用:在使用 el-table 或 a-table 时,总是需要固定表头,而固定表头就需要设置高度,高度通常是要撑满容器,但百分比或 calc 设置的高度并不准确。
思路:给表格组件包装一层,通过获取包装容器的高度来设置表格高度。
1.2 实现
/*
* 表格高度自动适配
*/
import { onMounted, onUnmounted, Ref, ref } from 'vue'
import * as utils from '@/util/common'
export default function useTableHeight(tableWrapperRef: Ref<HTMLElement | undefined>) {
const tableHeight = ref<number>()
const setTableHeight = () => {
if (!tableWrapperRef.value) return
tableHeight.value = tableWrapperRef.value.clientHeight
}
const resizeHandler = utils.throttle(() => {
setTableHeight()
}, 300)
onMounted(() => {
setTableHeight()
window.addEventListener('resize', resizeHandler)
})
onUnmounted(() => {
window.removeEventListener('resize', resizeHandler)
})
return {
tableHeight,
setTableHeight,
}
}
1.3 使用
<div ref="tableWrapperRef">
<el-table :height="tableHeight">
或
<a-table :scroll="{ y: tableHeight }">
</div>
const tableWrapperRef = ref()
const { tableHeight, setTableHeight } = useTableHeight(tableWrapperRef)
另外:
- 包装容器需要设置 flex: 1,得撑开高度;
- 如果表格空白,手动调用 setTableHeight;
- a-table 的 scroll.y 设置的是表体高度,计算结果需要减去表头高度才准确。
2 离开表单页面前提示数据会丢失
2.1 说明
作用:让用户清楚的知道,如果离开或刷新表单页面,那么已经填写的内容就会丢失。
思路:监听表单字段,只要发生改变,那么在离开路由或刷新时就触发提示。
特殊场景的处理:
场景一:有的表单页面在初始化时会自动给表单项赋值,如果一开始就监听的话,总是会触发提示
解决方法:延迟监听(目前没想到更好的方法)
场景二:表单提交成功跳转时,不能触发提示
解决方法:在跳转前清除监听
2.2 实现
/**
* 离开或刷新表单页面前提示数据会丢失
*/
import { Modal } from 'ant-design-vue'
import { WatchStopHandle, onMounted, onUnmounted, ref, watch } from 'vue'
import { onBeforeRouteLeave } from 'vue-router'
export default function useFormPageLeavePrompt(watchData: any, delay: number = 300) {
const isFormEdit = ref(false)
let watchTimer: number
let watchStop: WatchStopHandle
// 刷新提示
const handleBeforeunload = (e: any) => {
// 标准写法
e.preventDefault()
// Chrome
e.returnValue = ''
}
// 离开路由提示
onBeforeRouteLeave((to, from, next) => {
if (isFormEdit.value) {
Modal.destroyAll()
Modal.confirm({
title: '提示',
content: '确定离开吗?表单数据会丢失。',
class: 'leave-form-modal',
onOk: () => {
next(true)
},
onCancel: () => {
next(false)
},
})
} else {
next(true)
}
})
// 监听传入的表单数据
const watchFormData = () => {
watchTimer = setTimeout(() => {
watchStop = watch(
watchData,
(newVal, oldVal) => {
console.log('表单变了')
isFormEdit.value = true
window.addEventListener('beforeunload', handleBeforeunload)
},
{
deep: true,
},
)
}, delay)
}
// 清除监听(在提交完成的跳转前主动调用)
const resetFormPageLeavePrompt = () => {
clearTimeout(watchTimer)
watchStop?.()
isFormEdit.value = false
window.removeEventListener('beforeunload', handleBeforeunload)
}
onMounted(() => {
watchFormData()
})
onUnmounted(() => {
resetFormPageLeavePrompt()
})
return {
isFormEdit,
watchFormData,
resetFormPageLeavePrompt,
}
}
2.3 使用
import useFormPageLeavePrompt from '@/hooks/useFormPageLeavePrompt'
// 除非是特殊的场景一,否则不用传入 delay
const { isFormEdit, resetFormPageLeavePrompt } = useFormPageLeavePrompt([
() => state.addForm,
() => state.tableForm,
])
3 延迟加载组件
3.1 说明
作用:解决一次性循环渲染过多组件导致的页面白屏问题(一种性能优化手段)。
思路:利用 requestAnimationFrame(在每次重绘前执行)分批渲染。
3.2 实现
/*
* 延迟加载组件
*/
import { ref, onMounted } from 'vue';
export default function useDefer(maxFrameCount) {
const frameCount = ref(0);
onMounted(() => {
const refreshFrameCount = () => {
requestAnimationFrame(() => {
frameCount.value++;
if (frameCount.value < maxFrameCount) {
refreshFrameCount();
}
});
};
refreshFrameCount();
});
function defer(showFrameCount) {
return frameCount.value >= showFrameCount;
}
return {
defer,
};
}
3.3 使用
<div v-for="n in list">
<template v-if="defer(n)">
<HeavyComp />
</template>
</div>
const { defer } = useDefer(list.length);
最后
欢迎沟通交流,提出改进意见,文章会更新补充。