示例图:上面四个框可以点击
重要代码片段 :
index_v1中
<panel-group @handleSetLineChartData="handleSetLineChartData" :data="totalData"/>
- : 这是一个自定义的 Vue 组件。名称是
panel-group
。- @handleSetLineChartData="handleSetLineChartData": 这是一个事件监听器。在 Vue.js 中,
@
是v-on:
的简写,用于监听 DOM 事件。这意味着当panel-group
组件触发一个名为handleSetLineChartData
的事件时,它将调用当前 Vue 实例中的handleSetLineChartData
方法。- :data="totalData": 这是一个属性绑定。在 Vue.js 中,
:
是v-bind:
的简写,用于绑定一个属性到一个表达式。这里,它将panel-group
组件的data
属性绑定到当前 Vue 实例的totalData
数据属性。这意味着panel-group
组件内部可以访问并使用这个data
属性。总的来说,这段代码的意思是:渲染一个名为
panel-group
的自定义组件,当该组件触发handleSetLineChartData
事件时,调用handleSetLineChartData
方法,并将totalData
数据属性传递给该组件的data
属性。
methods: { handleSetLineChartData(type) { this.lineChartData.type=type; console.log("点击上方按钮的数据变化type:",this.lineChartData) }, }定义了一个名为
handleSetLineChartData
的方法。这个方法接受一个参数type
,并将这个type
值赋给this.lineChartData.type。
PanelGroup.vue中
<div class="card-panel" @click="handleSetLineChartData('inBound')">表示一个
div
元素,它具有一个card-panel
类,并且当这个div
被点击时,它会调用handleSetLineChartData
方法并传递'inBound'
字符串作为参数。这里是具体的分解:
<div class="card-panel">
:这是一个div
元素,它有一个card-panel
类,通常用于 CSS 样式或 JavaScript 选择器。
@click="handleSetLineChartData('inBound')"
:这是一个事件监听器,它监听click
事件。当这个div
被点击时,它会执行handleSetLineChartData
方法,并传递一个字符串参数'inBound'
。
@
是v-on:
的简写,用于监听 DOM 事件。click
是要监听的事件名称,即鼠标点击事件。"handleSetLineChartData('inBound')"
是当事件触发时要调用的方法,并传递一个参数。在这个例子中,当
div
被点击时,handleSetLineChartData
方法将被调用,并且type
参数将被设置为'inBound'
。这通常用于更新组件的状态或触发其他操作,比如更新图表数据。
//接收TotalData props: { data: { typeof: Object,//数据类型 required: true//必须的 } },methods: { handleSetLineChartData(type) { this.$emit('handleSetLineChartData', type) } }分析:
props
用于子组件接收父组件传递下来的数据handleSetLineChartData(type)
: 这是一个方法,它接受一个参数type
。this.$emit('handleSetLineChartData', type)
: 在这个方法中,组件使用$emit
方法触发一个自定义事件,事件的名称也是handleSetLineChartData
,并且传递了type
参数。这通常用于通知父组件某些状态的变化或者触发父组件的某个方法。现在,将这两部分结合起来解释:
当父组件使用
<panel-group />
组件,并传递一个data prop
时,这个data
会被panel-group
组件接收并使用。如果panel-group
组件内部需要通知其父组件更新线性图表的数据类型,它会调用handleSetLineChartData
方法,并传递相应的type
。通过$emit
,这个事件和参数会被发送到父组件,父组件可以监听这个事件并调用相应的处理函数(如handleSetLineChartData
),从而更新线性图表的数据。
全部代码:
index_v1.vue
<template>
<div class="dashboard-editor-container">
<panel-group @handleSetLineChartData="handleSetLineChartData" :data="totalData"/>
<el-row style="background:#fff;padding:16px 16px 0;margin-bottom:32px;">
<line-chart :chart-data="lineChartData" v-if="!isLoading1"/>
</el-row>
<el-row :gutter="32">
<el-col :xs="24" :sm="24" :lg="8">
<div class="chart-wrapper">
<raddar-chart/>
</div>
</el-col>
<el-col :xs="24" :sm="24" :lg="8">
<div class="chart-wrapper">
<pie-chart/>
</div>
</el-col>
<el-col :xs="24" :sm="24" :lg="8">
<div class="chart-wrapper">
<bar-chart/>
</div>
</el-col>
</el-row>
</div>
</template>
<script>
import PanelGroup from './dashboard/PanelGroup'
//折线图
import LineChart from './dashboard/LineChart'
//雷达图
import RaddarChart from './dashboard/RaddarChart'
//饼图
import PieChart from './dashboard/PieChart'
//柱状图
import BarChart from './dashboard/BarChart'
import BackGrand from "@/views/dashboard/BackGrand";
import {getTotalData,getStatistics} from "@/api";
const lineChartData = {
//折线图
type:"inBound",
inBound: [],
outBound: [],
returnBound: [],
inventory: [],
dateData:[]
}
export default {
name: 'Index',
components: {
PanelGroup,
LineChart,
RaddarChart,
PieChart,
BarChart,
BackGrand
},
data() {
return {
// lineChartData: lineChartData.inBound,
lineChartData:{},
totalData: {},
isLoading1 :true,
}
},
created() {
this.getTotalData();
this.getStatistics();
},
methods: {
handleSetLineChartData(type) {
this.lineChartData.type=type;
console.log("点击上方按钮的数据变化type:",this.lineChartData)
//this.lineChartData = lineChartData[type]
},
getTotalData() {
getTotalData().then(response =>{
console.log("response",response);
this.totalData=response.data;
})
},
getStatistics() {
getStatistics().then(response =>{
console.log("response1",response);
//this.lineChartData=response.data;
this.lineChartData.inBound=response.data.map(item=>item.everydayInboundCount);
console.log("inBound",this.lineChartData.inBound);
this.lineChartData.outBound=response.data.map(item=>item.everydayOutboundCount);
console.log("outbound:",this.lineChartData.outBound)
this.lineChartData.returnBound=response.data.map(item=>item.everydayReturnboundCount);
console.log("returnbound:",this.lineChartData.returnBound)
this.lineChartData.inventory=response.data.map(item=>item.inventoryCount);
console.log("inventory:",this.lineChartData.inventory)
this.lineChartData.dateData=response.data.map(item=>item.date);
this.isLoading1 = false;
this.lineChartData.type="inBound";
})
},
}
}
</script>
<style lang="scss" scoped>
.dashboard-editor-container {
padding: 32px;
background-color: rgb(240, 242, 245);
position: relative;
.chart-wrapper {
background: #fff;
padding: 16px 16px 0;
margin-bottom: 32px;
}
}
@media (max-width: 1024px) {
.chart-wrapper {
padding: 8px;
}
}
#main{
width:auto;
height: auto;
}
</style>
PanelGroup.vue
<template>
<el-row :gutter="40" class="panel-group">
<el-col :xs="12" :sm="12" :lg="6" class="card-panel-col">
<div class="card-panel" @click="handleSetLineChartData('inBound')">
<div class="card-panel-icon-wrapper icon-people">
<svg-icon icon-class="in" class-name="card-panel-icon" />
</div>
<div class="card-panel-description">
<div class="card-panel-text">
数量一
</div>
<count-to :start-val="0" :end-val="data.inBoundTotal" :duration="2600" class="card-panel-num" />
</div>
</div>
</el-col>
<el-col :xs="12" :sm="12" :lg="6" class="card-panel-col">
<div class="card-panel" @click="handleSetLineChartData('outBound')">
<div class="card-panel-icon-wrapper icon-message">
<svg-icon icon-class="out" class-name="card-panel-icon" />
</div>
<div class="card-panel-description">
<div class="card-panel-text">
数量二
</div>
<count-to :start-val="0" :end-val="data.outBoundTotal" :duration="3000" class="card-panel-num" />
</div>
</div>
</el-col>
<el-col :xs="12" :sm="12" :lg="6" class="card-panel-col">
<div class="card-panel" @click="handleSetLineChartData('returnBound')">
<div class="card-panel-icon-wrapper icon-money">
<svg-icon icon-class="returnDetail" class-name="card-panel-icon" />
</div>
<div class="card-panel-description">
<div class="card-panel-text">
数量三
</div>
<count-to :start-val="0" :end-val="data.returnBoundTotal" :duration="3200" class="card-panel-num" />
</div>
</div>
</el-col>
<el-col :xs="12" :sm="12" :lg="6" class="card-panel-col">
<div class="card-panel" @click="handleSetLineChartData('inventory')">
<div class="card-panel-icon-wrapper icon-shopping">
<svg-icon icon-class="international" class-name="card-panel-icon" />
</div>
<div class="card-panel-description">
<div class="card-panel-text">
数量四
</div>
<count-to :start-val="0" :end-val="data.inventoryTotal" :duration="3600" class="card-panel-num" />
</div>
</div>
</el-col>
</el-row>
</template>
<script>
import CountTo from 'vue-count-to'
export default {
props: {
data: {
typeof: Object,//数据类型
required: true//必须的
}
},
components: {
CountTo
},
created() {
console.log("数量数据:",this.data)
},
methods: {
handleSetLineChartData(type) {
this.$emit('handleSetLineChartData', type)
}
}
}
</script>
<style lang="scss" scoped>
.panel-group {
margin-top: 18px;
.card-panel-col {
margin-bottom: 32px;
}
.card-panel {
height: 108px;
cursor: pointer;
font-size: 12px;
position: relative;
overflow: hidden;
color: #666;
background: #fff;
box-shadow: 4px 4px 40px rgba(0, 0, 0, .05);
border-color: rgba(0, 0, 0, .05);
&:hover {
.card-panel-icon-wrapper {
color: #fff;
}
.icon-people {
background: #40c9c6;
}
.icon-message {
background: #36a3f7;
}
.icon-money {
background: #f4516c;
}
.icon-shopping {
background: #34bfa3
}
}
.icon-people {
color: #40c9c6;
}
.icon-message {
color: #36a3f7;
}
.icon-money {
color: #f4516c;
}
.icon-shopping {
color: #34bfa3
}
.card-panel-icon-wrapper {
float: left;
margin: 14px 0 0 14px;
padding: 16px;
transition: all 0.38s ease-out;
border-radius: 6px;
}
.card-panel-icon {
float: left;
font-size: 48px;
}
.card-panel-description {
float: right;
font-weight: bold;
margin: 26px;
margin-left: 0px;
.card-panel-text {
line-height: 18px;
color: rgba(0, 0, 0, 0.45);
font-size: 16px;
margin-bottom: 12px;
}
.card-panel-num {
font-size: 20px;
}
}
}
}
@media (max-width:550px) {
.card-panel-description {
display: none;
}
.card-panel-icon-wrapper {
float: none !important;
width: 100%;
height: 100%;
margin: 0 !important;
.svg-icon {
display: block;
margin: 14px auto !important;
float: none !important;
}
}
}
</style>
LineChart.vue
这个有点问题,不知道为什么watch检测不到数据变化,所以使用了定时器。
<template>
<div :class="className" :style="{height:height,width:width}"/>
</template>
<script>
import * as echarts from 'echarts'
require('echarts/theme/macarons') // echarts theme
import resize from './mixins/resize'
export default {
mixins: [resize],
props: {
className: {
type: String,
default: 'chart'
},
width: {
type: String,
default: '98%'
},
height: {
type: String,
default: '350px'
},
autoResize: {
type: Boolean,
default: true
},
chartData: {
type: Object,
required: true
}
},
data() {
return {
chart: null,
needData: [],
displayName:'出库量',
timerId: null
}
},
// watch: {
// chartData: {
// // deep: true,
// handler(val) {
// // this.setOptions(val)
// this.initChart();
// console.log("watch检测到数据变化,")
// }
// }
// },
/* watch: {
chartData(newValue, oldValue) {
console.log('Message changed from', oldValue, 'to', newValue);
}
},*/
mounted() {
// 启动定时器
this.timerId = setInterval(this.yourMethod, 500); // 每1000毫秒调用一次yourMethod方法
this.$nextTick(() => {
this.initChart();
console.log("chartData:", this.chartData)
console.log("chartData:", this.chartData.dateData)
console.log("chartData:", this.chartData.inBound)
this.getData();
console.log("进入页面折线图展示的数据",this.needData)
})
},
beforeDestroy() {
if (!this.chart) {
return
}
this.chart.dispose()
this.chart = null
// 清除定时器
if (this.timerId) {
clearInterval(this.timerId);
}
},
methods: {
yourMethod() {
// 你的方法逻辑
// console.log('定时器触发的方法',this.chartData);
this.getData();
this.setOptions(this.needData);
},
initChart() {
this.chart = echarts.init(this.$el, 'macarons')
this.getData();
// this.setOptions(this.chartData.inBound)
this.setOptions(this.needData);
console.log("初始化chartData数据", this.chartData)
console.log("展示数据", this.needData)
},
getData() {
if (this.chartData.type === "inventory") {
this.needData = this.chartData.inventory;
this.displayName="数量一"
} else if (this.chartData.type === "inBound") {
this.needData = this.chartData.inBound;
this.displayName="数量二"
} else if (this.chartData.type === "outBound") {
this.needData = this.chartData.outBound;
this.displayName="数量三"
} else {
this.needData = this.chartData.returnBound;
this.displayName="数量四"
}
},
setOptions() {
this.chart.setOption({
xAxis: {
// data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
//留取后五位
data: this.chartData.dateData.map(date => date.substr(-5)),
boundaryGap: false,
//有竖线
// splitLine: {
// show: true,
// lineStyle: {
// color: "rgba(31,99,163,.5)",
// },
// },
axisLine: {
// show:false,
lineStyle: {
color: "rgba(31,99,163,.5)",
},
},
axisLabel: {
color: "#7EB7FD",
fontWeight: "500",
},
axisTick: {
show: false
}
},
grid: {
//布局
show: true,
left: 10,
right: 10,
bottom: 20,
top: 30,
containLabel: true,
borderColor: "#1F63A3",
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross'
},
padding: [5, 10]
},
yAxis: {
//有横线
splitLine: {
show: true,
lineStyle: {
color: "rgba(213,188,143,0.1)",
},
},
axisLine: {
lineStyle: {
//横着指示线颜色
color: "rgba(31,99,163,.5)",
},
},
axisLabel: {
color: "#7EB7FD",
fontWeight: "500",
},
axisTick: {
show: false
},
},
legend: {
data: ['11', '22']
},
series: [
{
name: this.displayName,
smooth: true,
type: 'line',
itemStyle: {
normal: {
color: '#3888fa',
lineStyle: {
color: '#3888fa',
width: 2
},
areaStyle: {
color: '#f3f8ff'
}
}
},
data: this.needData,
animationDuration: 2800,
animationEasing: 'quadraticOut',
//最大值点
markPoint: {
data: [
{
name: "最大值",
type: "max",
valueDim: "y",
symbol: "rect",
symbolSize: [60, 26],
symbolOffset: [0, -20],
itemStyle: {
color: "rgba(0,0,0,0)",
},
label: {
color: "#107efc",
backgroundColor: "rgba(0,102,204,0.1)",
borderRadius: 6,
padding: [7, 14],
borderWidth: 0.5,
borderColor: "rgba(4,35,114,0.5)",
formatter: this.displayName+":{c}",
},
},
{
name: "最大值",
type: "max",
valueDim: "y",
symbol: "circle",
symbolSize: 6,
itemStyle: {
color: "#2f5eb6",//最大点
shadowColor: "#2f5eb6",
shadowBlur: 8,
},
label: {
formatter: "",
},
},
],
},
}
]
})
}
}
}
</script>
记录学习日常~
有大佬晓得为什么watch不生效可以留言~