创新的营销型网站,外包软件开发,长春市网络公司,申请一个电子邮箱号1.引言
在做数字大屏时#xff0c;图表能跟着浏览器的尺寸自动变化#xff0c;本文采用Vue3前端框架#xff0c;采用TypeScript语言#xff0c;封装了一个大屏自适应组件#xff0c;将需要显示的图表放入组件的插槽中#xff0c;就能实现自适应屏幕大小的效果。
2.实际…1.引言
在做数字大屏时图表能跟着浏览器的尺寸自动变化本文采用Vue3前端框架采用TypeScript语言封装了一个大屏自适应组件将需要显示的图表放入组件的插槽中就能实现自适应屏幕大小的效果。
2.实际效果 3.组件代码
/** * ScaleScreen.vue * author: zgr * createTime: 2023/9/22 */templatediv classscreen-wrapper refscreenWrapper :stylewrapperStyleslot/slot/div
/templatescript langts setup
import { CSSProperties, PropType } from vue
import { useFullscreen } from vueuse/core
const { toggle } useFullscreen()defineOptions({ name: ScaleScreen })
interface IState {originalWidth: string | numberoriginalHeight: string | numberwidth?: string | numberheight?: string | numberobserver: null | MutationObserver
}
type IAutoScale | boolean| {x?: booleany?: boolean}const props defineProps({width: {type: [String, Number] as PropTypestring | number,default: 1920},height: {type: [String, Number] as PropTypestring | number,default: 1080},fullScreen: {type: Boolean as PropTypeboolean,default: false},autoScale: {type: [Object, Boolean] as PropTypeIAutoScale,default: true},delay: {type: Number as PropTypenumber,default: 500},boxStyle: {type: Object as PropTypeCSSProperties,default: () ({})},wrapperStyle: {type: Object as PropTypeCSSProperties,default: () ({})},bodyOverflowHidden: {type: Boolean as PropTypeboolean,default: true}
})const state reactiveIState({currentWidth: 0,currentHeight: 0,originalWidth: 0,originalHeight: 0,observer: null
})
//ref
const screenWrapper refHTMLElement()//全屏函数
const toggleFullscreen () {toggle()
}
//按键F11全屏退出全屏
const KeyDown (event: KeyboardEvent) {if (event.code F9) {toggleFullscreen()}
}const listenKeyDown () {window.addEventListener(keydown, KeyDown, true) //监听按键事件
}
const removeListenKeyDown () {window.removeEventListener(keydown, KeyDown, false) //监听按键事件
}let bodyOverflowHiddenStr: string
/*** 防抖函数* param {Function} fn* param {number} delay* returns {() void}*/
const debounce (fn: Function, delay: number) {let timer: NodeJS.Timeoutreturn function (...args: any[]): void {if (timer) {clearTimeout(timer)}timer setTimeout(() {typeof fn function fn.apply(null, args)clearTimeout(timer)},delay 0 ? delay : 100)}
}
const initBodyStyle () {if (props.bodyOverflowHidden) {bodyOverflowHiddenStr document.body.style.overflowdocument.body.style.overflow hidden}
}
const initSize () {return new Promise((resolve) {// console.log(初始化样式);nextTick(() {// region 获取大屏真实尺寸if (props.width props.height) {state.currentWidth props.widthstate.currentHeight props.height} else {state.currentWidth screenWrapper.value?.clientWidthstate.currentHeight screenWrapper.value?.clientHeight}// endregion// region 获取画布尺寸if (!state.originalHeight || !state.originalWidth) {state.originalWidth window.screen.widthstate.originalHeight window.screen.height}// endregionresolve()})})
}
const updateSize () {if (state.width state.height) {screenWrapper.value!.style.width ${state.width}pxscreenWrapper.value!.style.height ${state.height}px} else {screenWrapper.value!.style.width ${state.originalWidth}pxscreenWrapper.value!.style.height ${state.originalHeight}px}
}
const autoScale (scale: number) {if (!props.autoScale) returnconst domWidth screenWrapper.value!.clientWidthconst domHeight screenWrapper.value!.clientHeightconst currentWidth document.body.clientWidthconst currentHeight document.body.clientHeightscreenWrapper.value!.style.transform scale(${scale},${scale})let mx Math.max((currentWidth - domWidth * scale) / 2, 0)let my Math.max((currentHeight - domHeight * scale) / 2, 0)if (typeof props.autoScale object) {!props.autoScale.x (mx 0)!props.autoScale.y (my 0)}screenWrapper.value!.style.margin ${my}px ${mx}px
}
const updateScale () {// 获取真实视口尺寸const currentWidth document.body.clientWidthconst currentHeight document.body.clientHeight// 获取大屏最终的宽高const realWidth state.width || state.originalWidthconst realHeight state.height || state.originalHeight// 计算缩放比例const widthScale currentWidth / realWidthconst heightScale currentHeight / realHeight// 若要铺满全屏则按照各自比例缩放if (props.fullScreen) {screenWrapper.value!.style.transform scale(${widthScale},${heightScale})return false}// 按照宽高最小比例进行缩放const scale Math.min(widthScale, heightScale)autoScale(scale)
}const onResize debounce(async () {await initSize()updateSize()updateScale()
}, props.delay)const initMutationObserver () {const observer (state.observer new MutationObserver(() {onResize()}))observer.observe(screenWrapper.value!, {attributes: true,attributeFilter: [style],attributeOldValue: true})
}
//设置数字大屏背景颜色为黑色
const setBgColor () {document.getElementsByTagName(body)[0].setAttribute(style, background: black)
}onMounted(() {setBgColor()initBodyStyle()nextTick(async () {await initSize()updateSize()updateScale()window.addEventListener(resize, onResize)initMutationObserver()})listenKeyDown()
})onBeforeUnmount(() {window.removeEventListener(resize, onResize)removeListenKeyDown()state.observer?.disconnect()if (props.bodyOverflowHidden) {document.body.style.overflow bodyOverflowHiddenStr}
})
/scriptstyle scoped langscss
.screen-wrapper {transition-property: all;transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);transition-duration: 500ms;position: relative;overflow: hidden;z-index: 100;transform-origin: left top;
}
/style4.感谢
1.GitHub - Alfred-Skyblue/v-scale-screen: Vue large screen adaptive component vue大屏自适应组件
2.koi-screen-plus: vue3版本数据大屏模板
3.DataV - Vue3 | DataV - Vue3