1、scale方案
优点:使用scale适配是最快且有效的(等比缩放)
缺点: 等比缩放时,项目的上下或者左右是肯定会有留白的
实现步骤
<div className="screen-wrapper">
<div className="screen" id="screen">
</div>
</div>
<script>
export default {
mounted() {
// 初始化自适应 ----在刚显示的时候就开始适配一次
handleScreenAuto();
// 绑定自适应函数 ---防止浏览器栏变化后不再适配
window.onresize = () => handleScreenAuto();
},
deleted() {
window.onresize = null;
},
methods: {
// 数据大屏自适应函数
handleScreenAuto() {
const designDraftWidth = 1920; //设计稿的宽度
const designDraftHeight = 960; //设计稿的高度
// 根据屏幕的变化适配的比例,取短的一边的比例
const scale =
(document.documentElement.clientWidth / document.documentElement.clientHeight) <
(designDraftWidth / designDraftHeight)
?
(document.documentElement.clientWidth / designDraftWidth)
:
(document.documentElement.clientHeight / designDraftHeight)
// 缩放比例
document.querySelector(
'#screen',
).style.transform = `scale(${scale}) translate(-50%, -50%)`;
}
}
}
</script>
/*
除了设计稿的宽高是根据您自己的设计稿决定以外,其他复制粘贴就完事
*/
.screen-root {
height: 100%;
width: 100%;
.screen {
display: inline-block;
width: 1920px; //设计稿的宽度
height: 960px; //设计稿的高度
transform-origin: 0 0;
position: absolute;
left: 50%;
top: 50%;
}
}
如果你不想分别写html,js和css,那么你也可以使用v-scale-screen
插件来帮你完成
使用插件参考:https://juejin.cn/post/7075253747567296548
2、使用dataV库,推荐使用
vue2版本:http://datav.jiaminghi.com/
vue3版本:https://datav-vue3.netlify.app/
<dv-full-screen-container>
content
</dv-full-screen-container>
优点:方便,没有留白,铺满可视区
3、手写dataV的container容器
嫌麻还是用dataV吧
文件结构
index.vue
<template>
<div id="imooc-screen-container" :ref="ref">
<template v-if="ready">
<slot></slot>
</template>
</div>
</template>
<script>
import autoResize from './autoResize.js'
export default {
name: 'DvFullScreenContainer',
mixins: [autoResize],
props: {
options: {
type: Object
}
},
data() {
return {
ref: 'full-screen-container',
allWidth: 0,
allHeight: 0,
scale: 0,
datavRoot: '',
ready: false
}
},
methods: {
afterAutoResizeMixinInit() {
this.initConfig()
this.setAppScale()
this.ready = true
},
initConfig() {
this.allWidth = this.width || this.originalWidth
this.allHeight = this.height || this.originalHeight
if (this.width && this.height) {
this.dom.style.width = `${this.width}px`
this.dom.style.height = `${this.height}px`
} else {
this.dom.style.width = `${this.originalWidth}px`
this.dom.style.height = `${this.originalHeight}px`
}
},
setAppScale() {
const currentWidth = document.body.clientWidth
const currentHeight = document.body.clientHeight
this.dom.style.transform = `scale(${currentWidth / this.allWidth}, ${currentHeight / this.allHeight})`
},
onResize() {
this.setAppScale()
}
}
}
</script>
<style lang="less">
#imooc-screen-container {
position: fixed;
top: 0;
left: 0;
overflow: hidden;
transform-origin: left top;
z-index: 999;
}
</style>
autoResize.js
import { debounce, observerDomResize } from './util'
export default {
data () {
return {
dom: '',
width: 0,
height: 0,
originalWidth: 0,
originalHeight: 0,
debounceInitWHFun: '',
domObserver: ''
}
},
methods: {
async autoResizeMixinInit () {
await this.initWH(false)
this.getDebounceInitWHFun()
this.bindDomResizeCallback()
if (typeof this.afterAutoResizeMixinInit === 'function') this.afterAutoResizeMixinInit()
},
initWH (resize = true) {
const { $nextTick, $refs, ref, onResize } = this
return new Promise(resolve => {
$nextTick(e => {
const dom = this.dom = $refs[ref]
if (this.options) {
const { width, height } = this.options
if (width && height) {
this.width = width
this.height = height
}
} else {
this.width = dom.clientWidth
this.height = dom.clientHeight
}
if (!this.originalWidth || !this.originalHeight) {
const { width, height } = screen
this.originalWidth = width
this.originalHeight = height
}
if (typeof onResize === 'function' && resize) onResize()
resolve()
})
})
},
getDebounceInitWHFun () {
this.debounceInitWHFun = debounce(100, this.initWH)
},
bindDomResizeCallback () {
this.domObserver = observerDomResize(this.dom, this.debounceInitWHFun)
window.addEventListener('resize', this.debounceInitWHFun)
},
unbindDomResizeCallback () {
this.domObserver.disconnect()
this.domObserver.takeRecords()
this.domObserver = null
window.removeEventListener('resize', this.debounceInitWHFun)
}
},
mounted () {
this.autoResizeMixinInit()
},
beforeDestroy () {
const { unbindDomResizeCallback } = this
unbindDomResizeCallback()
}
}
util/index.js
export function randomExtend (minNum, maxNum) {
if (arguments.length === 1) {
return parseInt(Math.random() * minNum + 1, 10)
} else {
return parseInt(Math.random() * (maxNum - minNum + 1) + minNum, 10)
}
}
export function debounce (delay, callback) {
let lastTime
return function () {
clearTimeout(lastTime)
const [that, args] = [this, arguments]
lastTime = setTimeout(() => {
callback.apply(that, args)
}, delay)
}
}
export function observerDomResize (dom, callback) {
const MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver
const observer = new MutationObserver(callback)
observer.observe(dom, { attributes: true, attributeFilter: ['style'], attributeOldValue: true })
return observer
}
export function getPointDistance (pointOne, pointTwo) {
const minusX = Math.abs(pointOne[0] - pointTwo[0])
const minusY = Math.abs(pointOne[1] - pointTwo[1])
return Math.sqrt(minusX * minusX + minusY * minusY)
}
// 看下面这个没有封装完善的
核心原理: 固定宽高比,采用缩放,一屏展示出所有的信息
<template>
<div class="datav_container" id="datav_container" :ref="refName">
<template v-if="ready">
<slot></slot>
</template>
</div>
</template>
<script>
import { ref, getCurrentInstance, onMounted, onUnmounted, nextTick } from 'vue'
import { debounce } from '../../utils/index.js'
export default {
// eslint-disable-next-line vue/multi-word-component-names
name: 'Container',
props: {
options: {
type: Object,
default: () => {}
}
},
setup(ctx) {
const refName = 'container'
const width = ref(0)
const height = ref(0)
const origialWidth = ref(0) // 视口区域
const origialHeight = ref(0)
const ready = ref(false)
let context, dom, observer
const init = () => {
return new Promise((resolve) => {
nextTick(() => {
// 获取dom
dom = context.$refs[refName]
console.log(dom)
console.log('dom', dom.clientWidth, dom.clientHeight)
// 获取大屏真实尺寸
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 (!origialWidth.value || !origialHeight.value) {
origialWidth.value = window.screen.width
origialHeight.value = window.screen.height
}
console.log(width.value, height.value, window.screen, origialWidth.value, origialHeight.value)
resolve()
})
})
}
const updateSize = () => {
if (width.value && height.value) {
dom.style.width = `${width.value}px`
dom.style.height = `${height.value}px`
} else {
dom.style.width = `${origialWidth.value}px`
dom.style.height = `${origialHeight.value}px`
}
}
const updateScale = () => {
// 计算压缩比
// 获取真实视口尺寸
const currentWidth = document.body.clientWidth // 视口实际显示区(浏览器页面实际显示的)
const currentHeight = document.body.clientHeight
console.log('浏览器页面实际显示', currentWidth, currentHeight)
// 获取大屏最终宽高
const realWidth = width.value || origialWidth.value
const realHeight = height.value || origialHeight.value
const widthScale = currentWidth / realWidth
const heightScale = currentHeight / realHeight
dom.style.transform = `scale(${widthScale}, ${heightScale})`
}
const onResize = async (e) => {
// console.log('resize', e)
await init()
await updateScale()
}
const initMutationObserver = () => {
const MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver
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 init()
updateSize()
updateScale()
window.addEventListener('resize', debounce(onResize, 100))
initMutationObserver()
ready.value = true
})
onUnmounted(() => {
window.removeEventListener('resize', debounce(onResize, 100))
removeMutationObserver()
})
return {
refName,
ready
}
}
}
</script>
<style lang="scss" scoped>
.datav_container {
position: fixed;
top: 0;
left: 0;
transform-origin: left top;
overflow: hidden;
z-index: 999;
}
</style>
在使用Container组件的时候,这样用
<Container :options="{ width: 3840, height: 2160 }">
<div class="test">111</div>
</Container>
传入你的大屏的分辨率options
// 获取大屏真实尺寸
// 获取dom
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 (!origialWidth.value || !origialHeight.value) {
origialWidth.value = window.screen.width
origialHeight.value = window.screen.height
}
// 定义更新size方法
const updateSize = () => {
if (width.value && height.value) {
dom.style.width = `${width.value}px`
dom.style.height = `${height.value}px`
} else {
dom.style.width = `${origialWidth.value}px`
dom.style.height = `${origialHeight.value}px`
}
}
// 设置压缩比
const updateScale = () => {
// 计算压缩比
// 获取真实视口尺寸
const currentWidth = document.body.clientWidth // 视口实际显示区(浏览器页面实际显示的)
const currentHeight = document.body.clientHeight
console.log('浏览器页面实际显示', currentWidth, currentHeight)
// 获取大屏最终宽高
const realWidth = width.value || origialWidth.value
const realHeight = height.value || origialHeight.value
const widthScale = currentWidth / realWidth
const heightScale = currentHeight / realHeight
dom.style.transform = `scale(${widthScale}, ${heightScale})`
}