前言
網上有許多開源的可視化大屏項目,但是分析之后,還是想自己從 0 搭建一個可視化大屏項目,畢竟 Vue 一直在更新,自己搭建的可以使用最新版本的 Vue ,如果對版本沒有太多要求的小伙伴們選擇那些開源項目的基礎上去修改也是很不錯的。其次自己搭建一個項目,可以更好的了解具體的實現(xiàn)方式。當然這個項目中還是會引用一些組件庫。
創(chuàng)建 Vue3 + TypeScript + Vite 項目
這里就不過多去介紹了,創(chuàng)建項目大家都會,我這里就使用 WebStorm 去創(chuàng)建一個項目,node 我選用 18.6.0版本的

項目創(chuàng)建好之后,我們先來引入一個組件庫 DataV Vue3。這個組件庫是在 DataV 的基礎上重構的
引入 DataV Vue3
- 首先為什選擇 DataV Vue3 ,是因為 DataV 雖然有 Vue2,Vue3,React 各個版本的,但是 Vue3 版本的不支持 Vite
- 其次,為什么要使用 DataV Vue3 ,是因為這里為我們封裝好了一些酷炫的邊框、裝飾、圖表之類的組件,我們可以拿過來直接使用
- 安裝
npm install @kjgl77/datav-vue3
- 全局引入(也可以按需引入,考慮到每個頁面都可能會用到,所以這里直接在 main.ts 中全局引入)
// main.ts中全局引入
import { createApp } from 'vue'
import DataVVue3 from '@kjgl77/datav-vue3'
const app = createApp(App)
app.use(DataVVue3)
app.mount('#app')
接下來就該屏幕適配的問題了,雖然 DataV Vue3 中有全局容器 <dv-full-screen-container>,但是官方文檔中建議在全屏容器內使用百分比搭配 flex 進行布局,以便于在不同的分辨率下得到較為一致的展示效果。 并且使用前請注意將 body 的 margin 設為 0 ,否則會引起計算誤差,全屏后不能完全充滿屏幕。我還是傾向于直接使用 px 或者 vw、vh 布局,所以打算自己去進行屏幕的適配。
屏幕適配
屏幕適配大概有這幾種方式:rem、scale、vw 和 vh、以及 DataV Vue3 中的全局容器,這些方式都可以很好的去進行適配,具體選用哪種方法就看各人的喜好以及項目的需求了。個人比較推薦 scale 這種方式,所以這里就采用 scale 方式來進行屏幕適配
scale 方式
實現(xiàn)思路
scale 方式,大家都知道就是等比例縮放。一般情況下,我們的設計稿尺寸都是 1920*1080 (具體尺寸可以提前和 UI 溝通好),我們就以這個尺寸作為我們需要保持的默認的寬高比例,然后我們使用 window.innerWidth 、 window.innerHeight 獲取瀏覽器窗口內部的寬度和高度,之后根據(jù)瀏覽器窗口內部的寬高比和默認的寬高比來計算出需要縮放的比例就可以了。
代碼
我們對其進行封裝提取,在 utils 文件夾中新建一個 scalingRatio.ts 文件
import { ref } from 'vue'
export default function useDraw() {
// 指向最外層容器
const appRef = ref()
// 定時函數(shù)
const timer = ref(0)
// 默認縮放值
const scale = {
width: '1',
height: '1',
}
// 設計稿尺寸(px)
const baseWidth = 1920
const baseHeight = 1080
// 需保持的比例
const baseProportion = parseFloat((baseWidth / baseHeight).toFixed(5))
const calcRate = () => {
// 當前寬高比
const currentRate = parseFloat((window.innerWidth / window.innerHeight).toFixed(5))
if (appRef.value) {
if (currentRate > baseProportion) {
// 表示更寬
scale.width = ((window.innerHeight * baseProportion) / baseWidth).toFixed(5)
scale.height = (window.innerHeight / baseHeight).toFixed(5)
appRef.value.style.transform = `scale(${scale.width}, ${scale.height}) translate(-50%, -50%)`
} else {
// 表示更高
scale.height = ((window.innerWidth / baseProportion) / baseHeight).toFixed(5)
scale.width = (window.innerWidth / baseWidth).toFixed(5)
appRef.value.style.transform = `scale(${scale.width}, ${scale.height}) translate(-50%, -50%)`
}
}
}
const resize = () => {
clearTimeout(timer.value)
timer.value = setTimeout(() => {
calcRate()
}, 200)
}
// 改變窗口大小重新繪制
const windowDraw = () => {
window.addEventListener('resize', resize)
}
// 改變窗口大小重新繪制
const unWindowDraw = () => {
window.removeEventListener('resize', resize)
}
return {
appRef,
calcRate,
windowDraw,
unWindowDraw
}
}
接下來就是 CSS 部分以及使用封裝的方法來進行屏幕適配,這里需要把寬高改為你自己的設計稿的寬高
<!--app.vue-->
<script setup lang="ts">
import { RouterView } from 'vue-router'
</script>
<template>
<div class="app">
<RouterView />
</div>
</template>
<style lang="scss" scoped>
.app {
width: 100vw;
height: 100vh;
background-color: #000;
overflow: hidden;
}
</style>
<!--index.vue-->
<script lang="ts" setup>
import {
onMounted,
onUnmounted,
} from 'vue'
// 引入封裝好的方法
import useDraw from '@/utils/useDraw'
// 適配處理
const { appRef, calcRate, windowDraw, unWindowDraw } = useDraw()
// 生命周期
onMounted(() => {
windowDraw()
calcRate()
})
onUnmounted(() => {
unWindowDraw()
})
</script>
<div id="index" ref="appRef">
<!-- 頁面內容-->
</div>
<style>
#index{
color: #d3d6dd;
/*根據(jù)設計稿的寬高進行修改*/
width: 1920px;
height: 1080px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
transform-origin: left top;
}
</style>
圖表組件
安裝 eCharts
npm i echarts --save
全局引入以及掛載
// main.ts
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import DataVVue3 from '@kjgl77/datav-vue3'
// 引入全局樣式
import './assets/scss/style.scss';
// 引入 eCharts
import * as echarts from 'echarts'
const app = createApp(App)
/*
* 全局掛載 eCharts
* 這里需要注意的是,掛載之前不能連綴 use()和 mount(),也就是掛載要寫到 use() 之前
* */
app.config.globalProperties.$echarts = echarts
app.use(DataVVue3)
app.use(router)
app.mount('#app')
使用
因為 Vue3 是組合 API ,所以要引入對應的 getCurrentInstance 去使用掛載到全局的圖表組件
<script lang="ts" setup>
import {
onMounted,
ref,
getCurrentInstance
} from 'vue'
const { proxy }: any = getCurrentInstance()
const decorationColors = ['#568aea', '#000000']
const title = '可視化大屏項目示例'
const eacharts1 = ref(null)
const renderChart = () => {
var myChart = proxy.$echarts.init(eacharts1.value);
myChart.setOption({
title: [
{
text: '極坐標柱狀圖標簽'
}
],
polar: {
radius: [30, '80%']
},
radiusAxis: {
max: 4
},
angleAxis: {
type: 'category',
data: ['a', 'b', 'c', 'd'],
startAngle: 75
},
tooltip: {},
series: {
type: 'bar',
data: [2, 1.2, 2.4, 3.6],
coordinateSystem: 'polar',
label: {
show: true,
position: 'middle',
formatter: ': {c}'
}
},
animation: false
})
};
onMounted(() => {
renderChart()
})
</script>
<template>
<div class="eacharts1" ref="eacharts1" style="width: 500px;height: 500px;"></div>
</template>
到這里,所需的東西基本就都 OK 了,我們就可以開始我們的大屏項目布局以及后續(xù)開發(fā)了。這里的屏幕適配的實現(xiàn)方式參考了 vue-big-screen 的實現(xiàn)方式。如果不使用 vite ,也可以直接使用 vue-big-screen 提供的源碼進行刪減,然后開發(fā)使用。
此 Demo 已上傳至個人 GitHub ,需要的可自取。更多文章(由于只是 Demo ,所以在樣式方面并沒有過多的去調整)