1.vue-cli 搭建项目
npm install @vue/cli -g (一台电脑只执行一次即可)
vue create 项目名
选 (下键选择 空格确认)
:Manually select features 手动选择某些特性
:Router Vuex CSS
:2.0 x
Use history mode for router?是否使用路由: no
CSS预处理语言 : Less
ESLint 配置模式 - 标准模式:ESLint + Standard config
何时出现ESLint提示- 保存时:Lint on save
配置问件处理:In dedicated config files 单独存放
Save this as a preset for future projects? (y/N) :no
cd 项目名
npm run serve
2.删除无关代码
①App.vue文件中:
//待编写
②components文件夹、 views文件夹 清空
③router/index.js文件中 剩余内容:
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
const routes = [ ]
const router = new VueRouter({
routes
})
export default router
3.静态资源的引入
图片img、第三方包lib、地图map、主题theme 放在public文件夹下
4.项目的基本配置
根目录下创建vue.config.js文件:
module.exports = {
devServer: {
port: 8999, //前端 端口号 访问网址(http://localhost:8999/#/具体页面路由)
open: true //自动打开浏览器
}
};
5.全局echarts对象的挂载
public/index.html文件中:
src/main.js文件中:
// 将全局的echarts对象挂载到Vue的原型对象上
// 别的组件中 使用this.$echarts
Vue.prototype.$echarts = window.echarts;
6.axios的封装与挂载
下载axios模块 :npm install axios
src/main.js文件中:
import axios from "axios"; //引入axios // 请求基准路径的配置 接口前缀 axios.defaults.baseURL = "http://127.0.0.1:8888/api/"; // 将axios挂载到Vue的原型对象上 在别的组件中 使用this.$http发起ajax请求 Vue.prototype.$http = axios;
1.横向柱状图 Seller.vue
①组件结构和布局结构的设计
router/index.js文件中:(定义路由)
import SellerPage from '@/views/SellerPage'
const routes = [{ path: '/sellerpage', component: SellerPage }] //路由规则
App.vue文件中:
//路由的占位符
父- views/SellerPage.vue文件中:(创建SellerPage.vue文件)
③ //显示子组件
子- components/Seller.vue文件中:(创建Seller.vue文件,功能主要写在这个文件里面)
你好
assets/css/global.less文件中: 全局样式
html, body, #app {
width: 100%;
height: 100%;
padding: 0;
margin: 0;
overflow: hidden;
}
.com-page {
width: 100%;
height: 100%;
overflow: hidden;
}
.com-container {
width: 100%;
height: 100%;
overflow: hidden;
}
.com-chart {
width: 100%;
height: 900px; //注意
overflow: hidden;
}
canvas {
border-radius: 20px; // 全局样式 圆角
}
.com-container {
position: relative;
}
main.js文件中:
// 引入全局的样式文件
import "./assets/css/global.less";
public/index.html文件中: 声明主题
components/Seller.vue文件中:总的代码
//ref更好的获取dom
2.折线图:Trend.vue
main.js文件中:
import './assets/font/iconfont.css' //引入字体icon的样式
router/index.js文件中:
import MapPage from '@/views/MapPage'
const routes = [
{ path: '/sellerpage', component: SellerPage },
{ path: '/trendpage', component: TrendPage },
]
views/TrendPage.vue文件中:
componens/Trend.vue文件中:总的代码
{{ '▎ ' + showTitle }}
{{ item.text }}
3.地图+散点图
router/index.js文件中:
import MapPage from '@/views/MapPage'
const routes = [
{ path: '/sellerpage', component: SellerPage },
{ path: '/trendpage', component: TrendPage },
{ path: '/mappage', component: MapPage }
]
views/MapPage.vue文件中:
componens/Map.vue文件中:总的代码
4.柱状图
router/index.js文件中:
import Vue from 'vue'
import VueRouter from 'vue-router'
import TrendPage from '@/views/TrendPage'
import SellerPage from '@/views/SellerPage'
import MapPage from '@/views/MapPage'
import RankPage from '@/views/RankPage'
Vue.use(VueRouter)
const routes = [
{ path: '/sellerpage', component: SellerPage },
{ path: '/trendpage', component: TrendPage },
{ path: '/mappage', component: MapPage },
{ path: '/rankpage', component: RankPage }
]
const router = new VueRouter({
routes
})
export default router
views/RankPage.vue文件中:
componens/Rank.vue文件中:总的代码
5.饼图
router/index.js文件中:
import Vue from 'vue'
import VueRouter from 'vue-router'
import TrendPage from '@/views/TrendPage'
import SellerPage from '@/views/SellerPage'
import MapPage from '@/views/MapPage'
import RankPage from '@/views/RankPage'
import HotPage from '@/views/HotPage'
Vue.use(VueRouter)
const routes = [
{ path: '/sellerpage', component: SellerPage },
{ path: '/trendpage', component: TrendPage },
{ path: '/mappage', component: MapPage },
{ path: '/rankpage', component: RankPage },
{ path: '/hotpage', component: HotPage }
]
const router = new VueRouter({
routes
})
export default router
views/HotPage.vue文件中:
componens/Hot.vue文件中:总的代码
{{ catName }}
6.循环饼图
router/index.js文件中:
import Vue from 'vue'
import VueRouter from 'vue-router'
import TrendPage from '@/views/TrendPage'
import SellerPage from '@/views/SellerPage'
import MapPage from '@/views/MapPage'
import RankPage from '@/views/RankPage'
import HotPage from '@/views/HotPage'
import StockPage from '@/views/StockPage'
Vue.use(VueRouter)
const routes = [
{ path: '/sellerpage', component: SellerPage },
{ path: '/trendpage', component: TrendPage },
{ path: '/mappage', component: MapPage },
{ path: '/rankpage', component: RankPage },
{ path: '/hotpage', component: HotPage },
{ path: '/stockpage', component: StockPage }
]
const router = new VueRouter({
routes
})
export default router
views/StockPage.vue文件中:
componens/Stock.vue文件中:总的代码
1.后端 app.js文件中:
const webSocketService = require('./service/web_socket_service')
// 开启服务端的监听, 监听客户端的连接
// 当某一个客户端连接成功之后, 就会对这个客户端进行message事件的监听
webSocketService.listen()
// 读取文件的工具方法
const fs = require("fs");
module.exports.getFileJsonData = filePath => {
// return "你好";
return new Promise((resolve, reject) => {
fs.readFile(filePath, "utf-8", (error, data) => {
if (error) {
reject(error);
} else {
resolve(data);
}
});
});
};
src/service/web_socket_service.js文件中:
const path = require('path')
const fileUtils = require('../utils/file_utils')
//WebSocket的引入
//下载插件 npm i ws -S
const WebSocket = require('ws')
// 创建WebSocket服务端的对象, 绑定的端口号是9998
const wss = new WebSocket.Server({
port: 9998
})
// 服务端开启了监听
module.exports.listen = () => {
// 对客户端的连接事件进行connection事件的监听
// client:代表的是客户端的连接socket对象
wss.on('connection', client => {
console.log('有客户端连接成功了...')
// 对客户端的连接对象进行message事件的监听
// msg: 由客户端发给服务端的数据
client.on('message', async msg => {
console.log('客户端发送数据给服务端了: ' + 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)
// 需要在服务端获取到数据的基础之上, 增加一个data的字段
// data所对应的值,就是某个json文件的内容
payload.data = ret
client.send(JSON.stringify(payload))
} else {
// 原封不动的将所接收到的数据转发给每一个处于连接状态的客户端
// wss.clients // 所有客户端的连接
wss.clients.forEach(client => {
client.send(msg)
})
}
// 由服务端往客户端发送数据
// client.send('hello socket from backend')
})
})
}
2.前端
export default class SocketService {
/**
* 单例
*/
static instance = null
static get Instance () {
if (!this.instance) {
this.instance = new SocketService()
}
return this.instance
}
// 和服务端连接的socket对象
ws = null
// 存储回调函数
callBackMapping = {}
// 标识是否连接成功
connected = false
// 记录重试的次数
sendRetryCount = 0
// 重新连接尝试的次数
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
// 重置重新连接的次数
this.connectRetryCount = 0
}
// 1.连接服务端失败
// 2.当连接成功之后, 服务器关闭的情况
this.ws.onclose = () => {
console.log('连接服务端失败')
this.connected = false
this.connectRetryCount++
setTimeout(() => {
this.connect()
}, 500 * this.connectRetryCount)
}
// 得到服务端发送过来的数据
this.ws.onmessage = msg => {
console.log('从服务端获取到了数据')
// 真正服务端发送过来的原始数据时在msg中的data字段
// console.log(msg.data)
const recvData = JSON.parse(msg.data)
const socketType = recvData.socketType
// 判断回调函数是否存在
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)
}
}
}
}
// 回调函数的注册
registerCallBack (socketType, callBack) {
this.callBackMapping[socketType] = callBack
}
// 取消某一个回调函数
unRegisterCallBack (socketType) {
this.callBackMapping[socketType] = null
}
// 发送数据的方法
send (data) {
// 判断此时此刻有没有连接成功
if (this.connected) {
this.sendRetryCount = 0
this.ws.send(JSON.stringify(data))
} else {
this.sendRetryCount++
setTimeout(() => {
this.send(data)
}, this.sendRetryCount * 500)
}
}
}
src/main.js文件中:
import SocketService from '@/utils/socket_service'
// 对服务端进行websocket的连接
SocketService.Instance.connect()
// 其他的组件 this.$socket
Vue.prototype.$socket = SocketService.Instance
componens/Seller.vue文件中: 其他组件一样
created () {
// 在组件创建完成之后 进行回调函数的注册
this.$socket.registerCallBack('sellerData', this.getData)
},
mounted () {
// this.getData()
this.$socket.send({
action: 'getData',
socketType: 'sellerData',
chartName: 'seller',
value: ''
})
},
destroyed () {
this.$socket.unRegisterCallBack('sellerData')
},
methods:{
// 获取服务器的数据
getData (ret) {
// const { data: ret } = await this.$http.get('seller')
this.allData = ret
},
}
1.组件合并
src/router/index.js文件中:
import Vue from 'vue'
import VueRouter from 'vue-router'
import ScreenPage from '@/views/ScreenPage'
Vue.use(VueRouter)
const routes = [
{
path: '/',
redirect: '/screen'
},
{
path: '/screen',
component: ScreenPage
}
]
const router = new VueRouter({
routes
})
export default router
src/views/ScreenPage.vue文件中:组件 -导入注册引用
电商平台实时监控系统
{{timeComput}}
2.主题切换
①图表主题
src/store/index.js文件中:数据存储
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
theme: 'chalk'
},
mutations: {
changeTheme (state) {
if (state.theme === 'chalk') {
state.theme = 'vintage'
} else {
state.theme = 'chalk'
}
}
},
actions: {
},
modules: {
}
})
public/static/index.html文件中:
src/views/ScreenPage.vue文件中:
methods:{
handleChangeTheme () {
// 修改VueX中数据
this.$store.commit('changeTheme')
}
}
components/Seller.vue文件中: 其他组件同样
import { mapState } from 'vuex'
computed: {
...mapState(['theme'])
},
watch: {
theme () {
console.log('主题切换了')
this.chartInstance.dispose() // 销毁当前的图表
this.initChart() // 重新以最新的主题名称初始化图表对象
this.screenAdapter() // 完成屏幕的适配
this.updateChart() // 更新图表的展示
}
},
methods:{
initChart () {
this.chartInstance = this.$echarts.init(this.$refs.hot_ref, this.theme)
}
}
②特殊html的主题:
src/utils/theme_utils.js文件中:
const theme = {
chalk: {
backgroundColor: '#161522', // 背景颜色
titleColor: '#ffffff', // 标题的文字颜色
logoSrc: 'logo_dark.png', // 左上角logo的图标路径
themeSrc: 'qiehuan_dark.png', // 切换主题按钮的图片路径
headerBorderSrc: 'header_border_dark.png'// 页面顶部的边框图片
},
vintage: {
backgroundColor: '#eeeeee', // 背景颜色
titleColor: '#000000',// 标题的文字颜色
logoSrc: 'logo_light2.png', // 左上角logo的图标路径
themeSrc: 'qiehuan_light.png',// 切换主题按钮的图片路径
headerBorderSrc: 'header_border_light.png' // 页面顶部的边框图片
}
}
export function getThemeValue (themeName) {
return theme[themeName]
}
components/Hot.vue文件中: 其他组件同样
import { getThemeValue } from '@/utils/theme_utils'
computed: {
comStyle () {
return {
color: getThemeValue(this.theme).titleColor
}
},
},
src/views/ScreenPage.vue文件中:
import { mapState } from 'vuex'
import { getThemeValue } from '@/utils/theme_utils'
computed: {
headerSrc () {
return '/static/img/' + getThemeValue(this.theme).headerBorderSrc
},
themeSrc () {
return '/static/img/' + getThemeValue(this.theme).themeSrc
},
containerStyle () {
return {
backgroundColor: getThemeValue(this.theme).backgroundColor,
color: getThemeValue(this.theme).titleColor
}
},
...mapState(['theme'])
}