前言
- 现在后端管理系统主页面基本都是由三部分组成
- 查询条件,高度不固定,可能有的页面查询条件多,有的少
- 表格,高度不固定,占据页面剩余高度
- 分页,高度固定
- 这三部分加起来肯定是占满全屏的,那么我们可以结合
flex
布局,来实现。
方法一:利用flex布局
代码及效果
app.vue
- 相当于页面首页
<template>
<div id="app">
<!-- 假设为页头内容,导航等...-->
<div class="routers">
<router-link :to="item.path" v-for="item in routerLinks" :key="item.name">{{ item.name }}</router-link>
</div>
<!-- 内容区域 -->
<div class="content">
<router-view />
</div>
</div>
</template>
<script>
export default {
data() {
return {
routerLinks: [],
};
},
created() {
this.handleRouterLink();
},
methods: {
handleRouterLink() {
// 获取所有路由配置
this.routerLinks = this.$router.getRoutes();
},
},
};
</script>
<style lang="scss" scoped>
#app {
height: 100vh;
display: flex;
flex-direction: column;
}
.routers {
display: flex;
justify-content: space-around;
}
/* 确定内容高度,好让业务组件的 height:100%生效 */
.content {
flex: 1;
}
</style>
test.vue
- 某业务表格组件
<!-- 表格高度自适应 -->
<template>
<div class="wrapper">
<!-- 查询条件 -->
<div class="searchView">
<div class="formItem" v-for="(item, index) in formNum" :key="index"></div>
</div>
<!-- 表格 -->
<div class="tableView" :key="tableKey">
<el-table :data="tableData" ref="myTable" style="width: 100%" :height="tableHeight">
<el-table-column prop="date" label="日期" width="180"> </el-table-column>
<el-table-column prop="name" label="姓名" width="180"> </el-table-column>
<el-table-column prop="address" label="地址"> </el-table-column>
</el-table>
</div>
<!-- 分页 -->
<div class="pageView">
<el-pagination
:pager-count="5"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page.sync="currentPage2"
:page-sizes="[100, 200, 300, 400]"
:page-size="100"
layout="sizes, prev, pager, next"
:total="1000"
>
</el-pagination>
</div>
</div>
</template>
<script>
export default {
data() {
return {
// 表格key,当表格height变化时,el-table无法重新渲染,只能刷新key,强制渲染表格组件
tableKey: 0,
// 当前页数
currentPage2: 1,
// 查询条件数量
formNum: 4,
// 表格高度
tableHeight: 500,
// 表格数据
tableData: [
{
date: '2016-05-02',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄',
},
{
date: '2016-05-04',
name: '王小虎',
address: '上海市普陀区金沙江路 1517 弄',
},
{
date: '2016-05-01',
name: '王小虎',
address: '上海市普陀区金沙江路 1519 弄',
},
{
date: '2016-05-03',
name: '王小虎',
address: '上海市普陀区金沙江路 1516 弄',
},
],
};
},
async mounted() {
this.handleTableHeight();
// 当浏览器大小修改时,同时动态修改表格高度
window.onresize = this.getDebounce(this.handleTableHeight, 500);
},
methods: {
// 处理表格高度修改事件
async handleTableHeight() {
this.tableHeight = 0;
await this.$nextTick();
const tableView = document.querySelector('.tableView');
this.tableHeight = tableView.clientHeight;
console.log('tableHeight', this.tableHeight);
this.tableKey++;
},
handleSizeChange(val) {
console.log(`每页 ${val} 条`);
},
handleCurrentChange(val) {
console.log(`当前页: ${val}`);
},
// 生成一个debounce函数,避免事件频繁除法
getDebounce(func, delay) {
let timer = null;
return function (...args) {
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(() => {
func.apply(this, args);
}, delay);
};
},
},
};
</script>
<style lang="scss" scoped>
/* 以下样式皆可写到全局文件中,每个页面布局基本一致 */
.wrapper {
display: flex;
flex-direction: column;
height: 100%;
.searchView {
display: flex;
flex-wrap: wrap;
gap: 10px 20px;
.formItem {
width: 230px;
height: 30px;
border: 1px solid #000;
}
}
.tableView {
flex: 1;
}
}
</style>
效果
思路
- 首先整个内容主页面
.wrapper
肯定是flex
,并且纵向布局,高度100%。- 其次,我们要分别在
查询条件、表格、分页
外层套一层div
,这样好进行样式管理。- 内容主页面肯定主要展示的是表格,那么我们就给表格外层的div
tableView
设置flex: 1;
,占据剩余所有高度- 当页面加载完成的时候,由于是
flex
布局,表格的高度(剩余高度)就是wrapper的高度100% - searchView的高度 - pageView的高度
。- 然后我们在
mounted
钩子函数中,获取.tableView
div的clientHeight
高度,这个值,就能作为表格的高度了。- 最后我们把这个高度值赋值给表格
el-table的height
属性,并且刷新key
,强制表格重新渲染以达到效果。- 最最后,我们给
window.onresize
绑定了事件,并且优化了使用防抖,当浏览器大小修改的时候,页面也会动态自适应高度。
方法二:父元素高度-所有子元素高度
- 要实现该方法,首先表格所在元素的父元素必须定高,固定
px
,或百分比都可(有效就行)
思路
- 首先表格要提取出来组件,这样获取表格本身元素直接使用
this.$el
(vue中)即可。- 使用
this.$el.parentElement
获取表格父元素- 然后再使用父元素中
children
属性,即可获取表格所有子元素的高度- 最后
表格高度 = 剩余空间高度 = 父元素高度-所有子元素高度
代码与效果
util.js
首先我们要先写一个工具函数,获取一个元素的
总高度 = 上下外边距+上下内边距+上下边框宽度+元素内容高度
export const getElementTotalHeight = (element) => {
// 获取元素样式
const style = window.getComputedStyle(element);
// 获取上下外边距,并转换成数字
const marginTop = parseInt(style.marginTop, 10) || 0;
const marginBottom = parseInt(style.marginBottom, 10) || 0;
// 计算总高度:元素自身高度 + 元素上下内边距+上下边框宽度 + 上下外边距
return element.offsetHeight + marginTop + marginBottom;
};
MyTable组件
- 在
mounted
钩子函数时要自动计算可用高度,并且赋值给tableHeight
属性,并且表格有上下10px
的外边距
<template>
<div class="my-table" :style="{ height: tableHeight + 'px' }">表格组件</div>
</template>
<script>
import { getElementTotalHeight } from "@/utils/util";
export default {
data() {
return {
tableHeight: 0,
};
},
mounted() {
this.calcHeight();
// 这里当屏幕比例发生变化时,自动调用
window.addEventListener("resize", this.calcHeight);
},
beforeDestroy() {
window.removeEventListener("resize", this.calcHeight);
},
methods: {
// 计算 组件可用高度
calcHeight() {
const parent = this.$el.parentElement;
// 父组件高度
const parentHeight = parent.clientHeight;
// 父组件其他元素总高度
const childrenHeights = Array.from(parent.children).reduce(
(acc, child) => {
// 排除掉组件本身
if (child == this.$el) {
return acc;
}
return acc + getElementTotalHeight(child);
},
0
);
// 本身的外边距
const style = window.getComputedStyle(this.$el);
const myMarginTop = parseInt(style.marginTop, 10) || 0;
const myMarginBottom = parseInt(style.marginBottom, 10) || 0;
this.tableHeight =
parentHeight - childrenHeights - myMarginTop - myMarginBottom;
},
},
};
</script>
<style lang="scss" scoped>
.my-table {
outline: 2px solid #000;
width: 100%;
margin: 10px 0;
background-color: cornflowerblue;
}
</style>
主页面组件
- 这里最外层使用了
flex
布局,重点是MyTable
组件的父组件content
使用了flex: 1;
来定高
<template>
<div class="test1">
<div class="header">页面header导航</div>
<div class="content">
<div class="search">查询条件内容</div>
<MyTable />
<div class="pagination">分页内容</div>
</div>
</div>
</template>
<script>
import MyTable from "@/components/MyTable.vue";
export default {
components: {
MyTable,
},
};
</script>
<style lang="scss" scoped>
.test1 {
height: 80vh;
width: 70vw;
border: 1px solid red;
display: flex;
flex-direction: column;
}
.header {
height: 10vh;
width: 100%;
background-color: darkgray;
}
.content {
flex: 1;
}
.search {
height: 10vh;
width: 100%;
background-color: aquamarine;
}
.pagination {
height: 7vh;
width: 100%;
background-color: bisque;
}
</style>