学习前端还是非常有意思的,因为前端真的是可见即所得,可以做出来非常好看漂亮的页面,最近我就在使用前端技术 做一些大屏报表,在制作这些大屏报表过程中,又熟练的练习了自己的学到的相关的前端技术,接下来把做出来的效果 分享给大家。主要做的是一个图书资源相关的数据大屏展示。
使用的技术是vue2 + element-ui
· Vue2
· Element-UI
· ECharts
· Node版本 16.20
安装依赖:npm i
运行项目:npm run serve
打包项目:npm run build
介绍了使用的技术后,接下来给大家看一下页面效果
因为是练习项目,为了熟练的对ECharts插件的使用。只做了一个页面。
部分代码
<template>
<div class="home">
<Header />
<div class="dashboard-container">
<!-- 左侧面板 -->
<div class="left-panel">
<div class="panel-item">
<div class="panel-header">图书分类统计</div>
<div class="chart-container" ref="categoryChart"></div>
</div>
<div class="panel-item">
<div class="panel-header">读者年龄分布</div>
<div class="chart-container" ref="ageChart"></div>
</div>
</div>
<!-- 中间面板 -->
<div class="center-panel">
<div class="panel-item map-container">
<div class="panel-header">全国图书馆分布</div>
<div class="chart-container" ref="mapChart"></div>
</div>
<div class="data-overview">
<div class="data-card" v-for="(item, index) in dataCards" :key="index">
<div class="data-icon" :style="{backgroundColor: item.color}">
<i :class="item.icon"></i>
</div>
<div class="data-info">
<div class="data-title">{{item.title}}</div>
<div class="data-value">{{item.value}}</div>
</div>
</div>
</div>
</div>
<!-- 右侧面板 -->
<div class="right-panel">
<div class="panel-item">
<div class="panel-header">借阅趋势分析</div>
<div class="chart-container" ref="trendChart"></div>
</div>
<div class="panel-item">
<div class="panel-header">热门排行榜</div>
<div class="rank-list-container">
<div class="rank-list-scroll" ref="rankList">
<div class="rank-item" v-for="(book, index) in hotBooks" :key="index">
<div class="rank-number" :class="{'top-three': index < 3}">{{index + 1}}</div>
<div class="book-info">
<div class="book-name">{{book.name}}</div>
<div class="book-author">{{book.author}}</div>
</div>
<div class="book-borrow-count">{{book.count}}次</div>
</div>
<!-- 复制一份列表用于无缝滚动 -->
<div class="rank-item" v-for="(book, index) in hotBooks" :key="'copy-'+index">
<div class="rank-number" :class="{'top-three': index < 3}">{{index + 1}}</div>
<div class="book-info">
<div class="book-name">{{book.name}}</div>
<div class="book-author">{{book.author}}</div>
</div>
<div class="book-borrow-count">{{book.count}}次</div>
</div>
</div>
</div>
</div>
</div>
</div>
<Footer />
</div>
</template>
<script>
/**
* 作者:json
*/
import Header from '../components/Header.vue'
import Footer from '../components/Footer.vue'
import { echarts, createChart, getCommonOptions, getGradientColor } from '../utils/echarts-helper'
import 'echarts/map/js/china'
export default {
name: 'Home',
components: {
Header,
Footer
},
data() {
return {
// 数据卡片
dataCards: [
{ title: '图书总量', value: '2,568,321', icon: 'el-icon-reading', color: '#1890ff' },
{ title: '读者总数', value: '1,245,689', icon: 'el-icon-user', color: '#52c41a' },
{ title: '今日借阅', value: '12,456', icon: 'el-icon-date', color: '#faad14' },
{ title: '电子资源', value: '856,932', icon: 'el-icon-document', color: '#f5222d' }
],
// 热门排行
hotBooks: [
{ name: '001', author: 'xxx作者1', count: 12568 },
{ name: '002', author: 'xxx作者2', count: 10234 },
{ name: '003', author: 'xxx作者3', count: 9872 },
{ name: '004', author: 'xxx作者4', count: 8765 },
{ name: '005', author: 'xxx作者5', count: 7654 },
{ name: '006', author: 'xxx作者6', count: 6543 },
{ name: '007', author: 'xxx作者7', count: 5432 },
{ name: '008', author: 'xxx作者8', count: 4321 }
],
// 图表实例
charts: {}
}
},
mounted() {
this.initCharts()
// 窗口大小变化时重新调整图表大小
window.addEventListener('resize', this.resizeCharts)
// 初始化排行榜滚动暂停功能
this.$nextTick(() => {
this.initRankListScroll()
})
},
beforeDestroy() {
// 组件销毁前移除事件监听
window.removeEventListener('resize', this.resizeCharts)
// 移除排行榜滚动相关的事件监听
if (this.$refs.rankList) {
this.$refs.rankList.removeEventListener('mouseenter', this.pauseRankScroll)
this.$refs.rankList.removeEventListener('mouseleave', this.resumeRankScroll)
}
// 销毁图表实例
Object.keys(this.charts).forEach(key => {
if (this.charts[key]) {
this.charts[key].dispose()
}
})
},
methods: {
// 初始化所有图表
initCharts() {
this.$nextTick(() => {
this.initCategoryChart()
this.initAgeChart()
this.initMapChart()
this.initTrendChart()
})
},
// 图书分类统计图表
initCategoryChart() {
const { chart } = createChart(this.$refs.categoryChart)
this.charts.category = chart
const option = {
...getCommonOptions(),
tooltip: {
trigger: 'item',
formatter: '{a} <br/>{b}: {c} ({d}%)'
},
legend: {
orient: 'vertical',
right: 10,
top: 'center',
textStyle: { color: '#fff' }
},
series: [
{
name: '图书分类',
type: 'pie',
radius: ['50%', '70%'],
avoidLabelOverlap: false,
label: {
show: false,
position: 'center'
},
emphasis: {
label: {
show: true,
fontSize: '18',
fontWeight: 'bold'
}
},
labelLine: {
show: false
},
data: [
{ value: 1048, name: '文学' },
{ value: 735, name: '历史' },
{ value: 580, name: '科技' },
{ value: 484, name: '艺术' },
{ value: 300, name: '教育' },
{ value: 200, name: '经济' }
],
itemStyle: {
borderWidth: 2,
borderColor: 'rgba(255, 255, 255, 0.1)'
}
}
]
}
chart.setOption(option)
},
// 读者年龄分布图表
initAgeChart() {
const { chart } = createChart(this.$refs.ageChart)
this.charts.age = chart
const option = {
...getCommonOptions(),
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
},
xAxis: [
{
type: 'category',
data: ['<18岁', '18-25岁', '26-35岁', '36-45岁', '46-60岁', '>60岁'],
axisTick: {
alignWithLabel: true
}
}
],
yAxis: [
{
type: 'value'
}
],
series: [
{
name: '读者人数',
type: 'bar',
barWidth: '60%',
data: [15000, 42000, 35000, 28000, 16000, 9000],
itemStyle: {
color: getGradientColor('rgba(131, 191, 246, 1)', 'rgba(24, 141, 240, 1)')
}
}
]
}
chart.setOption(option)
},
// 全国图书馆分布地图
initMapChart() {
const { chart } = createChart(this.$refs.mapChart)
this.charts.map = chart
// 模拟数据
const data = [
{ name: '北京', value: 156 },
{ name: '天津', value: 89 },
{ name: '上海', value: 178 },
{ name: '重庆', value: 95 },
{ name: '河北', value: 125 },
{ name: '河南', value: 132 },
{ name: '云南', value: 86 },
{ name: '辽宁', value: 93 },
{ name: '黑龙江', value: 78 },
{ name: '湖南', value: 112 },
{ name: '安徽', value: 96 },
{ name: '山东', value: 145 },
{ name: '新疆', value: 56 },
{ name: '江苏', value: 158 },
{ name: '浙江', value: 168 },
{ name: '江西', value: 82 },
{ name: '湖北', value: 105 },
{ name: '广西', value: 76 },
{ name: '甘肃', value: 58 },
{ name: '山西', value: 72 },
{ name: '内蒙古', value: 63 },
{ name: '陕西', value: 89 },
{ name: '吉林', value: 65 },
{ name: '福建', value: 98 },
{ name: '贵州', value: 71 },
{ name: '广东', value: 172 },
{ name: '青海', value: 42 },
{ name: '西藏', value: 35 },
{ name: '四川', value: 125 },
{ name: '宁夏', value: 38 },
{ name: '海南', value: 59 },
{ name: '台湾', value: 86 },
{ name: '香港', value: 32 },
{ name: '澳门', value: 12 }
]
const option = {
...getCommonOptions(),
tooltip: {
trigger: 'item',
formatter: '{b}<br/>图书馆数量:{c}'
},
visualMap: {
min: 0,
max: 200,
left: 'left',
top: 'bottom',
text: ['高', '低'],
inRange: {
color: ['#e0f7fa', '#4fc3f7', '#0288d1']
},
textStyle: {
color: '#fff'
}
},
series: [
{
name: '图书馆数量',
type: 'map',
map: 'china',
roam: true,
emphasis: {
label: {
show: true
}
},
itemStyle: {
areaColor: '#0f1c3c',
borderColor: 'rgba(65, 120, 255, 0.5)',
borderWidth: 1
},
data: data
}
]
}
chart.setOption(option)
},
// 借阅趋势分析图表
initTrendChart() {
const { chart } = createChart(this.$refs.trendChart)
this.charts.trend = chart
const option = {
...getCommonOptions(),
tooltip: {
trigger: 'axis'
},
legend: {
data: ['实体图书', '电子图书'],
textStyle: {
color: '#fff'
}
},
xAxis: {
type: 'category',
boundaryGap: false,
data: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月']
},
yAxis: {
type: 'value'
},
series: [
{
name: '实体图书',
type: 'line',
stack: '总量',
smooth: true,
symbol: 'circle',
symbolSize: 5,
showSymbol: false,
lineStyle: {
width: 2
},
areaStyle: {
color: getGradientColor('rgba(80, 141, 255, 0.8)', 'rgba(80, 141, 255, 0.1)')
},
emphasis: {
focus: 'series'
},
data: [12000, 13200, 15100, 14500, 13800, 14900, 18000, 21000, 20500, 19200, 18300, 23500]
},
{
name: '电子图书',
type: 'line',
stack: '总量',
smooth: true,
symbol: 'circle',
symbolSize: 5,
showSymbol: false,
lineStyle: {
width: 2
},
areaStyle: {
color: getGradientColor('rgba(255, 180, 0, 0.8)', 'rgba(255, 180, 0, 0.1)')
},
emphasis: {
focus: 'series'
},
data: [8200, 9320, 9010, 10340, 12800, 14300, 15200, 16500, 17800, 18100, 19500, 22000]
}
]
}
chart.setOption(option)
},
// 调整图表大小
resizeCharts() {
Object.keys(this.charts).forEach(key => {
this.charts[key].resize()
})
},
// 初始化排行榜滚动
initRankListScroll() {
if (this.$refs.rankList) {
// 添加鼠标悬停暂停滚动的事件
this.$refs.rankList.addEventListener('mouseenter', this.pauseRankScroll)
this.$refs.rankList.addEventListener('mouseleave', this.resumeRankScroll)
}
},
// 暂停排行榜滚动
pauseRankScroll() {
if (this.$refs.rankList) {
this.$refs.rankList.style.animationPlayState = 'paused'
}
},
// 恢复排行榜滚动
resumeRankScroll() {
if (this.$refs.rankList) {
this.$refs.rankList.style.animationPlayState = 'running'
}
}
}
}
</script>
<style scoped>
.home {
display: flex;
flex-direction: column;
height: 100vh;
background-color: #0f1c3c;
color: white;
overflow: hidden;
}
.dashboard-container {
flex: 1;
display: flex;
padding: 10px;
overflow: hidden;
}
.left-panel, .right-panel {
width: 25%;
display: flex;
flex-direction: column;
}
.center-panel {
width: 50%;
display: flex;
flex-direction: column;
}
.panel-item {
flex: 1;
margin: 5px;
background-color: rgba(13, 28, 61, 0.7);
border: 1px solid rgba(65, 120, 255, 0.3);
border-radius: 4px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
display: flex;
flex-direction: column;
overflow: hidden;
}
.panel-header {
height: 40px;
line-height: 40px;
padding: 0 15px;
font-size: 16px;
font-weight: bold;
background: linear-gradient(to right, rgba(15, 67, 132, 0.8), rgba(15, 67, 132, 0.2));
border-bottom: 1px solid rgba(65, 120, 255, 0.3);
}
.chart-container {
flex: 1;
width: 100%;
}
.map-container {
flex: 2;
}
.data-overview {
display: flex;
flex-wrap: wrap;
margin: 5px;
}
.data-card {
flex: 1;
min-width: calc(50% - 10px);
height: 100px;
margin: 5px;
background-color: rgba(13, 28, 61, 0.7);
border: 1px solid rgba(65, 120, 255, 0.3);
border-radius: 4px;
display: flex;
align-items: center;
padding: 0 15px;
}
.data-icon {
width: 50px;
height: 50px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin-right: 15px;
font-size: 24px;
color: white;
}
.data-info {
flex: 1;
}
.data-title {
font-size: 14px;
color: rgba(255, 255, 255, 0.7);
margin-bottom: 5px;
}
.data-value {
font-size: 22px;
font-weight: bold;
}
.rank-list-container {
flex: 1;
padding: 10px 15px;
overflow: hidden;
position: relative;
}
.rank-list-scroll {
position: absolute;
top: 0;
left: 0;
width: 100%;
padding: 5px 0;
animation: scrollRank 30s linear infinite;
}
@keyframes scrollRank {
0% {
transform: translateY(0);
}
100% {
transform: translateY(-50%);
}
}
/* 当鼠标悬停在容器上时,添加阴影效果 */
.rank-list-container:hover {
box-shadow: inset 0 0 10px rgba(65, 120, 255, 0.3);
}
.rank-item {
display: flex;
align-items: center;
padding: 10px 0;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
transition: background-color 0.3s;
}
.rank-item:hover {
background-color: rgba(65, 120, 255, 0.1);
}
.rank-number {
width: 24px;
height: 24px;
background-color: rgba(255, 255, 255, 0.1);
border-radius: 4px;
display: flex;
align-items: center;
justify-content: center;
margin-right: 10px;
font-size: 14px;
}
.top-three {
background-color: #f5a623;
color: #fff;
}
.book-info {
flex: 1;
}
.book-name {
font-size: 14px;
margin-bottom: 3px;
}
.book-author {
font-size: 12px;
color: rgba(255, 255, 255, 0.5);
}
.book-borrow-count {
font-size: 14px;
color: #f5a623;
}
/* 自定义滚动条 */
::-webkit-scrollbar {
width: 6px;
height: 6px;
}
::-webkit-scrollbar-track {
background: rgba(0, 0, 0, 0.1);
border-radius: 3px;
}
::-webkit-scrollbar-thumb {
background: rgba(65, 120, 255, 0.5);
border-radius: 3px;
}
::-webkit-scrollbar-thumb:hover {
background: rgba(65, 120, 255, 0.8);
}
</style>
如果对这个源码有兴趣可以去看看~ 源码地址: