效果图:
<template>
<!-- 天气预报 -->
<div>
<el-popover
placement="bottom"
popper-class="weather-popver"
title=""
trigger="click"
@hide="handleHideWeather"
>
<div class="bigWeather">
<div class="bigWeather-top">
<div class="bigWeather-top-txt1">
<span>当前天气</span>
<span> | </span>
<img class="bigWeather-top-icon1" src="@/assets/icon/icon-focus.svg">
<span> {{ currentWeather.areaName }}</span>
</div>
<div class="bigWeather-top-txt2">
<div class="bigWeather-top-txt2-1">{{ currentWeather.avgTemperature }}°</div>
<div class="bigWeather-top-txt2-2">{{ currentWeather.dayWeather }}</div>
</div>
<div class="bigWeather-top-txt3">
<div class="bigWeather-top-txt3-1">{{ currentWeather.minTemperature }}~{{ currentWeather.maxTemperature }}°C</div>
<div class="bigWeather-top-txt3-2">{{ currentWeather.dayWindDirection }}</div>
<!-- <div class="bigWeather-top-txt3-3">
<img class="bigWeather-top-txt3-3-1-img" src="@/assets/icon/icon-kq.svg">
<div class="bigWeather-top-txt3-3-1">空气 优</div>
</div> -->
</div>
<img class="bigWeather-top-txt4" :src="handleWeatherSrc(currentWeather.dayWeather)">
</div>
<div class="bigWeather-bottom">
<div ref="PieChart" class="bigWeather-bottom-echarts"></div>
<img class="bigWeather-bottom-l" src="@/assets/icon/icon little-unfold-r.svg" @click="scrollToLeft" v-if="!tabScrollShow">
<img class="bigWeather-bottom-r" v-if="tabScrollShow" src="@/assets/icon/icon little-unfold-l.svg" @click="scrollToRight">
</div>
</div>
<template #reference>
<div :class="defaultClass=='weather-div'?'weather-div':defaultClass" @click="clickWeather">
<img class="weather-icon" v-if="handleWeatherSrc(defaultValue.dayWeather)" :src="handleWeatherSrc(defaultValue.dayWeather)">
<span class="weather-txt1" v-if="defaultValue.avgTemperature">{{defaultValue.avgTemperature}}°</span>
<span class="weather-txt2">{{defaultValue.dayWeather}}|{{defaultValue.minTemperature}}~{{defaultValue.maxTemperature}}°C</span>
<img class="weather-icon1" v-if="!weatherVisible" src="@/assets/icon/icon-shouqi222.svg">
<img class="weather-icon2" v-if="weatherVisible" src="@/assets/icon/icon-shouqi222.svg">
</div>
</template>
</el-popover>
</div>
</template>
<script>
import * as api from '@apis/common'
import * as echarts from 'echarts'
import clearSkyIcon from '../../../assets/icon/weather/icon-晴天.png'
import blizzardIcon from '../../../assets/icon/weather/icon-暴雪.png'
import heavyRainIcon from '../../../assets/icon/weather/icon-暴雨.png'
import hailIcon from '../../../assets/icon/weather/icon-冰雹.png'
import extremeHeavyRainIcon from '../../../assets/icon/weather/icon-大暴雨.png'
import heavySnowIcon from '../../../assets/icon/weather/icon-大雪.png'
import rainIcon from '../../../assets/icon/weather/icon-大雨.png'
import freezingRainIcon from '../../../assets/icon/weather/icon-冻雨.png'
import cloudyIcon from '../../../assets/icon/weather/icon-多云.png'
import dustIcon from '../../../assets/icon/weather/icon-浮尘.png'
import frostIcon from '../../../assets/icon/weather/icon-降霜.png'
import thunderstormRainIcon from '../../../assets/icon/weather/icon-雷阵雨.png'
import hazeIcon from '../../../assets/icon/weather/icon-霾.png'
import severeDustStormIcon from '../../../assets/icon/weather/icon-强沙尘暴.png'
import dustStormIcon from '../../../assets/icon/weather/icon-沙尘暴.png'
import torrentialRainIcon from '../../../assets/icon/weather/icon-特大暴雨.png'
import darkCloudsIcon from '../../../assets/icon/weather/icon-乌云.png'
import fogIcon from '../../../assets/icon/weather/icon-雾天.png'
import lightSnowIcon from '../../../assets/icon/weather/icon-小雪.png'
import lightRainIcon from '../../../assets/icon/weather/icon-小雨.png'
import sandIcon from '../../../assets/icon/weather/icon-扬沙.png'
import nightIcon from '../../../assets/icon/weather/icon-夜晚.png'
import overcastIcon from '../../../assets/icon/weather/icon-阴天.png'
import drizzleIcon from '../../../assets/icon/weather/icon-阴雨.png'
import raindropIcon from '../../../assets/icon/weather/icon-雨.png'
import sleetIcon from '../../../assets/icon/weather/icon-雨夹雪.png'
import snowShowerIcon from '../../../assets/icon/weather/icon-阵雪.png'
import rainShowerIcon from '../../../assets/icon/weather/icon-阵雨.png'
import moderateSnowIcon from '../../../assets/icon/weather/icon-中雪.png'
import moderateRainIcon from '../../../assets/icon/weather/icon-中雨.png'
export default {
name: 'Weather',
components: {
},
directives: {},
props: {
defaultValue: {
type: Object,
default: () => ({})
},
defaultClass: {
type: String,
default() {
return 'weather-div'
}
}
},
filters: {},
provide: {},
mixins: [],
data() {
return {
weatherVisible: false,
currentPointInfo: null,
tabScrollShow: true,
currentWeather: {}
}
},
created() {
},
methods: {
handleHideWeather() {
this.weatherVisible = false
},
clickWeather() {
const t = this
if (t.weatherVisible) return
t.weatherVisible = true
t.tabScrollShow = true
const req = {
data: t.defaultValue.datekey,
shopNo: t.defaultValue.shopNo
}
api.weatherInfo(req).then((res) => {
for (const i in res.data) {
// eslint-disable-next-line eqeqeq
if (res.data[i].weekNickName == '今天') {
t.currentWeather = res.data[i]
}
}
setTimeout(() => {
const chartDom = t.$refs.PieChart
t.myChart = echarts.init(chartDom)
t.myChart.setOption(t.replaceOptionPie(res.data))
// 监听图表的全局点击事件
t.myChart.getZr().on('click', (event) => {
const pointInPixel = [event.offsetX, event.offsetY]
const pointInGrid = t.myChart.convertFromPixel({ seriesIndex: 0 }, pointInPixel)
const xIndex = Math.round(pointInGrid[0])
if (xIndex >= 0 && xIndex < t.myChart.getOption().xAxis[0].data.length) {
if (t.currentPointInfo) {
res.data.map((j) => {
if (j.weekNickName === t.currentPointInfo[0].name.split(' ')[0]) {
t.currentWeather = j
}
})
// 在这里处理点击事件
}
}
})
// 监听 dataZoom 事件
t.myChart.on('dataZoom', (params) => {
console.log('params', params)
let startIndex = ''
let endIndex = ''
if (params.endValue) { // 直接点击箭头滚动
startIndex = params.startValue
endIndex = params.endValue
} else { // 鼠标滚轮滚动
const dataLength = res.data.length
startIndex = Math.round((params.batch[0].start / 100) * dataLength)
endIndex = Math.round((params.batch[0].end / 100) * dataLength)
}
console.log('startIndex', startIndex, endIndex)
// 更新 rich 属性
const newRich = t.handleWeatherIcon(res.data.slice(startIndex, endIndex + 1))
t.myChart.setOption({
xAxis: [
{
axisLabel: {
rich: newRich
}
},
{
axisLabel: {
rich: newRich
}
}
]
})
})
// 实现窗口变化时,图表的自适应
window.addEventListener('resize', () => {
t.myChart.resize()
})
}, 100)
})
},
replaceOptionPie(list) {
const t = this
return {
dataZoom: [
{
// 设置滚动条的隐藏与显示
show: false,
// 设置滚动条类型
type: 'slider',
// 数据窗口范围的起始数值
startValue: 0,
// 数据窗口范围的结束数值(一页显示多少条数据)
endValue: 7,
// 是否锁定选择区域(或叫做数据窗口)的大小
zoomLoxk: true,
// 控制手柄的尺寸
handleSize: 0,
// dataZoom-slider组件离容器下侧的距离
bottom: 3
},
{
// 没有下面这块的话,只能拖动滚动条,
// 鼠标滚轮在区域内不能控制外部滚动条
type: 'inside',
// 滚轮是否触发缩放
zoomOnMouseWheel: false,
// 鼠标滚轮触发滚动
moveOnMouseMove: false,
moveOnMouseWheel: false
}
],
grid: {
left: '5%',
right: '5%',
backgroundColor: 'transparent',
bottom: '3%',
top: '5px',
containLabel: true
},
tooltip: {
trigger: 'axis',
borderWidth: 2,
backgroundColor: 'rgba(50, 50, 50, 0.7)', // 设置背景颜色
textStyle: {
color: '#fff' // 设置文字颜色
},
formatter(params) {
t.currentPointInfo = params // 保存当前点的信息
return '' // 不显示提示内容
},
axisPointer: {
type: 'shadow', // 使用阴影指示器
shadowStyle: {
z: -1,
color: 'rgba(238, 248, 255, 0.2)' // 设置阴影颜色
}
}
},
xAxis: [
{
type: 'category',
boundaryGap: false,
position: 'top',
offset: 70,
zlevel: 100,
axisLine: {
show: false
},
axisTick: {
show: false
},
splitLine: {
show: false
},
axisLabel: {
fontFamily: 'D-DIN,SAN-SERIF',
fontSize: '12px',
fontWeight: 'normal',
interval: 0,
color: '#081836',
formatter(value) {
// 将 ' ' 替换为 '\n' 进行换行
return value.replace(' ', '\n')
}
},
// 日期数据
data: t.handleXaxis(list)
},
{
type: 'category',
boundaryGap: false,
position: 'top',
offset: 20,
zlevel: 100,
axisLine: {
show: false
},
axisTick: {
show: false
},
splitLine: {
show: false
},
axisLabel: {
interval: 0,
formatter(value, index) {
// 使用富文本标签来显示图标
return `{${index}| }\n{icon|}`
},
rich: t.handleWeatherIcon(list)
},
data: t.handleXaxis(list)
},
{
type: 'category',
boundaryGap: false,
position: 'top',
offset: 0,
zlevel: 100,
axisLine: {
show: false
},
axisTick: {
show: false
},
splitLine: {
show: false
},
axisLabel: {
fontFamily: 'D-DIN,SAN-SERIF',
fontSize: '12px',
fontWeight: 'normal',
interval: 0,
color: '#081836',
formatter(value) {
return `${value}℃`
}
},
// 日期数据
data: t.handleMaxWeatherList(list)
},
{
type: 'category',
boundaryGap: false,
position: 'bottom',
offset: 0,
zlevel: 100,
axisLine: {
show: false
},
axisTick: {
show: false
},
splitLine: {
show: false
},
axisLabel: {
fontFamily: 'D-DIN,SAN-SERIF',
fontSize: '12px',
fontWeight: 'normal',
interval: 0,
color: '#081836',
formatter(value) {
return `${value}℃`
}
},
// 日期数据
data: t.handleMaxWeatherList(list)
}
],
yAxis: [
{
type: 'value',
min: t.handleLineMin(list),
max: t.handleLineMax(list),
axisLine: { show: false },
axisTick: { show: false },
axisLabel: { show: false },
splitLine: { show: false }
}
],
series: [
{
name: '温度',
type: 'line',
connectNulls: true,
showSymbol: true, // 去除拐点,未划过时候
label: {
show: false,
color: '#54626F',
align: 'center',
formatter: '{c}℃'
},
lineStyle: {
color: '#D1D9E0'
},
labelLayout(params) {
return {
x: params.rect.x - params.rect.width,
y: params.rect.y < params.rect.height * 2 ? params.rect.y + params.rect.height * 3 : params.rect.y - params.rect.height,
verticalAlign: 'middle',
align: 'left'
}
},
itemStyle: {
normal: {
color: '#D1D9E0',
borderColor: '#D1D9E0',
borderWidth: 2, // 描边的线宽
lineStyle: {
color: '#D1D9E0', // 折线颜色
width: 2 // 折线宽度
}
}
},
data: t.handleLineData(list)
}
]
}
},
// 处理X轴
handleXaxis(list) {
const arr = []
list.map((i) => {
arr.push(`${i.weekNickName} ${i.datekey.slice(-4)}`)
})
return arr
},
// 处理图表折现图的最大值
handleLineMax(list) {
const arr = []
list.map((i) => {
arr.push(i.avgTemperature)
})
return Math.max(...arr) + 2
},
// 处理图表折现图的最小值
handleLineMin(list) {
const arr = []
list.map((i) => {
arr.push(i.avgTemperature)
})
return Math.min(...arr) - 2
},
// 处理折线图数据
handleLineData(list) {
const arr = []
list.map((i) => {
arr.push(i.avgTemperature)
})
return arr
},
// 处理天气折现图标显示
handleWeatherIcon(list) {
const t = this
const rich = {}
list.forEach((item, index) => {
rich[index] = {
backgroundColor: {
image: t.handleWeatherSrc(item.dayWeather)
},
height: 32,
width: 32
}
})
return rich
},
// 获取天气最高温度数组
handleMaxWeatherList(list) {
const arr = []
list.map((i) => {
arr.push(i.maxTemperature)
})
return arr
},
// 获取天气最高温度数组
handleMinWeatherList(list) {
const arr = []
list.map((i) => {
arr.push(i.minTemperature)
})
return arr
},
handleWeatherSrc(type) {
const weatherImages = {
晴: clearSkyIcon,
霾: hazeIcon,
暴雪: blizzardIcon,
小雨: lightRainIcon,
多云: cloudyIcon,
大到暴雨: heavyRainIcon,
雷阵雨: thunderstormRainIcon,
中雪: moderateSnowIcon,
冻雨: freezingRainIcon,
沙尘暴: dustStormIcon,
扬沙: sandIcon,
中到大雨: rainIcon,
小到中雪: moderateSnowIcon,
强沙尘暴: severeDustStormIcon,
阴: overcastIcon,
阵雨: rainShowerIcon,
雾: fogIcon,
雷阵雨伴有冰雹: hailIcon,
大雪: heavySnowIcon,
暴雨到大暴雨: extremeHeavyRainIcon,
大雨: rainIcon,
阵雪: snowShowerIcon,
小到中雨: moderateRainIcon,
大暴雨: extremeHeavyRainIcon,
特大暴雨: torrentialRainIcon,
中到大雪: heavySnowIcon,
中雨: moderateRainIcon,
雨: raindropIcon,
雨夹雪: sleetIcon,
浮尘: dustIcon,
大到暴雪: blizzardIcon,
小雪: lightSnowIcon,
暴雨: heavyRainIcon,
降霜: frostIcon,
乌云: darkCloudsIcon,
夜晚: nightIcon,
阴雨: drizzleIcon
}
return weatherImages[type] || ''
},
scrollToLeft() {
if (this.myChart) {
this.tabScrollShow = !this.tabScrollShow
this.myChart.dispatchAction({
type: 'dataZoom',
startValue: 0,
endValue: 7
})
}
},
scrollToRight() {
if (this.myChart) {
this.tabScrollShow = !this.tabScrollShow
const xAxisData = this.myChart.getOption().xAxis[0].data
const endValue = xAxisData.length - 1
this.myChart.dispatchAction({
type: 'dataZoom',
startValue: endValue - 7,
endValue
})
}
}
}
}
</script>
<style lang="scss">
.weather-div {
display: flex;
align-items: center;
height: 2.865vw;
padding-left: 0.8333vw;
cursor: pointer;
position: absolute;
left: 0;
top: 0;
z-index: 20;
.weather-icon{
width:46px;
height:46px;
}
.weather-txt2{
font-family: Roboto-Bold;
font-size: 14px;
color: #FFFFFF;
letter-spacing: 0;
line-height: 16px;
font-weight: 700;
margin-left:4px;
}
.weather-txt1 {
font-family: Roboto-BoldCondensed;
font-size: 1.66667vw;
color: #FFFFFF;
letter-spacing: 0;
font-weight: 700;
margin-right: 0.2083vw;
margin-left:10px;
}
.weather-echarts{
width: 25vw;
height:5.208vw;
padding-top:1.8vw;
}
}
.weather-popver {
padding: 0 !important;
width: 552px !important;
.bigWeather {
width: 100%;
height: fit-content;
.bigWeather-top {
width: 100%;
padding-left: 32px;
padding-top: 32px;
padding-bottom: 18px;
background-image: linear-gradient(0deg, #F5FBFF 0%, #EAF7FF 100%);
border-radius: 4px 4px 0px 0px;
position: relative;
.bigWeather-top-txt1 {
font-family: PingFangSC-Regular;
font-size: 12px;
color: #54626F;
letter-spacing: 0;
line-height: 14px;
font-weight: 400;
.bigWeather-top-icon1 {
width: 14px;
height: 14px;
}
}
.bigWeather-top-txt2 {
margin-top: 16px;
display: flex;
align-items: flex-end;
.bigWeather-top-txt2-1 {
font-family: Roboto-BoldCondensed;
font-size: 56px;
color: #081836;
letter-spacing: 0;
line-height: 56px;
font-weight: 700;
margin-right: 9px;
}
.bigWeather-top-txt2-2 {
font-family: PingFangSC-Medium;
font-size: 16px;
color: #081836;
letter-spacing: 0;
line-height: 20px;
font-weight: 500;
}
}
.bigWeather-top-txt3 {
margin-top: 18px;
display: flex;
align-items: center;
.bigWeather-top-txt3-1 {
font-family: Roboto-Regular;
font-size: 16px;
color: #081836;
letter-spacing: 0;
line-height: 20px;
font-weight: 400;
margin-right: 16px;
}
.bigWeather-top-txt3-2 {
font-family: Roboto-Regular;
font-size: 16px;
color: #081836;
letter-spacing: 0;
line-height: 20px;
font-weight: 400;
margin-right: 16px;
}
.bigWeather-top-txt3-3 {
display: flex;
align-items: center;
flex-wrap: nowrap;
background: #DFF0FF;
border-radius: 4px;
padding: 2px 6px;
.bigWeather-top-txt3-3-1-img {
width: 9px;
height: 10px;
margin-right: 3.5px;
}
.bigWeather-top-txt3-3-1 {
font-family: PingFangSC-Regular;
font-size: 12px;
color: #0581E3;
letter-spacing: 0;
line-height: 16px;
font-weight: 400;
}
}
}
.bigWeather-top-txt4 {
width: 112px;
height: 112px;
position: absolute;
top: 24px;
right: 46px;
}
}
.bigWeather-bottom {
width: 100%;
height: fit-content;
padding: 24px;
position: relative;
.bigWeather-bottom-echarts {
width: 100%;
height: 214px;
}
.bigWeather-bottom-l {
background: rgba(255, 255, 255, 0.80);
box-shadow: 0px 2px 6px 0px rgba(0, 0, 0, 0.16);
width: 30px;
height: 30px;
border-radius: 50%;
position: absolute;
left: 9px;
top: 110px;
cursor: pointer;
}
.bigWeather-bottom-r {
background: rgba(255, 255, 255, 0.80);
box-shadow: 0px 2px 6px 0px rgba(0, 0, 0, 0.16);
width: 30px;
height: 30px;
border-radius: 50%;
position: absolute;
right: 9px;
top: 110px;
cursor: pointer;
}
}
}
}
</style>