开发大屏主要是两方面的工作:
大屏之关键-前期的自适应适配
根据 ui 稿绘制图表,调细节
方案 | 实现方式 | 优点 | 缺点 |
vw vh | 1.按照设计稿的尺寸,将px 按比例计算转为vw 和vh |
1.可以动态计算图表的宽高,字体等,灵活性较高 2.当屏幕比例跟 ui 稿不一致时,不会出现两边留白情况 |
1.每个图表都需要单独做字体、间距、位移的适配,比较麻烦 |
按照设计稿的尺寸,将px
按比例计算转为vw
和vh
,转换公式如下
假设设计稿尺寸为 1920*1080(做之前一定问清楚 ui 设计稿的尺寸)
即:
网页宽度=1920px
网页高度=1080px
我们都知道
网页宽度=100vw
网页宽度=100vh
所以,在 1920px*1080px 的屏幕分辨率下
1920px = 100vw
1080px = 100vh
这样一来,以一个宽 300px 和 200px 的 div 来说,其所占的宽高,以 vw 和 vh 为单位,计算方式如下:
vwDiv = (300px / 1920px ) * 100vw
vhDiv = (200px / 1080px ) * 100vh
所以,就在 1920*1080 的屏幕分辨率下,计算出了单个 div 的宽高
当屏幕放大或者缩小时,div 还是以 vw 和 vh 作为宽高的,就会自动适应不同分辨率的屏幕
util.scss
// 使用 scss 的 math 函数,https://sass-lang.com/documentation/breaking-changes/slash-div
@use "sass:math";
// 默认设计稿的宽度
$designWidth: 1920;
// 默认设计稿的高度
$designHeight: 1080;
// px 转为 vw 的函数
@function vw($px) {
@return math.div($px, $designWidth) * 100vw;
}
// px 转为 vh 的函数
@function vh($px) {
@return math.div($px, $designHeight) * 100vh;
}
在 .vue 中使用
这种使用方式有个弊端,就是屏幕尺寸发生变化后,需要手动刷新一下才能完成自适应调整
为了解决这个问题,你需要在各个图表中监听页面尺寸变化,重新调整图表,在 vue 项目中,最好封装个 resize 的指令,在各图表中就只要使用该指令就可以了。
// 在directives目录下创建resizeObserver.js文件
// 监听元素大小变化的指令
const map = new WeakMap()
const ob = new ResizeObserver((entries) => {
for (const entry of entries) {
// 获取dom元素的回调
const handler = map.get(entry.target)
//存在回调函数
if (handler) {
// 将监听的值给回调函数
handler({
width: entry.borderBoxSize[0].inlineSize,
height: entry.borderBoxSize[0].blockSize
})
}
}
})
export const Resize = {
mounted(el, binding) {
//将dom与回调的关系塞入map
map.set(el, binding.value)
//监听el元素的变化
ob.observe(el)
},
unmounted(el) {
//取消监听
ob.unobserve(el)
}
}
export default Resize
import Resize from "./resizeObserver"; // 监听dom宽高变化
const directivesList = {
Resize
};
const directives = {
install: function (app) {
Object.keys(directivesList).forEach((key) => {
app.directive(key, directivesList[key]); // 注册
});
}
};
export default directives;// 抛出
在vue中使用
echarts 的字体大小只支持具体数值(像素),不能用百分比或者 vw 等尺寸,一般字体不会去做自适应,当宽高比跟 ui 稿比例出入太大时,会出现文字跟图表重叠的情况
这里我们就需要封装一个工具函数,来处理图表中文字自适应了
默认情况下,这里以你的设计稿是 1920*1080 为例,即网页宽度是 1920px (做之前一定问清楚 ui 设计稿的尺寸)
把这个函数写在一个单独的工具文件dataUtil.js
里面,在需要的时候调用
其原理是计算出当前屏幕宽度和默认设计宽度的比值,将原始的尺寸乘以该值
另外,其它 echarts 的配置项,比如间距、定位、边距也可以用该函数
// Echarts图表字体、间距自适应
export const fitChartSize = (size,defalteWidth = 1920) => {
let clientWidth = window.innerWidth||document.documentElement.clientWidth||document.body.clientWidth;
if (!clientWidth) return size;
let scale = (clientWidth / defalteWidth);
return Number((size*scale).toFixed(3));
}
import { fitChartSize } from '@/assets/js/utils.js'
// 饼状图
let myPieChart = {}
let options = {}
const pieInit = ()=>{
// 基于准备好的dom,初始化echarts实例
myPieChart = echarts.init(document.getElementById('pie-content'));
options = {
// backgroundColor: 'rgb(43, 51, 59)',
toolbox: {
show: true,
feature: {
mark: {
show: true
},
dataView: {
show: true,
readOnly: false
},
magicType: {
show: true,
type: ['pie', 'funnel']
},
restore: {
show: true
},
saveAsImage: {
show: true
}
}
},
calculable: true,
"tooltip": {
"trigger": "item",
"formatter": "{a}
{b}:{c}千万元"
},
"title": {
"text": "南丁格尔玫瑰图--PieHalfRose",
"left": "center",
"top": fitChartSize(20),
"textStyle": {
"color": "#ccc",
"fontSize": fitChartSize(18)
}
},
"calculable": true,
"legend": {
"icon": "circle",
"x": "center",
"y": "15%",
"data": [
"义乌市1",
"义乌市2",
"义乌市3",
"义乌市4",
"义乌市5",
"义乌市6",
"义乌市7",
"义乌市8",
"义乌市9"
],
"textStyle": {
"color": "#fff",
"fontSize": fitChartSize(12)
}
},
"series": [{
"name": "XX线索",
"type": "pie",
"radius": [
fitChartSize(30),
fitChartSize(70)
],
"avoidLabelOverlap": false,
"startAngle": 0,
"center": [
"50%",
"60%"
],
"roseType": "area",
"selectedMode": "single",
"label": {
"normal": {
"show": true,
"formatter": "{c}千万元",
"color": '#fff',
fontSize: fitChartSize(12)
},
"emphasis": {
"show": true
}
},
"labelLine": {
"normal": {
"show": true,
"smooth": false,
"length": fitChartSize(20),
"length2": fitChartSize(10)
},
"emphasis": {
"show": true
}
},
"data": [{
"value": 600.58,
"name": "义乌市1",
"itemStyle": {
"normal": {
"color": "#f845f1"
}
}
},
{
"value": 1100.58,
"name": "义乌市2",
"itemStyle": {
"normal": {
"color": "#ad46f3"
}
}
},
{
"value": 1200.58,
"name": "义乌市3",
"itemStyle": {
"normal": {
"color": "#5045f6"
}
}
},
{
"value": 1300.58,
"name": "义乌市4",
"itemStyle": {
"normal": {
"color": "#4777f5"
}
}
},
{
"value": 1400.58,
"name": "义乌市5",
"itemStyle": {
"normal": {
"color": "#44aff0"
}
}
},
{
"value": 1500.58,
"name": "义乌市6",
"itemStyle": {
"normal": {
"color": "#45dbf7"
}
}
},
{
"value": 1500.58,
"name": "义乌市7",
"itemStyle": {
"normal": {
"color": "#f6d54a"
}
}
},
{
"value": 1600.58,
"name": "义乌市8",
"itemStyle": {
"normal": {
"color": "#f69846"
}
}
},
{
"value": 1800,
"name": "义乌市9",
"itemStyle": {
"normal": {
"color": "#ff4343"
}
}
},
{
"value": 0,
"name": "",
"itemStyle": {
"normal": {
"label": {
"show": false
},
"labelLine": {
"show": false
}
}
}
},
{
"value": 0,
"name": "",
"itemStyle": {
"normal": {
"label": {
"show": false
},
"labelLine": {
"show": false
}
}
}
},
{
"value": 0,
"name": "",
"itemStyle": {
"normal": {
"label": {
"show": false
},
"labelLine": {
"show": false
}
}
}
},
{
"value": 0,
"name": "",
"itemStyle": {
"normal": {
"label": {
"show": false
},
"labelLine": {
"show": false
}
}
}
},
{
"value": 0,
"name": "",
"itemStyle": {
"normal": {
"label": {
"show": false
},
"labelLine": {
"show": false
}
}
}
},
{
"value": 0,
"name": "",
"itemStyle": {
"normal": {
"label": {
"show": false
},
"labelLine": {
"show": false
}
}
}
},
{
"value": 0,
"name": "",
"itemStyle": {
"normal": {
"label": {
"show": false
},
"labelLine": {
"show": false
}
}
}
},
{
"value": 0,
"name": "",
"itemStyle": {
"normal": {
"label": {
"show": false
},
"labelLine": {
"show": false
}
}
}
},
{
"value": 0,
"name": "",
"itemStyle": {
"normal": {
"label": {
"show": false
},
"labelLine": {
"show": false
}
}
}
}
]
}]
}
// 绘制图表
myPieChart.setOption(options);
}