(下)Vue+Echarts構建大數據可視化酷屏展示公司品牌實戰項目分享(附源碼)

回顧

作者用心寫作,請動動你可愛的小手點亮大拇指。你的鼓勵是作者繼續創作的動力…

前端的學習,不能僅僅依靠知識點的學習,實戰項目的操作可以幫助我們整理知識點以及提高編程能力,更有助於學習和實踐,最重要的是提高自己的項目經驗,對於找工作而言有着大大的幫助。

閱讀本篇文章之前,可以先看看上一篇分享的內容,主要講大數據可視化的由來,與前端的淵源,主題風格設計,選擇比較流行的可視化第三方庫。

一個基於Vue前端框架和第三方圖表庫Echarts構建的可視化大數據平臺,通過vue項目構建、指令的靈活運用、組件封裝、組件之間通信,使內部圖表組件庫可實現自由替換和組合。以及一些功能模塊的設計及代碼實現。

老規矩先上效果圖(可視化酷屏展示公司品牌),後面會講這個實例。

在這裏插入圖片描述
線上體驗:https://jackchen0120.github.io/vueDataV/#/brand

下面接着繼續分享上一篇未講完的內容。

自定義全局模態框

先看效果圖:
在這裏插入圖片描述
自定義模態框已註冊全局小組件在/components/modal目錄文件,代碼如下(含註解):

<template>
  <transition name="fade">
    <div class="modal-backdrop" v-if="visible">
      <div class="modal">
        <div class="modal-header">
          {{ title }}
          <i class="iconfont icon-close close" @click="close"></i>
        </div>
        <div class="modal-body">
            {{ content }}
        </div>
        <div class="modal-footer">
          <button type="button" class="btn-close" @click="close" v-if="showCancle">
            {{cancleText ? cancleText : '取消'}}
          </button>
          <button type="button" class="btn-confirm" @click="confirm">
            {{confirmText ? confirmText : '確定'}}
          </button>
        </div>
      </div>
    </div>
  </transition>
</template>
 
<script>

export default {
  name: 'Modal',
  props: {
    // modal標題
    title: {
      type: String,
      default: '提示'
    },
    // modal內容
    content: {
      type: String,
      default: ''
    },
    // 是否顯示
    visible: {
      type: Boolean,
      default: false
    },
    // 是否顯示取消按鈕
    showCancle: {
      type: Boolean,
      default: true
    },
    // 確認按鈕文字
    confirmText: {
      type: String,
      default: '確認'
    },
    // 取消按鈕文字
    cancleText: {
      type: String,
      default: '取消'
    }
  },
  watch: {
    visible (curVal) {
      // 監聽visible值的變化	
      console.log(curVal)
    }
  },
  methods: { 
    // 關閉按鈕事件
    close() {
      this.$emit('update:visible', false);
    },
    // 確定按鈕事件
    confirm() {
      this.close();
      this.$emit('confirm');
    }   
  }
}
</script>

在components/index.js目錄文件中註冊全局組件,如下圖:
在這裏插入圖片描述
完整代碼如下:

// 引入自定義全局模態框組件
import modal from './modal' 

const components = {
  modal,
};

// install 是默認的方法。當外界在 Vue.use() 這個組件的時候,就會調用本身的 install 方法,同時傳一個 Vue 這個類的參數。
const install = (Vue = {}) => {
  if (install.installed) return;
  Object.keys(components).forEach(component => {
    Vue.component(components[component].name, components[component]);
  });

  install.installed = true;
};

install.installed = false;

if (typeof window !== "undefined" && window.Vue) {
  install(window.Vue);
  install.installed = true;
}

// 定義組件庫和install對象
const Vcomp = {
  ...components,
  install
};

// 導出
export default Vcomp

在main.js中全局引用,如下圖:
在這裏插入圖片描述
可在任意頁面調用,代碼如下:

<template>
	<div class="page">
	  <modal 
      	title="提示" 
      	:content="modalContent"
      	:visible.sync="visible" 
      	@confirm="confirm">
      </modal>
	</div>
</template>

export default {
	data() {
		return {
			visible: true, // 顯示模態框
      		modalContent: '這是一段自定義模態框消息'
		}
	},
	methods: {
		confirm() {
			this.visible = false;
      		console.log('點擊確定')
		}
	}
}
參數名 類型 說明
visible Boolean 是否顯示,默認false
title String 標題
content String 內容
confirmText String 確認按鈕文字,默認“確認”
cancleText String 取消按鈕文字,默認“取消”
showCancle Boolean 是否顯示,默認true
update:visible Boolean 更新visible, 使用:visible.sync實現動態綁定

數字滾動組件

推薦一款簡單好用的數字滾動組件,vue-count-to是一個無依賴,輕量級的vue組件,可以自行覆蓋easingFn。你可以設置 startVal 和 endVal,它會自動判斷計數或倒計時。支持vue-ssr,vue-countTo參考於countUp.js。

  • npm安裝依賴
npm install -D vue-count-to
  • 示例代碼:
<template>
  <countTo :startVal='startVal' :endVal='endVal' :duration='3000'></countTo>
</template>

<script>
  import countTo from 'vue-count-to';
  export default {
    components: { countTo },
    data () {
      return {
        startVal: 0,
        endVal: 2020
      }
    }
  }
</script>
  • 選項:
屬性 描述 數據類型 默認值
startVal 開始值 Number 0
endVal 結束值 Number 2020
duration 持續時間,以毫秒爲單位 Number 3000
autoplay 自動播放 Boolean true
decimals 要顯示的小數位數 Number 0
decimal 十進制分割 String .(點)
separator 分隔符 String ,(逗號)
prefix 前綴 String ‘’(空字符串)
suffix 後綴 String ‘’(空字符串)
useEasing 使用緩和功能 Boolean true
easingFn 緩和回調 Function

*注意:當autoplay:true時,它將在startVal或endVal更改時自動啓動

  • 功能:
函數名 描述
mountedCallback 掛載以後返回回調
start 開始計數
pause 暫停計數
reset 重置countTo

首頁動態列表組件顯示的數據,就引用了數字滾動特效,如下圖:
在這裏插入圖片描述
代碼如下圖:
在這裏插入圖片描述
如需查看完整源代碼請移步到作者的github倉庫

講講炫酷展示公司品牌實例

功能模塊
  • 天氣和當前日期
  • 自定義詞雲圖
  • 模擬飛機航線動效
  • 自動切換tab選項卡
  • 柱狀圖、餅圖、折線圖、南丁格玫瑰圖
技術棧
  • 基於 flexible.js + rem 智能大屏適配

之前首頁大屏佈局採用的是絕對定位,加上整體屏幕縮放進行適配(簡單粗暴,不是很優雅)。
現在推薦一種智能大屏適配方式,選用flexible.js是淘寶移動端自適應解決方案,源碼含註解如下:

// 首先是一個立即執行函數,執行時傳入的參數是window和document
(function flexible(window, document) {
  // 返回文檔的root元素
  var docEl = document.documentElement; 
  // 獲取設備的dpr,即當前設置下物理像素與虛擬像素的比值
  var dpr = window.devicePixelRatio || 1; 

  // 設置默認字體大小,默認的字體大小繼承自body
  function setBodyFontSize() {
    if (document.body) {
      // 調整body標籤的fontSize,fontSize = (12 * dpr) + 'px'
      document.body.style.fontSize = 12 * dpr + 'px';
    } else {
      document.addEventListener('DOMContentLoaded', setBodyFontSize);
    }
  }
  setBodyFontSize();

  // set 1rem = viewWidth / 24
  function setRemUnit() {
    // 設置root元素的fontSize = 其clientWidth / 24 + 'px'
    var rem = docEl.clientWidth / 24;
    docEl.style.fontSize = rem + 'px';
  }
  setRemUnit();

  // 當頁面展示或重新設置大小的時候,觸發重新
  window.addEventListener('resize', setRemUnit);
  window.addEventListener('pageshow', function(e) {
    if (e.persisted) {
      setRemUnit();
    }
  });

  // 檢測0.5px的支持,支持則root元素的class中有hairlines
  if (dpr >= 2) {
    var fakeBody = document.createElement('body');
    var testElement = document.createElement('div');
    testElement.style.border = '.5px solid transparent';
    fakeBody.appendChild(testElement);
    docEl.appendChild(fakeBody);
    if (testElement.offsetHeight === 1) {
      docEl.classList.add('hairlines');
    }
    docEl.removeChild(fakeBody);
  }
})(window, document);

設計稿尺寸是1920px*1080px,所以將屏幕分成24等份。

  • sublime text 3 cssrem插件
// 先下載插件到本地
git clone https://github.com/flashlizi/cssrem

進入packages目錄:Sublime Text -> Preferences -> Browse Packages… 如下圖:
在這裏插入圖片描述
將下載到本地的cssrem目錄複製到packges目錄裏,如下圖:
在這裏插入圖片描述
然後重啓Sublime Text,參數配置如下圖:
在這裏插入圖片描述
在這裏插入圖片描述
如果小夥伴使用的vscode編輯器,也可以安裝此插件,打開擴展,搜索cssrem,點擊安裝,如下圖:
在這裏插入圖片描述
配置設置,如下圖:
在這裏插入圖片描述
在這裏插入圖片描述
改完後重啓,插件效果如圖:
在這裏插入圖片描述

  • Flex 佈局

Flex是Flexible Box的縮寫,意爲”彈性佈局”,用來爲盒狀模型提供最大的靈活性。可以簡便、完整、響應式地實現各種頁面佈局。這裏推薦阮一峯老師的Flex佈局教程

動手之前,先來分析一下整個頁面設計佈局,整體佈局分爲上(頭部模塊)和下(主體模塊),主體模塊又分爲左中右三部分。主體中間又分爲上(數字滾動模塊)和下(地圖模塊)。

頭部佈局樣式採用的是定位position,主體模塊column列容器,分三列,佔比 3 : 5 : 3。主體代碼如下:

<section class="mainbox">
  <div class="item left">
    flex: 3;
  </div>

  <div class="item center">
    flex: 5;
  </div>

  <div class="item right">
    flex: 3;
  </div>
</section>
.mainbox {
  min-width: 1024px;
  max-width: 1920px;
  padding: 0.125rem 0.125rem 0;
  display: flex;
  .item {
    flex: 3;
    &.center {
      flex: 5;
      margin: 0 0.125rem 0.1rem;
      overflow: hidden;
    }
  }
}

全屏設置背景圖及頭部佈局樣式,可以直接在/src/views/Brand.vue目錄文件查看源代碼。

補充說明頭部有展示天氣和當前時間,天氣數據實時展示,通過axios的get方法調用第三方免費天氣API接口,並且設置每小時獲取一次最新數據。代碼實現如下:

mounted() {
  this.getWeather();
  this.timer = setInterval(() => {
  	this.getWeather();
  }, 1000 * 60 * 60)		
},
methods: {
  getWeather() { // 第三方天氣api接口
    axios.get('https://www.tianqiapi.com/api/', {
      params: {
        appid: '26148275',
        appsecret: '2id6H48Y',
        version: 'v6'
      }
    }).then(res => {
      if (res.data) {
        if (res.data.wea_img == 'xue') {
          this.imgSrc = require('../assets/img/brand/xue.png');
        } else if (res.data.wea_img == 'yin') {
          this.imgSrc = require('../assets/img/brand/yin.png');
        } else if (res.data.wea_img == 'yu' || res.data.wea_img == 'bingbao') {
          this.imgSrc = require('../assets/img/brand/yu.png');
        } else if (res.data.wea_img == 'yun') {
          this.imgSrc = require('../assets/img/brand/yun.png');
        } else if (res.data.wea_img == 'wu') {
          this.imgSrc = require('../assets/img/brand/wu.png');
        } else if (res.data.wea_img == 'shachen') {
          this.imgSrc = require('../assets/img/brand/shachen.png');
        } else if (res.data.wea_img == 'lei') {
          this.imgSrc = require('../assets/img/brand/lei.png');
        } else {
          this.imgSrc = require('../assets/img/brand/qing.png');
        }
        this.weatcherData = res.data;
      }
    }).catch(err => {
      console.log(err)
    })
  }
}

當前時間代碼實現如下:

mounted() {
  this.nowTimes();
},
methods: {
  timeFormate(timeStamp) { //顯示當前時間
    let newDate = new Date(timeStamp);
    let year = newDate.getFullYear();
    let month = newDate.getMonth() + 1 < 10 ? '0' + (newDate.getMonth() + 1) : newDate.getMonth() + 1;
    let date = newDate.getDate() < 10 ? '0' + newDate.getDate() : newDate.getDate();
    let hh = newDate.getHours() < 10 ? '0' + newDate.getHours() : newDate.getHours();
    let mm = newDate.getMinutes() < 10 ? '0' + newDate.getMinutes() : newDate.getMinutes();
    let ss = newDate.getSeconds() < 10 ? '0' + newDate.getSeconds() : newDate.getSeconds();
    let week = newDate.getDay();
    let weeks = ['日', '一', '二', '三', '四', '五', '六'];
    let getWeek = '星期' + weeks[week];
    this.week = getWeek;
    this.date = year + '.' + month + '.' + date;
    this.nowTime = hh + ':' + mm + ':' + ss;
  },
  nowTimes() {
    this.timeFormate(new Date());
    setInterval(this.nowTimes, 1000);
    this.clear();
  },
  clear() {
    clearInterval(this.nowTimes)
    this.nowTimes = null;
  },
}
  • Echarts 圖表和地圖的基本使用

1)Echarts使用五部曲

  1. 本項目採用cdn引入echarts.js文件(圖表依賴這個js庫)

index.html引入cdn
在這裏插入圖片描述
vue.config.js配置webpack
在這裏插入圖片描述

  1. 準備一個具備大小的容器(生成的圖表會放入這個容器內)
<div class="chart" id="chart" style="width: 480px; height: 240px;"></div>
  1. 初始化echarts實例對象(實例化echarts對象)
let myChart = echarts.init(document.getElementById('chart'));
  1. 指定配置項和數據 option(根據具體需求修改配置選項)
let option = {
  xAxis: {
    type: 'category',
    boundaryGap: false,
    data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
  },
  yAxis: {
    type: 'value'
  },
  series: [{
    data: [820, 932, 901, 934, 1290, 1330, 1320],
    type: 'line',
    areaStyle: {},
    smooth: true
  }]
};
  1. 將配置項設置給echarts實例對象(讓echarts對象根據修改好的配置生效)
myChart.setOption(option);

// 讓圖表跟隨屏幕自適應
window.addEventListener("resize", () => {
  myChart.resize();
});

2)瞭解echarts基礎配置
在這裏插入圖片描述
如需瞭解更多,請移步到Echarts官網查看相關文檔。

3)製作柱狀圖圖表

一般直接去echarts官網查找類似實例,適當分析,並且引入到頁面中,再根據需求定製圖表。官方實例地址:https://echarts.apache.org/examples/zh/index.html#chart-type-bar
在這裏插入圖片描述
比如上圖的效果是如何實現的呢?

作者悄悄地告訴你,其實有個很簡單的方法,直接在Echarts社區查找,因爲社區有很多活躍的Echarts使用者,經常貢獻一些非常棒的圖表示例。

本項目參考實例地址:https://gallery.echartsjs.com/editor.html?c=xgqdKhn5c,經過修改調整,最終呈現的效果如上圖。已封裝註冊全局小組件,源代碼在/src/components/companySummary/business.vue目錄文件,請自行查看。

4)Echarts map地圖使用

也是參考社區例子:模擬飛機航線動效

實現步驟:

  • 首先下載引入中國地圖china.js文件(文件存放路徑:/src/assets/js/china.js)
  • 其次使用社區實例的配置即可,修改圖例,標題,背景色,地圖放大比例等達到你想要的效果。

這個例子是擴展案例,大家以後可以多看看社區裏面的實例。

/* 約束屏幕尺寸 */
@media screen and (max-width: 1024px) {
  html {
    font-size: 42px !important;
  }
}
@media screen and (min-width: 1920) {
  html {
    font-size: 80px !important;
  }
}

5)自定義詞雲圖

先上效果圖
在這裏插入圖片描述
上圖效果,作者已封裝註冊全局小組件,源代碼在/src/components/companySummary/wordCloud.vue目錄文件,請自行查看。

首先下載echarts-wordcloud.min.js壓縮文件(存放路徑:/src/assets/js),並導入到wordCloud.vue模板文件中。代碼如下:

<template>
  <div class="word-container"> 
    <div class="chart" id="chart_right1"></div>
  </div>
</template>

<script>
import '@/assets/js/echarts-wordcloud.min'

export default {
  name: "wordCloud",
  data() {
    return {
      timer: null
    }
  },
  mounted() {
    this.getEchartRight1();
    this.timer = setInterval(() => {
      this.getEchartRight1();
    }, 5000)
  },
  methods: {
    getEchartRight1() {
      let myChart = echarts.init(document.getElementById('chart_right1'));
      let option = {
        // tooltip: {
        //   show: false
        // },
        series: [{
          type: 'wordCloud',
          gridSize: 1,
          sizeRange: [12, 50],
          rotationRange: [-90, 90],
          rotationStep: 45,
          shape: 'diamond',
          width: '90%',
          textPadding: 0,
          autoSize: {
            enable: true,
            minSize: 6
          },
          textStyle: {
            normal: {
              textBorderColor: 'rgba(255,255,255,0.3)',
              textBorderWidth: 1,
              color: () => {
                return 'rgb(' + [
                  Math.round(Math.random() * 160),
                  Math.round(Math.random() * 160),
                  Math.round(Math.random() * 160)
                ].join(',') + ')';
              }
            },
            emphasis: {
              fontSize: 20,
              // shadowBlur: 10,
              // shadowColor: 'rgba(255,255,255, .1)'
            }
          },
          data: [{
            name: '區塊鏈',
            value: 810
          }, {
            name: '雲計算',
            value: 520
          },{
            name: "人工智能",
            value: 928
          },{
            name: "大數據",
            value: 906
          },{
            name: "工業互聯網",
            value: 825
          },{
            name: "醫療",
            value: 514
          },{
            name: "質量溯源",
            value: 486
          },{
            name: "政務",
            value: 53
          },{
            name: "密碼學",
            value: 927
          },{
            name: "金融行業",
            value: 1308
          },{
            name: "供應鏈",
            value: 693
          },{
            name: "公有鏈",
            value: 611
          },{
            name: "私有鏈",
            value: 512
          },{
            name: "聯盟鏈",
            value: 382
          },{
            name: "數據共享",
            value: 312
          },{
            name: "文創版權",
            value: 187
          },{
            name: "天河鏈",
            value: 163
          },{
            name: "數據存證",
            value: 104
          },{
            name: "UDFS存儲",
            value: 3
          },{
            name: "在線教育",
            value: 31
          },{
            name: "關聯分析",
            value: 941
          },{
            name: "智慧停車",
            value: 585
          },{
            name: "鏈雲生態",
            value: 473
          },{
            name: "應用層",
            value: 358
          },{
            name: "網絡層",
            value: 246
          },{
            name: "數據層",
            value: 207
          },{
            name: "基礎層",
            value: 194
          },{
            name: "智能合約",
            value: 104
          },{
            name: "去中心化",
            value: 87
          },{
            name: "數字貨幣",
            value: 415
          },{
            name: "酷屏",
            value: 253
          },{
            name: "可視化",
            value: 211
          },{
            name: "P2P",
            value: 116
          },{
            name: "數據挖掘",
            value: 1309
          }]
        }]
      }

      myChart.setOption(option, true);
      window.addEventListener('resize', () => {
        myChart.resize();
      });
    },
  },
  beforeDestroy() {
    clearInterval(this.timer);
  }
};
</script>

參考配置說明:https://github.com/ecomfe/echarts-wordcloud

最後

如果感覺還不錯的話,老鐵們是不是來github裏賞個★Star鼓勵一哈。後續會持續更新和優化,也期待大家的交流。

從未停止發表一些實戰型項目的前端技術文章,分享讓更多小夥伴不花錢就能學到前端實戰經驗,也希望能幫助到大家一起成長,能與更多前端大神多交流學習,這是作者的初心。後續主題如下:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章