Vue3 + Vite + TypeScript + dataV 打造可视化大屏

前言

网上有许多开源的可视化大屏项目,但是分析之后,还是想自己从 0 搭建一个可视化大屏项目,毕竟 Vue 一直在更新,自己搭建的可以使用最新版本的 Vue ,如果对版本没有太多要求的小伙伴们选择那些开源项目的基础上去修改也是很不错的。其次自己搭建一个项目,可以更好的了解具体的实现方式。当然这个项目中还是会引用一些组件库。

创建 Vue3 + TypeScript + Vite 项目

这里就不过多去介绍了,创建项目大家都会,我这里就使用 WebStorm 去创建一个项目,node 我选用 18.6.0版本的


Vue3 创建新项目

项目创建好之后,我们先来引入一个组件库 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 方式

实现思路

scale 方式,大家都知道就是等比例缩放。一般情况下,我们的设计稿尺寸都是 1920*1080 (具体尺寸可以提前和 UI 沟通好),我们就以这个尺寸作为我们需要保持的默认的宽高比例,然后我们使用 window.innerWidth 、 window.innerHeight 获取浏览器窗口内部的宽度和高度,之后根据浏览器窗口内部的宽高比和默认的宽高比来计算出需要缩放的比例就可以了。

代码

我们对其进行封装提取,在 utils 文件夹中新建一个 scalingRatio.ts 文件

import { ref } from 'vue'

export default function useDraw() {
  // 指向最外层容器
  const appRef = ref()
  // 定时函数
  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;
  /*根据设计稿的宽高进行修改*/
  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: '{b}: {c}'
      }
    },
    animation: false
  })
};
onMounted(() => {
  renderChart()
})
</script>
<template>
  <div class="eacharts1" ref="eacharts1" style="width: 500px;height: 500px;"></div>
</template>

到这里,所需的东西基本就都 OK 了,我们就可以开始我们的大屏项目布局以及后续开发了。这里的屏幕适配的实现方式参考了 vue-big-screen 的实现方式。如果不使用 vite ,也可以直接使用 vue-big-screen 提供的源码进行删减,然后开发使用。
此 Demo 已上传至个人 GitHub ,需要的可自取。更多文章(由于只是 Demo ,所以在样式方面并没有过多的去调整)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,948评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,371评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,490评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,521评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,627评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,842评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,997评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,741评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,203评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,534评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,673评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,339评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,955评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,770评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,000评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,394评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,562评论 2 349

推荐阅读更多精彩内容