大屏适配解决方案

背景

公司最近需要在万吨线工厂的展示厅的巨屏上做可视化数据展示。其中一个技术点就是如何在大屏上做适配,譬如适配文字、图表、表格等,避免它们在大屏上展示错乱。

方案调研

rem方案

初步实现下来感觉还可以,但一旦还原设计稿后就会发现存在一些问题,譬如 element 图表的的行高等css样式都还是 px 单位,导致字体虽然自适应了,但文字上下之间重叠了。

css3 的 scale 缩放(推荐)

我们采用的就是这种方案,借助 CSS3 的 transform: scale 来动态的控制页面缩放比例。

具体思路

  1. 创建一个 layout 组件,用它来当所有需要缩放页面的根容器,通过控制此容器的 scale 来控制整体页面缩放比
  2. 计算出 宽度比(窗口可视区域宽度/设计稿宽度)和 长度比(窗口可视区域长度/设计稿长度),找出最小比例设置给 scale ,保证页面内容能全部展示出来
  3. 监听窗口的 resize 事件,动态的控制页面缩放

核心代码

layout 根容器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
<template>
<div class="shell" :style="style">
<!-- 页面以插件形式导入 -->
<slot />
</div>
</template>

<script>
export default {
name: 'shell',
// 放入设计稿长宽
props: {
width: {
type: String | Number,
default: '1920',
},
height: {
type: String | Number,
default: '1080'
}
},
data() {
return {
style: {
width: this.width + 'px',
height: this.height + 'px',
// 利用 left、top 50% + translate(-50%, -50%) 居中显示
// 利用计算 scale 比例放大缩小容器
// 最重要一点,transform-origin 要设置为 0 0,就是基于元素左上角变形
transform: 'scale(1) translate(-50%, -50%)'
}
}
},
mounted() {
this.setScale();
// 监听 窗口 resize ,设置 scale
window.onresize = this.$utils.debounce(this.setScale, 500, true);
},
methods: {
// 根据长度比和宽度比,找出min者设置scale,保证屏幕显示完全
getScale() {
const w = this.$utils.getViewportSize().width / this.width;
const h = this.$utils.getViewportSize().height / this.height;
return w < h ? w : h;
},
// 设置scale
setScale() {
this.style.transform = `scale(${this.getScale()}) translate(-50%, -50%)`;
console.log(this.style.transform);
}
}
}
</script>

<style scoped lang="scss">
.shell {
// 设置变形原点为左上角
transform-origin: 0 0;
position: absolute;
left: 50%;
top: 50%;
}
</style>

组件使用 Shell

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
<template>
<Shell :width="3840" :height="1080">
<div class="home">
<div class="nav">
<div class="title">华新水泥集团版图展示</div>
</div>
<div class="main">
<div id="myChart"></div>
</div>
</div>
</Shell>
</template>

<script>

export default {
name: 'Home',
data() {
return {
myChart: null
}
},
mounted() {
this.drawLine();
},
methods: {
drawLine(){
// 基于准备好的dom,初始化echarts实例
this.myChart = this.$echarts.init(document.getElementById('myChart'))
// 绘制图表
this.myChart.setOption({
title: { text: '在Vue中使用echarts' },
tooltip: {},
xAxis: {
data: ["衬衫","羊毛衫","雪纺衫","裤子","高跟鞋","袜子"]
},
yAxis: {},
series: [{
name: '销量',
type: 'bar',
data: [5, 20, 36, 10, 10, 20]
}]
});
}
}
}
</script>

<style scoped lang="scss">
.nav {
width: 3840px;
height: 153px;
background-color: #173C90;
display: flex;
justify-content: center;
align-items: center;
.title {
width: 613px;
font-size: 57px;
font-family: Microsoft YaHei;
font-weight: bold;
color: #FFFFFF;

background: linear-gradient(92deg, #0072FF 0%, #00EAFF 48.8525390625%, #01AAFF 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
}
#myChart {
width: 806px;
height: 312px;
}
</style>