响应式容器组件

对页面进行锁屏,始终保持一定的宽高比,常用于数据可视化开发中。

Container 组件

<template> <div id="container" :ref="refName"> <template v-if="ready"> <slot></slot> </template> </div> </template> <script> import { ref, getCurrentInstance, onMounted, onUnmounted, nextTick } from 'vue' import { debounce } from '../../shared/util.js' export default { name: 'Container', props: { options: Object }, setup(ctx) { const refName = 'container'; const width = ref(0); const height = ref(0); const originalWidth = ref(0); const originalHeight = ref(0); const ready = ref(false); let context, dom, observer; const initSize = () => { return new Promise((resolve, reject) => { nextTick(() => { dom = context.$refs[refName]; if (ctx.options && ctx.options.width && ctx.options.height) { width.value = ctx.options.width; height.value = ctx.options.height; } else { width.value = dom.clientWidth; height.value = dom.clientHeight; } if (!originalWidth.value || !originalHeight.value) { originalWidth.value = window.screen.width; originalHeight.value = window.screen.height; } resolve(); }) }); } const updateSize = () => { if (width.value && height.value) { dom.style.width = `${width.value}px`; dom.style.height = `${height.value}px`; } else { dom.style.width = `${originalWidth.value}px`; dom.style.height = `${originalHeight.value}px`; } } const updateScale = () => { const currentWidth = document.body.clientWidth; const currentHeight = document.body.clientHeight; const realWidth = width.value || originalWidth.value; const realHeight = height.value || originalHeight.value; const widthScale = currentWidth / realWidth; const heightScale = currentHeight / realHeight; dom.style.transform = `scale(${widthScale}, ${heightScale})`; } const onResize = async () => { await initSize(); updateScale(); } const initMutationObserver = () => { const MutationObserver = window.MutationObserver; observer = new MutationObserver(onResize); observer.observe(dom, { attributes: true, attributeFilter: ['style'], attributeOldValue: true }); } const removeMutationObserver = () => { if (observer) { observer.disconnect(); observer.takeRecords(); observer = null; } } onMounted(async () => { ready.value = false; context = getCurrentInstance().ctx; await initSize(); updateSize(); updateScale(); window.addEventListener('resize', onResize); initMutationObserver(); ready.value = true; }); onUnmounted(() => { window.removeEventListener('resize', debounce(0, onResize)); removeMutationObserver(); }); return { refName, ready } } } </script> <style lang="scss" scoped> #container { position: fixed; top: 0; left: 0; overflow: hidden; transform-origin: left top; z-index: 999; } </style>

测试用例

<template> <div class="home"> <Container :options="{ width: 3840, height: 2160 }"> <div class="test">123</div> </Container> </div> </template> <script> export default { name: 'Home' } </script> <style lang="scss" scoped> .test { font-size: 64px; color: red; } </style>