• vue+echarts项目十二:使用webSocket优化项目:合并图表到一个页面并添加 切换主题和切换全屏功能


    合并组件

    配置路由规则

    创建 Screen.vue 文件 ,
    完整的路由表如下  router/index.js
    1. import Vue from 'vue'
    2. import VueRouter from 'vue-router'
    3. const Seller = () => import('@/views/SellerPage')
    4. const Trend = () => import('@/views/TrendPage')
    5. const Map = () => import('@/views/MapPage')
    6. const Rank = () => import('@/views/RankPage')
    7. const Hot = () => import('@/views/HotPage')
    8. const Stock = () => import('@/views/StockPage')
    9. const Screen = () => import('../Screen')
    10. Vue.use(VueRouter)
    11. const routes = [
    12. {
    13. path: '/',
    14. redirect:'/screen'
    15. },
    16. {
    17. path:'/screen',
    18. component:Screen
    19. },
    20. {
    21. path:'/seller',
    22. component:Seller
    23. },
    24. {
    25. path:'/trend',
    26. component:Trend
    27. },
    28. {
    29. path: '/map',
    30. component:Map
    31. },
    32. {
    33. path: '/rank',
    34. component:Rank
    35. },
    36. {
    37. path: '/hot',
    38. component:Hot
    39. },
    40. {
    41. path: '/stock',
    42. component:Stock
    43. }
    44. ]
    45. const router = new VueRouter({
    46. routes
    47. })
    48. export default router

    准备相关的图片

    到public\static\img 下 各两张 配合明暗两种主图

    对页面进行分割百分比布局

    1. <style lang="less" scoped>
    2. .screen-body {
    3. width: 100%;
    4. height: 100%;
    5. display: flex;
    6. margin-top: 10px;
    7. .screen-left {
    8. height: 100%;
    9. width: 27.6%;
    10. #left-top {
    11. height: 53%;
    12. position: relative;
    13. }
    14. #left-bottom {
    15. height: 31%;
    16. margin-top: 25px;
    17. position: relative;
    18. }
    19. }
    20. .screen-middle {
    21. height: 100%;
    22. width: 41.5%;
    23. margin-left: 1.6%;
    24. margin-right: 1.6%;
    25. #middle-top {
    26. width: 100%;
    27. height: 56%;
    28. position: relative;
    29. }
    30. #middle-bottom {
    31. margin-top: 25px;
    32. width: 100%;
    33. height: 28%;
    34. position: relative;
    35. }
    36. }
    37. .screen-right {
    38. height: 100%;
    39. width: 27.6%;
    40. #right-top {
    41. height: 46%;
    42. position: relative;
    43. }
    44. #right-bottom {
    45. height: 38%;
    46. margin-top: 25px;
    47. position: relative;
    48. }
    49. }
    50. }
    51. style>

     全部的css:

    1. .fullscreen {
    2. position: fixed!important;
    3. top: 0 !important;
    4. left: 0 !important;
    5. width: 100% !important;
    6. height: 100% !important;
    7. margin: 0 !important;
    8. z-index: 100;
    9. }
    10. .screen-container {
    11. width: 100%;
    12. height: 100%;
    13. padding: 0 20px;
    14. background-color: #161522;
    15. color: #fff;
    16. box-sizing: border-box;
    17. }
    18. .screen-header {
    19. width: 100%;
    20. height: 64px;
    21. font-size: 20px;
    22. position: relative;
    23. padding-top: 20px;
    24. > div {
    25. img {
    26. width: 100%;
    27. }
    28. }
    29. .title {
    30. position: absolute;
    31. left: 50%;
    32. top: 50%;
    33. font-size: 20px;
    34. transform: translate(-50%, -50%);
    35. }
    36. .title-right {
    37. display: flex;
    38. align-items: center;
    39. position:absolute;
    40. right: 0px;
    41. top: 50%;
    42. transform: translateY(-80%);
    43. }
    44. .qiehuan {
    45. width: 28px;
    46. height: 21px;
    47. cursor: pointer;
    48. }
    49. .datetime {
    50. font-size: 15px;
    51. margin-left: 10px;
    52. }
    53. .logo {
    54. position: absolute;
    55. left: 0px;
    56. top: 50%;
    57. transform: translateY(-80%);
    58. img {
    59. height: 35px;
    60. width: 128px;
    61. }
    62. }
    63. }
    64. .screen-body { ... }
    65. .resize {
    66. position: absolute;
    67. right: 20px;
    68. top: 20px;
    69. cursor: pointer;
    70. }

    引入组件 和 注册组件 和一些数据的准备

    1. import Hot from '@/components/Hot.vue'
    2. import Map from '@/components/Map.vue'
    3. import Rank from '@/components/Rank.vue'
    4. import Seller from '@/components/Seller.vue'
    5. import Stock from '@/components/Stock.vue'
    6. import Trend from '@/components/Trend.vue'
    7. components: {
    8. Hot,
    9. Map,
    10. Rank,
    11. Seller,
    12. Stock,
    13. Trend
    14. },
    15. data(){
    16. return {
    17. // 定义每一个图表的全屏状态
    18. fullScreenStatus:{
    19. trend:false,
    20. seller:false,
    21. map:false,
    22. rank:false,
    23. hot:false,
    24. stock:false,
    25. },
    26. // 右上角显示事件的定时器
    27. time:'',
    28. timeID:null
    29. }
    30. },

    组件template布局

    1. <template>
    2. <div class="screen-container" :style="containerStyle">
    3. <header class="screen-header">
    4. <div>
    5. <img :src="herderBorderSrc" alt="">
    6. div>
    7. <span class="logo">
    8. <img :src="logoSrc" alt="" />
    9. span>
    10. <span class="title">中欣网校数据监控系统span>
    11. <div class="title-right">
    12. <img :src="themeSrc" class="qiehuan" @click="handleChangeTheme()">
    13. <span class="datetime">{{time}}span>
    14. div>
    15. header>
    16. <div class="screen-body">
    17. <section class="screen-left">
    18. <div id="left-top" :class="[fullScreenStatus.trend ? 'fullscreen' : '']">
    19. <Trend ref="trend">Trend>
    20. <div class="resize">
    21. <span @click="changeSize('trend')"
    22. :class="['iconfont', fullScreenStatus.trend ? 'icon-compress-alt' : 'icon-expand-alt']">span>
    23. div>
    24. div>
    25. <div id="left-bottom" :class="[fullScreenStatus.seller ? 'fullscreen' : '']">
    26. <Seller ref="seller">Seller>
    27. <div class="resize">
    28. <span @click="changeSize('seller')"
    29. :class="['iconfont', fullScreenStatus.seller ? 'icon-compress-alt' : 'icon-expand-alt']">span>
    30. div>
    31. div>
    32. section>
    33. <section class="screen-middle">
    34. <div id="middle-top" :class="[fullScreenStatus.map ? 'fullscreen' : '']">
    35. <Map ref="map">Map>
    36. <div class="resize">
    37. <span
    38. @click="changeSize('map')"
    39. :class="['iconfont',fullScreenStatus.map ? 'icon-compress-alt' : 'icon-expand-alt']">span>
    40. div>
    41. div>
    42. <div id="middle-bottom" :class="[fullScreenStatus.rank ? 'fullscreen' : '']">
    43. <Rank ref="rank">Rank>
    44. <div class="resize">
    45. <span
    46. @click="changeSize('rank')"
    47. :class="['iconfont',fullScreenStatus.rank ? 'icon-compress-alt' : 'icon-expand-alt']">span>
    48. div>
    49. div>
    50. section>
    51. <section class="screen-right">
    52. <div id="right-top" :class="[fullScreenStatus.hot ? 'fullscreen' : '']">
    53. <Hot ref="hot">Hot>
    54. <div class="resize">
    55. <span
    56. @click="changeSize('hot')"
    57. :class="['iconfont',fullScreenStatus.hot ? 'icon-compress-alt' : 'icon-expand-alt']">span>
    58. div>
    59. div>
    60. <div id="right-bottom" :class="[fullScreenStatus.stock ? 'fullscreen' : '']">
    61. <Stock ref="stock">Stock>
    62. <div class="resize">
    63. <span
    64. @click="changeSize('stock')"
    65. :class="['iconfont',fullScreenStatus.stock ? 'icon-compress-alt' : 'icon-expand-alt']">span>
    66. div>
    67. div>
    68. section>
    69. div>
    70. div>
    71. template>

     切换主题和各个图表全屏切换+显示当前事件的实现

    刚进入组件的时候注册事件+运行定时器

    1. created() {
    2. this.$socket.registerCallBack('fullScreen',this.recvData)
    3. this.$socket.registerCallBack('themeChange',this.recvThemeChange)
    4. this.dateFormat()
    5. },

    组件销毁时与进入组件操作相反

    1. destroyed() {
    2. this.$socket.unRegisterCallBack('fullScreen')
    3. this.$socket.unRegisterCallBack('themeChange')
    4. clearInterval(this.timerID)
    5. },

    点击时间旁边的图标触发 切换主题事件

    {{time}}
    handleChangeTheme(){
      this.$socket.send({
        action:'themeChange',
        socketType: 'themeChange',
        chartName: '',
        value:''
      })
    }

    上篇文章一个路数  handleChangeTheme 发起send 向服务器提交数据 =》action不是getData 服务器就原路返回数据 =》 前端再监听到服务器返回的数据调用进入页面时注册的函数 recvThemeChange =》而这个函数 调用的是Vuex 来改变当前的主题  

    因为各个组件注册的时候 都引入 vuex 的state来管理主题

    监听数据改变  进行重绘操作

    recvThemeChange(){
      // 修改Vuex中的数据
      this.$store.commit('changeTheme')
    },
    

    store/index.js:

    1. import Vue from 'vue'
    2. import Vuex from 'vuex'
    3. Vue.use(Vuex)
    4. export default new Vuex.Store({
    5. state: {
    6. theme:'chalk'
    7. },
    8. getters: {
    9. },
    10. mutations: {
    11. changeTheme(state){
    12. if (state.theme === 'chalk'){
    13. state.theme = 'vintage'
    14. }else {
    15. state.theme = 'chalk'
    16. }
    17. }
    18. },
    19. actions: {
    20. },
    21. modules: {
    22. }
    23. })

    每个组件的公用代码:映射出来 theme 图表初始化的时候 使用  监听theme  改变时进行重绘

    1. import {mapState} from "vuex";
    2. computed:{
    3. ...mapState(['theme'])
    4. },
    5. watch:{
    6. theme(){
    7. this.chartsInstance.dispose() //销毁当前的图表
    8. this.initChart() //重新以最新的主图渲染图表
    9. this.screenAdapter() // 完成屏幕的适配
    10. this.updateChart() // 更新图表的展示
    11. }
    12. },
    13. this.chartsInstance = this.$echarts.init(this.$refs.rank_1,this.theme)

    切换主题时 主页面一些属性也要跟随变化 logo变成反白、字体的颜色、.....

    theme_utils.js  

    1. const theme = {
    2. chalk:{
    3. // 背景颜色
    4. backgroundColor:'#161522',
    5. // 标题的文字颜色
    6. titleColor:'#ffffff',
    7. // 左上角logo的图表路径
    8. logoSrc:'logo_dark.png',
    9. // 切换主题按钮的图片路径
    10. themeSrc:'qiehuan_dark.png',
    11. // 页面顶部的边框图片
    12. herderBorderSrc:'header_border_dark.png'
    13. },
    14. vintage:{
    15. // 背景颜色
    16. backgroundColor:'#eee',
    17. // 标题的文字颜色
    18. titleColor:'#000000',
    19. // 左上角logo的图表路径
    20. logoSrc:'logo_light2.png',
    21. // 切换主题按钮的图片路径
    22. themeSrc:'qiehuan_light.png',
    23. // 页面顶部的边框图片
    24. herderBorderSrc:'header_border_light.png'
    25. }
    26. }
    27. export function getThemeValue(themeName) {
    28. return theme[themeName]
    29. }

    主页面的计算属性

    1. computed:{
    2. ...mapState(['theme']),
    3. logoSrc(){
    4. return '/static/img/' + getThemeValue(this.theme).logoSrc
    5. },
    6. herderBorderSrc(){
    7. return '/static/img/' + getThemeValue(this.theme).herderBorderSrc
    8. },
    9. themeSrc(){
    10. return '/static/img/' + getThemeValue(this.theme).themeSrc
    11. },
    12. containerStyle(){
    13. return{
    14. backgroundColor:getThemeValue(this.theme).backgroundColor,
    15. color:getThemeValue(this.theme).titleColor
    16. }
    17. },
    18. },

    实现每个图例的全屏切换效果:

    点击 span 触发changeSize  点击过后就是取反的 fullScreenStatus.具体图表的状态

    1. <div id="left-bottom" :class="[fullScreenStatus.seller ? 'fullscreen' : '']">
    2. <Seller ref="seller">Seller>
    3. <div class="resize">
    4. <span @click="changeSize('seller')"
    5. :class="['iconfont', fullScreenStatus.seller ? 'icon-compress-alt' : 'icon-expand-alt']">span>
    6. div>
    7. div>
    1. changeSize(chartsName){
    2. /**
    3. * 正常事件进行单客户端的全屏事件切换
    4. 取反点击的具体图表 全屏状态的布尔值
    5. this.fullScreenStatus[chartsName] = !this.fullScreenStatus[chartsName]
    6. 通过 ref 调用每一个图表 组件内内部 刷新分辨率的方法
    7. this.$nextTick(() =>{
    8. this.$refs[chartsName].screenAdapter()
    9. })
    10. **/
    11. // 通过webSocket 进行多端联动的效果
    12. const targetValue = !this.fullScreenStatus[chartsName]
    13. this.$socket.send({
    14. action:'fullScreen',
    15. socketType:'fullScreen',
    16. chartName:chartsName,
    17. value:targetValue
    18. })
    19. },

    走了一圈还是调用 最开始传出去的函数  recvData()

    1. // 接收到全屏数据之后的处理
    2. recvData(data){
    3. // 取出是哪一个图表需要进行切换
    4. const chartName = data.chartName
    5. // 取出 切换成什么状态
    6. const targetValue = data.value
    7. // 修改数据 根据模板内三元表达式 动态添加 具体图表的全屏事件
    8. this.fullScreenStatus[chartName] = targetValue
    9. // 在渲染完毕后重新刷新 具体图表的分辨率事件
    10. this.$nextTick(() =>{
    11. this.$refs[chartName].screenAdapter()
    12. })
    13. },

    上线地址

    visionhttp://www.wsg3096.com/vision/#/screen

     完结撒花!!!

  • 相关阅读:
    Transformer预测 | Python实现基于Transformer的股票价格预测(tensorflow)
    JavaScript基本概念
    Go语言聊天室demo
    分库分表用这个就够了
    DSPE-PEG-Hydrazide,DSPE-PEG-HZ,磷脂-聚乙二醇-酰肼MW:1000
    ELFK(filebeat)部署
    基于单片机的贪吃蛇游戏设计仿真
    【无标题】
    MATLAB - 不能使用PYTHON,缺少matplotlib模块的解决办法
    DigestUtils实现md5加密算法
  • 原文地址:https://blog.csdn.net/benlalagang/article/details/127108180