新闻类网站html模板免费下载,开发一个网站需要多少人,网站的建立目的,宠物网站建设论文总结假设我们正在开发一个可视化拖拽的搭建平台#xff0c;可以拖拽生成工作台或可视化大屏#xff0c;或者直接就是开发一个大屏#xff0c;首先必须要考虑的一个问题就是页面如何适应屏幕#xff0c;因为我们在搭建或开发时一般都会基于一个固定的宽高#xff0c;但是实际的… 假设我们正在开发一个可视化拖拽的搭建平台可以拖拽生成工作台或可视化大屏或者直接就是开发一个大屏首先必须要考虑的一个问题就是页面如何适应屏幕因为我们在搭建或开发时一般都会基于一个固定的宽高但是实际的屏幕可能大小不一接下来我们就尝试几种简单且常见的方案并简单分析一下利弊。 demo
首先写个基础的demo给后续使用
script setup
import { ref } from vue;
import Widget from ./components/Widget.vue;
import LineChart from ./components/LineChart.vue;
import BarChart from ./components/BarChart.vue;
import PieChart from ./components/PieChart.vue;
import FunnelChart from ./components/FunnelChart.vue;// 画布宽高
const canvasWidth ref(1920);
const canvasHeight ref(1080);
// 组件宽高
const widgetWidth ref(960);
const widgetHeight ref(540);
/scripttemplatediv classcanvasBoxdivclasscanvas:style{ width: canvasWidth px, height: canvasHeight px }Widget :widthwidgetWidth :heightwidgetHeight :left0 :top0LineChart/LineChart/WidgetWidget :widthwidgetWidth :heightwidgetHeight :leftwidgetWidth :top0BarChart/BarChart/WidgetWidget :widthwidgetWidth :heightwidgetHeight :left0 :topwidgetHeightPieChart/PieChart/WidgetWidget :widthwidgetWidth :heightwidgetHeight :leftwidgetWidth :topwidgetHeightFunnelChart/FunnelChart/Widget/div/div
/templatestyle scoped
.canvasBox {width: 100vw;height: 100vh;
}
.canvas {position: relative;
}
/style 每个图表组件的宽高都设为100%然后都被Widget组件包裹所以实际宽高是依赖Widget组件的Widget组件为绝对定位并且宽高、位置通过props传入模拟我们的拖拽操作简单起见所有图表的宽高我们都设为了相同的。 Widget组件
script setup
const props defineProps({width: {type: Number,default: 0,},height: {type: Number,default: 0,},left: {type: Number,default: 0,},top: {type: Number,default: 0,},
});
/scripttemplatedivclasswidgetBox:style{width: width px,height: height px,left: left px,top: top px,}slot/slot/div
/templatestyle scoped
.widgetBox {position: absolute;
}
/style 组件整体的容器为类名为canvas的元素相对定位宽高也是动态设置的canvas元素的父级canvasBox元素宽高设为和屏幕宽高一致。 固定尺寸 即宽度、高度固定如果宽高小于屏幕宽高则在屏幕居中。 这个是最简单的方案了相当于不适配屏幕画布配置了多大实际就是多大不随屏幕的变化而变化所以各个组件的宽高也是在配置后不会改变一般用于尺寸固定且后期不会改变的可视化大屏。 我们前面的demo初始就是这种方式 当然如果宽高小于屏幕的话居中的逻辑需要加一下居中的方法有很多通过css、js都可根据自己的喜好来就行
// 画布的位置
const canvasLeft ref(0);
const canvasTop ref(0);
// 如果屏幕的宽或高比画布的大那么居中显示
let windowWidth window.innerWidth;
let windowHeight window.innerHeight;
if (windowWidth canvasWidth.value) {canvasLeft.value (windowWidth - canvasWidth.value) / 2;
}
if (windowHeight canvasHeight.value) {canvasTop.value (windowHeight - canvasHeight.value) / 2;
}divclasscanvas:style{width: canvasWidth px,height: canvasHeight px,left: canvasLeft px,top: canvasTop px,}
/div判断窗口宽度和高度是否大于画布的宽高是的话通过left或top来调整 自适应宽度
即宽度适应屏幕高度不变这种方案的缺点是垂直方向上会出现滚动条。
比如画布设置的宽度为1920但是实际上屏幕的宽度为1280那么缩小了1.5倍那么画布和每个组件的宽度也需要同步缩小1.5倍并且每个组件的left值也需要进行动态调整。
首先实现一下容器元素canvas的尺寸调整
// 保存原始画布的宽度
const originCanvasWidth ref(canvasWidth.value);
// 宽度缩放比例
const ratioWidth ref(1);// 当前窗口的宽度
let windowWidth window.innerWidth;
// 将画布宽度设置为当前窗口的宽度
canvasWidth.value windowWidth;
// 计算当前宽度和原始宽度的比例
ratioWidth.value windowWidth / originCanvasWidth.value;然后再把这个比例传给Widget组件进行调整
Widget :ratioWidthratioWidthLineChart/LineChart
/Widget
Widget :ratioWidthratioWidthBarChart/BarChart
/Widget
Widget :ratioWidthratioWidthPieChart/PieChart
/Widget
Widget :ratioWidthratioWidthFunnelChart/FunnelChart
/Widget
在Widget组件里我们只要把宽度和left都乘以这个比例即可为什么是乘很简单
newWidth / width ratioWidth windowWidth / originCanvasWidth
newWidth width * ratioWidth// left同样看做是一个距左侧的宽度即可divclasswidgetBox:style{width: width * ratioWidth px,height: height px,left: left * ratioWidth px,top: top px,}slot/slot
/div自适应屏幕
即宽高都自适应和上一种方案相比这种横竖都不会出现滚动条且能完全铺满屏幕。
实现也很简单在上一个【自适应宽度】的基础上加上高度自适应即可。
// 画布原始宽高
const originCanvasWidth ref(canvasWidth.value);
const originCanvasHeight ref(canvasHeight.value);
// 缩放比例
const ratioWidth ref(1);
const ratioHeight ref(1);// 当前窗口的宽高
let windowWidth window.innerWidth;
let windowHeight window.innerHeight;
// 将画布宽高设置为当前窗口的宽高
canvasWidth.value windowWidth;
canvasHeight.value windowHeight;
// 计算当前宽高和原始宽高的比例
ratioWidth.value windowWidth / originCanvasWidth.value;
ratioHeight.value windowHeight / originCanvasHeight.value;同样再把比例传给Widget组件进行调整
Widget :ratioWidthratioWidth :ratioHeightratioHeightLineChart/LineChart
/Widget
Widget :ratioWidthratioWidth :ratioHeightratioHeightBarChart/BarChart
/Widget
Widget :ratioWidthratioWidth :ratioHeightratioHeightPieChart/PieChart
/Widget
Widget :ratioWidthratioWidth :ratioHeightratioHeightFunnelChart/FunnelChart
/WidgetdivclasswidgetBox:style{width: width * ratioWidth px,height: height * ratioHeight px,left: left * ratioWidth px,top: top * ratioHeight px,}slot/slot
/div 整体等比例缩放
即通过css的transform属性来对组件容器canvas进行整体的缩放保持原比例在屏幕居中显示当然你可以选择只缩放宽度或高度但是这样会变形。
前面的两种方案我们的组件开发时都必须要考虑容器的宽高即需要进行适配但是宽高比太极限了说实话很难处理显示效果肯定是比较差的但是这种整体等比例适配就无需考虑这种情况。
实际项目中如果有大屏需要适应屏幕我一般都通过这种方法优点是简单缺点是水平或垂直空间上可能会留白但是背景是全屏的所以效果也不会很差。
实现也很简单计算一下画布原始比例再计算一下屏幕的比例然后再判断是宽度和屏幕一致高度自适应还是高度和屏幕一致宽度自适应
// 当前窗口宽高比例
let windowWidth window.innerWidth;
let windowHeight window.innerHeight;
let windowRatio windowWidth / windowHeight;
// 画布原始宽高比例
const canvasRatio canvasWidth.value / canvasHeight.value;
// 计算画布适应后的新宽高
let newCanvasWidth 0;
let newCanvasHeight 0;
if (canvasRatio windowRatio) {// 画布的宽高比大于屏幕的宽高比// 画布的宽度调整为屏幕的宽度newCanvasWidth windowWidth;// 画布的高度根据画布原比例进行缩放newCanvasHeight windowWidth / canvasRatio;
} else {// 画布的宽高比小于屏幕的宽高比// 画布的高度调整为屏幕的高度newCanvasHeight windowHeight;// 画布的宽度根据画布原比例进行缩放newCanvasWidth windowHeight * canvasRatio;
}
// ...假设屏幕的宽高相同那么比例为1。
第一种情况假设画布的宽是高的两倍那么比例为2要保持原比例2适应屏幕显然只能宽度和屏幕一致高度自适应因为如果高度和屏幕一致那么宽度需要是高度的两倍屏幕显然显示不下 第二种情况假设画布的高是宽的两倍那么比例为0.5要保持比例为0.5适应屏幕需要高度和屏幕一致宽度自适应 计算完了画布适应屏幕后的新宽高接下来就可以计算它相对于画布原始宽高的缩放比例
// ...
// 相对于画布原始宽高的缩放比例
const canvasStyle reactive({transform: ,
});
const scaleX newCanvasWidth / canvasWidth.value;
const scaleY newCanvasHeight / canvasHeight.value;
canvasStyle.transform scale(${scaleX}, ${scaleY})把样式添加到容器元素canvas上即可
divclasscanvas:style{width: canvasWidth px,height: canvasHeight px,...canvasStyle}
/div 显示的位置似乎有点问题这其实是因为默认情况下元素的变换都是以自身的中心点为原点进行变换的 我们只要改成以左上角为原点即可
const canvasStyle reactive({transform: ,transformOrigin: left top// 改成以左上角为变换原点
});最后再来让它居中
// 居中
const translateX (windowWidth - newCanvasWidth) / 2 / scaleX;
const translateY (windowHeight - newCanvasHeight) / 2 / scaleY;
canvasStyle.transform scale(${scaleX}, ${scaleY}) translate(${translateX}px, ${translateY}px);窗口的宽高减去画布适应后的新宽高即剩余的空间再除以2进行居中显示为什么还要除以缩放值呢因为translate的值也会随scale进行缩放比如translateX计算出来为100scaleX为0.5那么实际上最终的偏移量为100*0.550这显然不对所以我们除一个缩放值进行抵消。 这个方案似乎很完美那么还有没有问题呢显然是有的一个小问题是缩放后文字可能会模糊这个问题不大笔者遇到的另一个问题是如果使用了getBoundingClientRect方法获取元素信息本意是获取元素原始的尺寸数据但是缩放后返回的就是缩放后的数据那么可能会和我们的原始意图出现偏差比如有一个如下的div
div refel1 stylewidth: 200px; height: 200px; background: red; position: absolute; left: 50px; top: 50px;/div 我们想要动态根据这个div大小和位置复制一个div div refel2 stylebackground: green; position: absolute/divconst { width, height } el1.value.getBoundingClientRect();
const { left, top } window.getComputedStyle(el1.value);
el2.value.style.width ${width}px;
el2.value.style.height ${height}px;
el2.value.style.left left;
el2.value.style.top top;可以看到获取到的宽高比实际的小了一点这显然不是我们需要的解决方法是要么不要使用getBoundingClientRect方法使用offsetWdith等不会被缩放影响的方法或属性获取元素尺寸要么把获取到的数据除以缩放值。
当然可能还会存在其他一些属性或方法也会存在这个问题这就需要各位在实际的开发时进行测试了。
总结
本文简单总结了一下大屏适配的几种方法没有哪一种是最好的也没有哪一种是非常完美的没办法很多时候都是需要进行一定妥协的。
demo地址Vite Vue
demo仓库地址GitHub - skyWangZhenDong/palteform-fit-demo: 大屏的自适应