前言:网页多宫格布局本来不是一件难实现的功能,是一个比较通用的需求。但是这里的多宫格布局的使用场景是 视频的监控画面布局,这对布局的有了一点要求;一般视频的纵横比在 16:9,所以需要设计一个满足不同分辨率下 16:9 的布局模型。
这里提供一种多个宫格(一宫格、四宫格、六宫格、九宫格、16宫格)的画面布局写法,添加上了不同分辨率下横纵比 16:9 适配,并添加全屏功能。
1、页面绘制(html+css)
由于是在实际项目中遇到的实际问题,所以这里的实例用 vue 的代码来写
1.1、html
<!-- 最外层盒子,宽高根据设计UI来 -->
<div class="page" id="preId">
<!-- 多宫格布局,宽高根据计算适配 -->
<div class="box" id="split-box">
<!-- 主盒子 -->
<div :class="[`box-group${type}`, 'box-com', 'clearfix']" >
<!-- 子元素 -->
<div
v-for="item in computedGroup"
class="item"
:class="{'item-main':item == '3-1'}"></div>
</div>
</div>
</div>
<!-- 切换按钮 -->
<div class="btn">
<el-button @click="change(1)">1宫格</el-button>
<el-button @click="change(2)">4宫格</el-button>
<el-button @click="change(3)">6宫格</el-button>
<el-button @click="change(4)">9宫格</el-button>
<el-button @click="change(5)">16宫格</el-button>
</div>
1.2 js
data() {
return {
type: 1,
group1: ["1-1"],
group2: ["2-1", "2-2", "2-3", "2-4"],
group3: ["3-1", "3-2", "3-3", "3-4", "3-5",'3-6'],
group4: ["4-1", "4-2", "4-3", "4-4", "4-5", "4-6", "4-7", "4-8", "4-9"],
group5: [
"5-1",
"5-2",
"5-3",
"5-4",
"5-5",
"5-6",
"5-7",
"5-8",
"5-9",
"5-10",
"5-11",
"5-12",
"5-13",
"5-14",
"5-15",
"5-16"
],
st:null,
};
},
computed: {
computedGroup(){
let key = 'group'+this.type
return this[key]
}
},
methods: {
change(type){
this.type = type
},
}
html + js 主要功能就是点击不同按钮时生成不同子元素,比较简单易懂
1.3、css 样式
- css样式这块的实现,始终觉得自己写的不是特别简洁。因为这里的宫格需要满足这几个要求:1、宫格之间不要有间隔;2、宫格的宽高不能写死,需要根据外层的宽高来适配,而外层的宽高也是响应式变化的;3、满足上面两点其实并不难,但是还要有一点,每个宫格的横纵比要满足 16:9
- 基于以上的要求,这里提供一种我写的方法,可做个参考,如果别的同学有更好的写法,可以一起交流。话不多说,直接贴代码。
<style lang="less">
html,
body {
width: 100%;
height: 100%;
padding: 0;
margin: 0;
}
* {
box-sizing: border-box;
}
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
/* text-align: center; */
color: #2c3e50;
/* margin-top: 60px; */
padding: 0;
margin: 0;
width: 100%;
height: 100%;
position: relative;
box-sizing: border-box;
}
.clearfix:after {
/*伪元素是行内元素 正常浏览器清除浮动方法*/
content: "";
display: block;
height: 0;
clear: both;
visibility: hidden;
}
.clearfix {
*zoom: 1;
/*ie6清除浮动的方式 *号只有IE6-IE7执行,其他浏览器不执行*/
}
.btn{
text-align: center;
margin: 50px auto 0;
}
// 外层盒子
.page{
width: 80%;
height: 500px;
border: 1px solid pink;
margin: 0 auto;
overflow: hidden;
}
.box {
margin: 0 auto;
aspect-ratio: auto 16 / 9;
}
.box-com {
width: 100%;
height: 100%;
overflow: hidden;
box-sizing: border-box;
.item {
float: left;
border: 1px solid #707070;
background: #000;
color: #fff;
font-size: 25px;
}
}
// 一宫格布局
.box-group1 {
.item {
width: 100%;
height: 100%;
}
}
// 四宫格布局
.box-group2 {
.item {
width: 50%;
height: 50%;
}
}
// 六宫格布局
.box-group3 {
background: #000;
.item-main {
float: left;
border: 1px solid #707070;
width: 66.66%!important;
height: calc(66.66% - 1px)!important;
border-bottom: none!important;
border-right: none!important;
}
.item {
width: 33.33%;
height: 33.33%;
}
}
// 九宫格布局
.box-group4 {
.item {
width: calc(100% / 3);
height: calc(100% / 3);
}
}
// 16宫格布局
.box-group5 {
.item {
width: 25%;
height: 25%;
}
}
</style>
- 代码比较已读,本质就是通过百分比来计算的
- 六宫格比较特殊,他长下面这个样子
按道理来说第一个子盒子宽高应该是 外层盒子的 2/3 。于是写成 66.66%,理论来说是没什么问题的,但是实际上这样处理,高度可能在不足 1px 的地方取整成多 1px,由于是浮动,就把下面元素挤掉了,这里 .box-group3 减掉的 1px 就是这么来的。因为减掉了 1px 于是底部边框索性去掉,看起来更舒服一些。
2、 16:9 页面响应式适配
前面说了这个多宫格布局是应用在视频监控的需求里面的,视频的宽高比一般是在16:9,为了最大的保持原视频布局,我们盒子也需要保持 16:9 。
具体思路是:
- 监听分辨率变化,获取 .page 宽高
- 如果 .page比较宽,就让 .box 高度撑满,宽度适配
- 如果 .page比较高,就让 .box 宽度撑满,高度适配
- 上面的比较宽(高)是相对于 16:9 来说的,比如 .pre 的 宽/高 > 16:9, 说明就是比较宽。
贴代码:
mounted() {
this.startResize()
},
beforeDestroy(){
// 销毁的时候移除
this.endResize()
},
methods: {
startResize(){
this.$nextTick(() => {
this.resizeTheBox()
})
window.addEventListener('resize',this.resizeFun)
},
endResize(){
this.st && clearTimeout(this.st)
window.removeEventListener('resize',this.resizeFun)
},
resizeFun(){
// 防抖,防止频繁改变
if(this.st){
clearTimeout(this.st)
this.st = null
}
this.st = setTimeout(()=>{
this.$nextTick(()=>{
this.resizeTheBox()
})
clearTimeout(this.st)
this.st = null
},100)
},
// 容器 16:9 适配
resizeTheBox(){
let dom = document.getElementById('preId')
let width = dom.clientWidth || dom.offsetWidth
let height = dom.clientHeight || dom.offsetHeight
let el = document.getElementById('split-box')
if(width*9 > height*16){
if(CSS.supports("aspect-ratio", "auto 16 / 9")){
el.style.width = 'auto'
}else{
el.style.width = height*16/9 + 'px'
}
// el.style.width = height*16/9 + 'px'
el.style.height = '100%'
}else{
if(CSS.supports("aspect-ratio", "auto 16 / 9")){
el.style.height = 'auto'
}else{
el.style.height = width*9/16 + 'px'
}
// el.style.height = width*9/16 + 'px'
el.style.width = '100%'
}
},
},
代码可读性是有的,这里就不赘述了。说一下 aspect-ratio,这个 css 属性的作用是元素宽高比。
3、全屏、退出全屏
都写到这儿了,最后分享一个让元素全屏和退出的方法,让监控画面充满整个电脑屏幕
<el-button @click="handleFull">全屏</el-button>
<el-button @click="exitFullScreen">退出全屏</el-button>
handleFull(){
this.fullScreen(document.getElementById('split-box'));
},
fullScreen(el) {
let rfs =
el.requestFullScreen ||
el.webkitRequestFullScreen ||
el.mozRequestFullScreen ||
el.msRequestFullScreen,
wscript;
if (typeof rfs != "undefined" && rfs) {
rfs.call(el);
return;
}
if (typeof window.ActiveXObject != "undefined") {
wscript = new ActiveXObject("WScript.Shell");
if (wscript) {
wscript.SendKeys("{F11}");
}
}
},
// 退出全屏
exitFullScreen() {
var el = document,
cfs =
el.cancelFullScreen ||
el.webkitCancelFullScreen ||
el.mozCancelFullScreen ||
el.exitFullScreen,
wscript;
if (typeof cfs != "undefined" && cfs) {
cfs.call(el);
return;
}
if (typeof window.ActiveXObject != "undefined") {
wscript = new ActiveXObject("WScript.Shell");
if (wscript != null) {
wscript.SendKeys("{F11}");
}
}
},
谢谢!