Vue使用Echarts實現(xiàn)橫向柱狀圖,并通過WebSocket即時通訊更新
先看下效果圖
并且數(shù)據(jù)每隔3秒自動變換一次
先看下后臺返回的數(shù)據(jù)結(jié)構(gòu)是什么樣子的
[ { "name":"商家1", "value":"99" }, { "name":"商家2", "value":"199" }, { "name":"商家3", "value":"222" }, { "name":"商家4", "value":"99" }, { "name":"商家5", "value":"499" }, { "name":"商家6", "value":"252" }, { "name":"商家7", "value":"199" }, { "name":"商家8", "value":"29" }, { "name":"商家9", "value":"232" },{ "name":"商家10", "value":"99" }, { "name":"商家11", "value":"77" }, { "name":"商家12", "value":"82" }, { "name":"商家13", "value":"99" }, { "name":"商家14", "value":"19" }, { "name":"商家15", "value":"22" }, { "name":"商家16", "value":"522" } ]
開始實現(xiàn)前端的代碼
html
<div class="com-page"> <div class="com-container"> <div class="com-chart" ref="seller_ref"></div> </div> </div>
css
html,body,#app{ width: 100%; height: 100%; padding: 0; margin: 0; overflow: hidden; } .com-page { width: 100%; height: 100%; overflow: hidden; } .com-container { position: relative; width: 100%; height: 100%; overflow: hidden; } .com-chart { width: 100%; height: 100%; overflow: hidden; }
data
data() { return { chartInstance: null, //初始化echartInstance對象 allData: null, //接收的后臺數(shù)據(jù) currentPage: 1, //當前顯示的頁數(shù) totalPage: 0, //一共有多少頁 timerId: null //定時器標識 } },
methods
initChart方法
initChart() { //初始化echartInstance對象 //chalk是我們定義的主題,echarts官方有案例,怎么使用可以百度一下,不喜歡可以直接刪掉 this.chartInstance = this.$echarts.init(this.$refs.seller_ref, 'chalk') //對圖表初始化配置對控制 const initOption = { title: { text: '▎商家銷售統(tǒng)計', left: 20, top: 20 }, grid: { top: '20%', left: '3%', right: '6%', bottom: '3%', containLabel: true // 距離是包含坐標軸上的文字 }, xAxis: { type: 'value' }, yAxis: { type: 'category' }, tooltip: { trigger: 'axis', axisPointer: { type: 'line', z: 0, lineStyle: { color: '#2D3443' } } }, series: [{ type: 'bar', label: { show: true, position: 'right', textStyle: { color: 'white' } }, itemStyle: { // 指明顏色漸變的方向 // 指明不同百分比之下顏色的值 color: new this.$echarts.graphic.LinearGradient(0, 0, 1, 0, [ // 百分之0狀態(tài)之下的顏色值 { offset: 0, color: '#5052EE' }, // 百分之100狀態(tài)之下的顏色值 { offset: 1, color: '#AB6EE5' } ]) } }] } this.chartInstance.setOption(initOption) //對圖表對象進行鼠標事件監(jiān)聽 //鼠標移入,定時器停止 this.chartInstance.on('mouseover', () => { clearInterval(this.timerId) }) //鼠標移出,定時器開始 this.chartInstance.on('mouseout', () => { this.startInterval() }) },
getData方法
這里還是用http請求獲取的數(shù)據(jù),后面我再講怎么用WebSocket獲取我們的數(shù)據(jù)
async getData() { const { data: res } = await this.$http.get('seller') this.allData = res //對數(shù)據(jù)進行排序 this.allData.sort((a, b) => { return a.value - b.value //從小到大排序 }) //每五個元素顯示一頁 this.totalPage = this.allData.length % 5 === 0 ? this.allData.length / 5 : this.allData.length / 5 + 1 this.updateChart() //啟動定時器 this.startInterval() },
updateChart方法
//更新圖表 updateChart() { //起始的位置 const start = (this.currentPage - 1) * 5 //結(jié)束的位置 //起始為0,所以展示1-5 const end = this.currentPage * 5 const showData = this.allData.slice(start, end) const sellerNames = showData.map((item) => { return item.name }) const sellerValue = showData.map((item) => { return item.value }) const dataOption = { yAxis: { data: sellerNames }, series: [{ data: sellerValue }] } this.chartInstance.setOption(dataOption) },
startInterval方法
//定時器,數(shù)據(jù)每3秒更新一次 startInterval() { if (this.timerId) { clearInterval(this.timerId) } this.timerId = setInterval(() => { this.currentPage++ if (this.currentPage > this.totalPage) { this.currentPage = 1 } this.updateChart() }, 3000) },
screenAdapter方法
//屏幕適配 screenAdapter() { const titleFontSize = this.$refs.seller_ref.offsetWidth / 100 * 3.6 console.log(titleFontSize) const adapterOption = { title: { textStyle: { fontSize: titleFontSize } }, tooltip: { axisPointer: { lineStyle: { width: titleFontSize } } }, series: [{ barWidth: titleFontSize, //圓角大小 itemStyle: { barBorderRadius: [0, titleFontSize / 2, titleFontSize / 2, 0], } }] } this.chartInstance.setOption(adapterOption) //手動調(diào)用圖表對象resize this.chartInstance.resize() }
mounted
mounted() { this.initChart() this.getData() window.addEventListener('resize', this.screenAdapter) this.screenAdapter() },
destroyed
destroyed() { clearInterval(this.timerId) window.removeEventListener('resize', this.screenAdapter) },
好了,完事
下面我把如何用WebSocket獲取數(shù)據(jù)說一下
封裝了一個WebSocket
export default class SocketService { /** * 單例 */ static instance = null static get Instance() { if (!this.instance) { this.instance = new SocketService() } return this.instance } // 和服務端連接的socket對象 ws = null // 存儲回調(diào)函數(shù) callBackMapping = {} // 標識是否連接成功 connected = false // 記錄重試的次數(shù) sendRetryCount = 0 // 重新連接嘗試的次數(shù) connectRetryCount = 0 // 定義連接服務器的方法 connect() { // 連接服務器 if (!window.WebSocket) { return console.log('您的瀏覽器不支持WebSocket') } this.ws = new WebSocket('ws://localhost:9998') // 連接成功的事件 this.ws.onopen = () => { console.log('連接服務端成功了') this.connected = true // 重置重新連接的次數(shù) this.connectRetryCount = 0 } // 1.連接服務端失敗 // 2.當連接成功之后, 服務器關閉的情況 this.ws.onclose = () => { console.log('連接服務端失敗') this.connected = false this.connectRetryCount++ setTimeout(() => { this.connect() }, 500 * this.connectRetryCount) } // 得到服務端發(fā)送過來的數(shù)據(jù) this.ws.onmessage = msg => { console.log('從服務端獲取到了數(shù)據(jù)') // 真正服務端發(fā)送過來的原始數(shù)據(jù)時在msg中的data字段 // console.log(msg.data) const recvData = JSON.parse(msg.data) const socketType = recvData.socketType // 判斷回調(diào)函數(shù)是否存在 if (this.callBackMapping[socketType]) { const action = recvData.action if (action === 'getData') { const realData = JSON.parse(recvData.data) this.callBackMapping[socketType].call(this, realData) } else if (action === 'fullScreen') { this.callBackMapping[socketType].call(this, recvData) } else if (action === 'themeChange') { this.callBackMapping[socketType].call(this, recvData) } } } } // 回調(diào)函數(shù)的注冊 registerCallBack (socketType, callBack) { this.callBackMapping[socketType] = callBack } // 取消某一個回調(diào)函數(shù) unRegisterCallBack (socketType) { this.callBackMapping[socketType] = null } // 發(fā)送數(shù)據(jù)的方法 send (data) { // 判斷此時此刻有沒有連接成功 if (this.connected) { this.sendRetryCount = 0 this.ws.send(JSON.stringify(data)) } else { this.sendRetryCount++ setTimeout(() => { this.send(data) }, this.sendRetryCount * 500) } } }
在main.js中進行連接,掛載原型
//對服務端進行連接 import SocketService from '../utils/socket_service' SocketService.Instance.connect() // 其他的組件 this.$socket Vue.prototype.$socket = SocketService.Instance
然后在組件中
created() { //在組件創(chuàng)建完成之后進行回調(diào)函數(shù)注冊 this.$socket.registerCallBack('trendData',this.getData) }, mounted() { this.initChart(); //發(fā)送數(shù)據(jù)給服務器,告訴服務器,我現(xiàn)在需要數(shù)據(jù) this.$socket.send({ action:'getData', socketType:'trendData', chartName:'trend', value:'' }) window.addEventListener("resize", this.screenAdapter); this.screenAdapter(); }, destroyed() { window.removeEventListener("resize", this.screenAdapter); //取消 this.$socket.unRegisterCallBack('trendData') }, methods:{ //res就是服務端發(fā)送給客戶端的圖表數(shù)據(jù) getData(res) { this.allData = res; this.updateChart(); }, }
這樣就實現(xiàn)了后端發(fā)生變化,前端即時更新視圖
至于為什么WebSocket這樣封裝,因為后臺定了規(guī)則
const path = require('path') const fileUtils = require('../utils/file_utils') const WebSocket = require('ws') // 創(chuàng)建WebSocket服務端的對象, 綁定的端口號是9998 const wss = new WebSocket.Server({ port: 9998 }) // 服務端開啟了監(jiān)聽 module.exports.listen = () => { // 對客戶端的連接事件進行監(jiān)聽 // client:代表的是客戶端的連接socket對象 wss.on('connection', client => { console.log('有客戶端連接成功了...') // 對客戶端的連接對象進行message事件的監(jiān)聽 // msg: 由客戶端發(fā)給服務端的數(shù)據(jù) client.on('message',async msg => { console.log('客戶端發(fā)送數(shù)據(jù)給服務端了: ' + msg) let payload = JSON.parse(msg) const action = payload.action if (action === 'getData') { let filePath = '../data/' + payload.chartName + '.json' // payload.chartName // trend seller map rank hot stock filePath = path.join(__dirname, filePath) const ret = await fileUtils.getFileJsonData(filePath) // 需要在服務端獲取到數(shù)據(jù)的基礎之上, 增加一個data的字段 // data所對應的值,就是某個json文件的內(nèi)容 payload.data = ret client.send(JSON.stringify(payload)) } else { // 原封不動的將所接收到的數(shù)據(jù)轉(zhuǎn)發(fā)給每一個處于連接狀態(tài)的客戶端 // wss.clients // 所有客戶端的連接 wss.clients.forEach(client => { client.send(msg) }) } // 由服務端往客戶端發(fā)送數(shù)據(jù) // client.send('hello socket from backend') }) }) }
有不懂的可以去我的github查看源代碼,前后端都有,后端必須啟動,前端才有顯示,WebSocket我只配了Trend組件,其他全部一樣的操作
github項目地址https://github.com/lsh555/Echarts
項目詳情如下
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
Vue.js@2.6.10更新內(nèi)置錯誤處機制Fundebug同步支持相應錯誤監(jiān)控
這篇文章主要介紹了Vue.js@2.6.10更新內(nèi)置錯誤處機制,F(xiàn)undebug同步支持相應錯誤監(jiān)控 ,需要的朋友可以參考下2019-05-05vue使用mpegts.js實現(xiàn)播放flv的直播視頻流
這篇文章主要為大家詳細介紹了vue如何使用mpegts.js實現(xiàn)播放flv的直播視頻流,文中的示例代碼講解詳細,有需要的小伙伴可以參考一下2024-01-01SpringBoot實現(xiàn)全局和局部跨域的兩種方式
本文主要介紹了SpringBoot實現(xiàn)全局和局部跨域的兩種方式,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2023-01-01