最近项目需要做个简单的动画,如上图,框出来的图片需要上下浮动在Y轴上来回循环的移动,这个要用到如下css代码:
.active-image-7 {
animation: 5s float7 linear infinite normal;
}
@keyframes float7{
0% {
transform: translateY(0px);
}
50% {
transform: translateY(-10px);
}
100% {
transform: translateY(0px);
}
}
然后红色箭头处是来回循环的从左到右的循环往复流动的线条,UI给到的图是png格式的静态图片,如下图icon-line.png:
这就需要我们写CSS让其动起来。代码如下:
.active-part-11 {
animation: 9s rowup11 linear infinite normal;
position: absolute;
top: 0;
left: 0;
}
@keyframes rowup11 {
0% {
transform: translateX(-70px);
}
100% {
transform: translateX(60px);
display: none;
}
}
思路就是上面的思路了,由于我们页面上有很多种这些需要浮动的图片和线条,我们在template里需要v-for分别对deviceList和lineList进行遍历,然后在mounted里调用封装的动画方法addImageAnimation,需注意的是我们在addImageAnimation方法里通过 document.getElementsByClassName(“topo-chart-item”)获取dom节点,然后forEach遍历分别加动画样式,这里还涉及到了document.createElement(“style”)创建style元素,调用封装的randomNum方法等,当前组件完整代码如下:
<template>
<div class="topo-chart">
<div
class="tip-wrapper"
:style="{ top: item.top + 'px', left: item.left + 'px' }"
v-for="(item, index) in tipList"
:key="index + item.left"
>
{{ item.label }}
</div>
<div
class="topo-chart-item"
:class="'active-image-' + index"
v-show="!item.isHidden"
v-for="(item, index) in deviceList"
v-if="!item.isHidden"
:key="index + item.top + item.left"
:style="{ left: item.left + 'px', top: item.top + 'px' }"
>
<img
class="topo-chart-item-image"
@click="clickImage(item)"
:src="item.unnormal ? item.unnormalUrl : item.url"
:style="{ width: item.ImgWidth + 'px', height: item.ImgHeight + 'px' }"
/>
<div class="count-wrapper" v-if="item.count">
<span class="normal-count">{{ item.count.normal }}</span>
<span class="unnormal-count">{{ item.count.unnormal }}</span>
</div>
<div class="device-count-wrapper" v-if="item.deviceCount">
<span class="device-count">{{ item.deviceCount.count }}</span>
</div>
<p class="text-style">{{ item.label }}</p>
<p class="count-style" v-if="item.mainCount">
{{ item.mainCount.count }}
</p>
</div>
<div
class="topo-chart-line"
v-for="(item, index) in lineList"
:key="index"
:style="{
top: item.top + 'px',
left: item.left + 'px',
width: item.width + 'px',
height: item.height + 'px',
transform: item.deg ? `rotate(${item.deg}deg)` : 'none',
}"
v-show="!item.isHidden"
>
<img
class="active-part"
:style="{
transform: item.width > item.height ? 'none' : `rotate(90deg)`,
}"
:class="'active-part-' + index"
:src="
item.normal
? require('@/assets/images/devices/icon-line.png')
: require('@/assets/images/devices/icon-line-abnormal.png')
"
alt=""
/>
</div>
<div class="legend-wrapper">
<div class="legend-wrapper-line">
<img
class="legend-wrapper-line-image"
src="@/assets/images/devices/icon-line.png"
alt=""
/>
<p class="text">网络流向</p>
</div>
<div class="legend-wrapper-line">
<img
class="legend-wrapper-line-image"
src="@/assets/images/devices/icon-line-abnormal.png"
alt=""
/>
<p class="text">网络异常</p>
</div>
<div class="legend-wrapper-text">
<div class="run-count">
<span class="signal">x</span>
<span>运行数量</span>
</div>
<div class="online-count">
<span class="signal">x</span>
<span>在线数量</span>
</div>
<div class="offline-count">
<span class="signal">x</span>
<span>离线数量</span>
</div>
</div>
</div>
<div
class="back-wrapper"
v-if="
showBackButton && (configLevel !== 'third' || configLevel !== 'second')
"
@click="goBack()"
>
<img src="@/assets/images/tupu/map-arrow.png" alt="" />
<p class="back-text">返回上级</p>
</div>
<div class="assets-list-modal" v-if="showModal">
<div class="assets-list-modal-top">
<p class="fonts">{{ clickItem.typeName }}</p>
<img
class="arrow"
src="@/assets/images/devices/icon-arrow-1.png"
alt=""
/>
<p class="fonts">视频网</p>
<p class="fonts data-text">{{ clickItem.label }}</p>
<img
class="close"
@click="closeModal"
src="@/assets/images/devices/icon-close.png"
alt=""
/>
</div>
<div class="assets-list-modal-detail">
<div class="wrapper">
<img
class="image"
src="@/assets/images/devices/icon-total.png"
alt=""
/>
<p>
<span class="label">边界总数</span>
<span class="count" @click="clickTotal">{{
activeNumber.bjNum
}}</span>
<span class="unit">套</span>
</p>
</div>
<div class="wrapper">
<img
class="image"
src="@/assets/images/devices/icon-online.png"
alt=""
/>
<p>
<span class="label">在线边界</span>
<span class="count" @click="clickOnline">{{
activeNumber.zxbjNum
}}</span>
<span class="unit">套</span>
</p>
</div>
<div class="wrapper">
<img
class="image"
src="@/assets/images/devices/icon-offline.png"
alt=""
/>
<p>
<span class="label">离线边界</span>
<span class="count" @click="clickOffline">{{
activeNumber.lxbjNum
}}</span>
<span class="unit">套</span>
</p>
</div>
</div>
<div class="assets-list-modal-table">
<div class="table-header">
<p class="header-text" style="width: 15%">状态</p>
<p class="header-text" style="width: 35%">边界名称</p>
<p class="header-text" style="width: 35%">边界走向</p>
<p class="header-text" style="width: 15%">业务总数</p>
</div>
<div class="table-body">
<div @click="clickTableItem($event)" v-if="tableData.length > 0">
<vue-seamless-scroll
:data="tableData"
class="seamless-warp"
:class-option="classOption"
>
<ul>
<li
class="Carousel_li"
v-for="(item, index) in tableData"
:key="index"
:data-item="JSON.stringify(item)"
>
<div class="first">
<p class="header-text status" style="width: 15%">
<img
class="body-image"
:src="
item.status == 0
? require('@/assets/images/devices/icon-online.png')
: require('@/assets/images/devices/icon-offline.png')
"
alt=""
/>
<span>{{ item.status == 0 ? "在线" : "离线" }}</span>
</p>
<p class="header-text" style="width: 35%">
{{ item.borderName }}
</p>
<p class="header-text" style="width: 35%">
{{ item.borderTrend }}
</p>
<p class="header-text" style="width: 15%">
{{ item.ywNum }}
</p>
</div>
</li>
</ul>
</vue-seamless-scroll>
</div>
<div class="no-data-style" v-else>暂无数据</div>
</div>
</div>
</div>
</div>
</template>
<script>
const x = 100;
const y = 100;
import { getModalData } from "@/api/assets-topo.js";
export default {
computed: {
classOption() {
return {
step: 0.5, // 数值越大速度滚动越快
// limitMoveNum: 10, // 开始无缝滚动的数据量 this.dataList.length
hoverStop: true, // 是否开启鼠标悬停stop
direction: 1, // 0向下 1向上 2向左 3向右
// openWatch: true, // 开启数据实时监控刷新dom
singleHeight: 0, // 单步运动停止的高度(默认值0是无缝不停止的滚动) direction => 0/1
singleWidth: 0, // 单步运动停止的宽度(默认值0是无缝不停止的滚动) direction => 2/3
waitTime: 1000, // 单步运动停止的时间(默认值1000ms)
};
},
},
props: {
centerTopoData: {
type: Object,
default: () => {},
},
},
watch: {
centerTopoData(val) {
this.deviceList[0].count = {
normal: val.hlwSjZxNum,
unnormal: val.hlwSjLxNum,
};
this.deviceList[1].count = {
normal: val.hlwSpZxNum,
unnormal: val.hlwSpLxNum,
};
this.deviceList[2].count = {
normal: val.qtzwSjZxNum,
unnormal: val.qtzwSjLxNum,
};
this.deviceList[3].count = {
normal: val.qtzwSpZxNum,
unnormal: val.qtzwSpLxNum,
};
this.deviceList[4].deviceCount = { count: val.zrkzsbNum };
this.deviceList[5].deviceCount = { count: val.spjkNum };
this.deviceList[6].mainCount = { count: val.hlwNum };
this.deviceList[7].mainCount = { count: val.qtzwNum };
this.dealAllData(val);
},
level(val) {
this.setLevel(val);
},
},
data() {
return {
deviceList: [
// index 0 互联网行
{
left: x + 510,
top: y + 50,
unnormal: false,
label: "数据边界",
count: { normal: 0, unnormal: 0 },
typeName: "互联网",
isClick: true,
typeId: 1,
url: require("@/assets/images/devices/icon-data.png"),
unnormalUrl: require("@/assets/images/devices/unnormal/icon-data-grey.png"),
ImgWidth: 180,
ImgHeight: 144,
},
// index 1 互联网行
{
left: x + 510,
top: y + 210,
unnormal: false,
label: "视频边界",
count: { normal: 0, unnormal: 0 },
typeName: "互联网",
isClick: true,
typeId: 2,
url: require("@/assets/images/devices/icon-video.png"),
unnormalUrl: require("@/assets/images/devices/unnormal/icon-video-grey.png"),
ImgWidth: 180,
ImgHeight: 144,
},
// index 2 其他专网行
{
left: x + 510,
top: y + 380,
unnormal: false,
label: "数据边界",
count: { normal: 0, unnormal: 0 },
typeName: "其他专网",
isClick: true,
typeId: 3,
url: require("@/assets/images/devices/icon-data.png"),
unnormalUrl: require("@/assets/images/devices/unnormal/icon-data-grey.png"),
ImgWidth: 180,
ImgHeight: 144,
},
// index 3 其他专网行
{
left: x + 510,
top: y + 550,
unnormal: false,
label: "视频边界",
count: { normal: 0, unnormal: 0 },
typeName: "其他专网",
isClick: true,
typeId: 4,
url: require("@/assets/images/devices/icon-video.png"),
unnormalUrl: require("@/assets/images/devices/unnormal/icon-video-grey.png"),
ImgWidth: 180,
ImgHeight: 144,
},
// index 4 后置行
{
left: x + 950,
top: y + 400,
unnormal: false,
label: "准入控制",
deviceCount: { count: 0 },
typeName: "后置",
isHidden: true,
url: require("@/assets/images/devices/icon-NAC.png"),
unnormalUrl: require("@/assets/images/devices/unnormal/icon-NAC-grey.png"),
ImgWidth: 120,
ImgHeight: 112,
},
// index 5 后置行
{
left: x + 1250,
top: y + 270,
unnormal: false,
label: "视频监控",
deviceCount: { count: 0 },
typeName: "后置",
url: require("@/assets/images/devices/icon-monitoring.png"),
unnormalUrl: require("@/assets/images/devices/unnormal/icon-monitoring-grey.png"),
ImgWidth: 120,
ImgHeight: 112,
},
// index 6 互联网行
{
left: x,
top: y + 130,
unnormal: false,
label: "互联网接入单位",
mainCount: { count: 0 },
typeName: "互联网",
url: require("@/assets/images/devices/icon-Internet.png"),
unnormalUrl: require("@/assets/images/devices/unnormal/icon-Internet-grey.png"),
ImgWidth: 150,
ImgHeight: 120,
},
// index 7 其他专网行
{
left: x,
top: y + 500,
unnormal: false,
label: "其他专网接入单位",
mainCount: { count: 0 },
typeName: "其他专网",
url: require("@/assets/images/devices/icon-other.png"),
unnormalUrl: require("@/assets/images/devices/unnormal/icon-other-grey.png"),
ImgWidth: 150,
ImgHeight: 120,
},
// index 8 互联网行
{
left: x + 170,
top: y + 130,
unnormal: false,
label: "防火墙",
typeName: "互联网",
url: require("@/assets/images/devices/icon-fw01.png"),
unnormalUrl: require("@/assets/images/devices/unnormal/icon-fw01-grey.png"),
ImgWidth: 150,
ImgHeight: 120,
},
// index 9 互联网行
{
left: x + 350,
top: y,
unnormal: false,
label: "入侵检测",
typeName: "互联网",
url: require("@/assets/images/devices/icon-IDS.png"),
unnormalUrl: require("@/assets/images/devices/unnormal/icon-IDS-grey.png"),
ImgWidth: 150,
ImgHeight: 120,
},
// index 10 互联网行
{
left: x + 350,
top: y + 130,
unnormal: false,
label: "交换机",
typeName: "互联网",
url: require("@/assets/images/devices/icon-switch01.png"),
unnormalUrl: require("@/assets/images/devices/unnormal/icon-switch01-grey.png"),
ImgWidth: 150,
ImgHeight: 120,
},
// index 11 互联网行
{
left: x + 350,
top: y + 250,
unnormal: false,
label: "集控探针",
typeName: "互联网",
url: require("@/assets/images/devices/icon-probe.png"),
unnormalUrl: require("@/assets/images/devices/unnormal/icon-probe-grey.png"),
ImgWidth: 150,
ImgHeight: 120,
},
{
left: x + 750,
top: y + 50,
unnormal: false,
label: "上级共享平台",
isHidden: false,
url: require("@/assets/images/devices/icon-up-down.png"),
ImgWidth: 160,
ImgHeight: 115,
},
{
left: x + 750,
top: y + 250,
unnormal: false,
label: "本级共享平台",
url: require("@/assets/images/devices/icon-this.png"),
ImgWidth: 180,
ImgHeight: 135,
},
{
left: x + 750,
top: y + 450,
unnormal: false,
label: "下级共享平台",
isHidden: false,
url: require("@/assets/images/devices/icon-up-down.png"),
ImgWidth: 160,
ImgHeight: 115,
},
// index 15 其他专网行
{
left: x + 170,
top: y + 500,
unnormal: false,
label: "防火墙",
typeName: "其他专网",
url: require("@/assets/images/devices/icon-fw01.png"),
unnormalUrl: require("@/assets/images/devices/unnormal/icon-fw01-grey.png"),
ImgWidth: 150,
ImgHeight: 120,
},
// index 16 其他专网行
{
left: x + 350,
top: y + 370,
unnormal: false,
label: "入侵检测",
typeName: "其他专网",
url: require("@/assets/images/devices/icon-IDS.png"),
unnormalUrl: require("@/assets/images/devices/unnormal/icon-IDS-grey.png"),
ImgWidth: 150,
ImgHeight: 120,
},
// index 17 其他专网行
{
left: x + 350,
top: y + 500,
unnormal: false,
label: "交换机",
typeName: "其他专网",
url: require("@/assets/images/devices/icon-switch01.png"),
unnormalUrl: require("@/assets/images/devices/unnormal/icon-switch01-grey.png"),
ImgWidth: 150,
ImgHeight: 120,
},
// index 18 其他专网行
{
left: x + 350,
top: y + 620,
unnormal: false,
label: "集控探针",
typeName: "其他专网",
url: require("@/assets/images/devices/icon-probe.png"),
unnormalUrl: require("@/assets/images/devices/unnormal/icon-probe-grey.png"),
ImgWidth: 150,
ImgHeight: 120,
},
{
left: x + 950,
top: y + 270,
unnormal: false,
label: "交换机",
url: require("@/assets/images/devices/icon-switch02.png"),
ImgWidth: 120,
ImgHeight: 112,
},
{
left: x + 1100,
top: y + 270,
unnormal: false,
label: "防火墙",
url: require("@/assets/images/devices/icon-fw02.png"),
ImgWidth: 120,
ImgHeight: 112,
},
],
lineList: [
// index 0 互联网-->防火墙
{
left: x + 130,
top: y + 170,
width: 60,
height: 4,
isHidden: false,
normal: true,
tag: "互联网",
},
// index 1 防火墙--> 交换机
{
left: x + 300,
top: y + 170,
width: 60,
height: 4,
isHidden: false,
normal: true,
tag: "互联网",
},
// index 2 防火墙--> 入侵检测
{
left: x + 290,
top: y + 110,
width: 110,
height: 4,
deg: -45,
isHidden: false,
normal: true,
tag: "互联网",
},
// index 3 防火墙--> 集控探针
{
left: x + 290,
top: y + 225,
width: 110,
height: 4,
deg: 45,
isHidden: false,
normal: true,
tag: "互联网",
},
// index 4 交换机 --> 视频边界
{
left: x + 450,
top: y + 225,
width: 100,
height: 4,
deg: 45,
isHidden: false,
normal: true,
tag: "互联网",
},
// index 5 交换机 --> 数据边界
{
left: x + 460,
top: y + 140,
width: 60,
height: 4,
deg: -30,
isHidden: false,
normal: true,
tag: "互联网",
},
// index 6 数据边界--> 本级平台
{
left: x + 620,
top: y + 225,
width: 200,
height: 4,
deg: 45,
isHidden: false,
normal: true,
tag: "互联网",
},
// index 7 视频边界--> 本级平台
{
left: x + 650,
top: y + 285,
width: 100,
height: 4,
deg: 15,
isHidden: false,
normal: true,
tag: "互联网",
},
// index 8 本级平台 --> 上级平台
{
left: x + 785,
top: y + 200,
width: 100,
height: 4,
deg: -90,
isHidden: false,
normal: true,
},
// index 9 本级平台 --> 下级平台
{
left: x + 795,
top: y + 410,
width: 70,
height: 4,
deg: 90,
isHidden: false,
normal: true,
},
// index 10 本级平台 --> 交换机
{
left: x + 910,
top: y + 315,
width: 60,
height: 4,
isHidden: false,
normal: true,
},
// index 11 交换机 --> 防火墙
{
left: x + 1050,
top: y + 315,
width: 60,
height: 4,
isHidden: false,
normal: true,
},
// index 12 防火墙 --> 视频监控
{
left: x + 1190,
top: y + 315,
width: 60,
height: 4,
isHidden: false,
normal: true,
},
// index 13 交换机 --> 准入控制
{
left: x + 980,
top: y + 385,
width: 50,
height: 4,
deg: 90,
isHidden: true,
normal: true,
},
// ********* index 14 其他专网 --> 防火墙
{
left: x + 130,
top: y + 540,
width: 60,
height: 4,
isHidden: false,
normal: true,
tag: "其他专网",
},
// index 15防火墙 --> 交换机
{
left: x + 300,
top: y + 540,
width: 60,
height: 4,
isHidden: false,
normal: true,
tag: "其他专网",
},
// index 16 防火墙 --> 入侵检测
{
left: x + 290,
top: y + 480,
width: 110,
height: 4,
deg: -45,
isHidden: false,
normal: true,
tag: "其他专网",
},
// index 17 防火墙 --> 集控探针
{
left: x + 260,
top: y + 595,
width: 130,
height: 4,
deg: 45,
isHidden: false,
normal: true,
tag: "其他专网",
},
// index 18 交换机 --> 视频边界
{
left: x + 450,
top: y + 580,
width: 110,
height: 4,
deg: 30,
isHidden: false,
normal: true,
tag: "其他专网",
},
// index 19 交换机 --> 数据边界
{
left: x + 450,
top: y + 480,
width: 80,
height: 4,
deg: -40,
isHidden: false,
normal: true,
tag: "其他专网",
},
// index 20 视频边界 --> 本级平台
{
left: x + 600,
top: y + 450,
width: 250,
height: 4,
deg: -55,
isHidden: false,
normal: true,
tag: "其他专网",
},
// index 21 数据边界 --> 本级平台
{
left: x + 650,
top: y + 380,
width: 120,
height: 4,
deg: -25,
isHidden: false,
normal: true,
tag: "其他专网",
},
],
tipList: [
{ label: "接入对象", left: x + 50, top: y - 35 },
{ label: "边界保护服务区", left: x + 365, top: y - 35 },
{ label: "安全隔离区", left: x + 545, top: y - 35 },
{ label: "视频专网", left: x + 780, top: y - 35 },
],
parentId: "",
showBackButton: false,
level: "",
currentLevel: "first",
currentItem: {},
showModal: false,
clickItem: {
count: { normal: 0, unnormal: 0 },
},
currentNation: window.g.activeAreaCode,
activeNumber: {},
tableData: [],
currentTypeId: "",
configLevel: window.g.topoLevel,
};
},
methods: {
randomNum(minNum, maxNum) {
switch (arguments.length) {
case 1:
return parseInt(Math.random() * minNum + 1, 10);
break;
case 2:
return parseInt(Math.random() * (maxNum - minNum + 1) + minNum, 10);
break;
default:
return 0;
break;
}
},
addLineAnimation() {
const line = document.getElementsByClassName("active-part");
const domList = [];
for (let i = 0; i < line.length; i++) {
domList[i] = line[i];
}
domList.forEach((item, index) => {
const p = item.parentNode;
const width = p.style.width;
// 关键帧动画
const runkeyframes = ` @keyframes ${"rowup" + index} {
0% {
transform: translateX(-70px);
}
100% {
transform: translateX(${width});
display: none;
}
}`;
const style = document.createElement("style");
const randomTime = this.randomNum(3, 10);
const styleObj = `.active-part-${index} { animation: ${randomTime}s rowup${index} linear infinite normal;position: absolute;top: 0;left:0;}`;
style.type = "text/css";
style.innerHTML =
runkeyframes + "\n" + JSON.stringify(styleObj).replace('"', ""); // 将字符串换行并生成css文本格式
item.appendChild(style);
});
},
addImageAnimation() {
const line = document.getElementsByClassName("topo-chart-item");
const domList = [];
for (let i = 0; i < line.length; i++) {
domList[i] = line[i];
}
domList.forEach((item, index) => {
// 关键帧动画
const runkeyframes = `@keyframes ${"float" + index} {
0% {
transform: translateY(0px);
}
50% {
transform: translateY(-10px);
}
100% {
transform: translateY(0px);
}
}`;
const style = document.createElement("style");
const randomTime = this.randomNum(5, 8);
const styleObj = `.active-image-${index} { animation: ${randomTime}s float${index} linear infinite normal;position: absolute;top: 0;left:0;}`;
style.type = "text/css";
style.innerHTML =
runkeyframes + "\n" + JSON.stringify(styleObj).replace('"', ""); // 将字符串换行并生成css文本格式
item.appendChild(style);
});
},
setLevel(val) {
if (val === "first") {
// 1级 省级 无上级平台
this.$set(this.deviceList[12], "isHidden", true);
this.$set(this.deviceList[14], "isHidden", false);
this.$set(this.lineList[8], "isHidden", true);
this.$set(this.lineList[9], "isHidden", false);
} else if (val === "second") {
// 2级 市级 上下级平台都有
this.$set(this.deviceList[12], "isHidden", false);
this.$set(this.deviceList[14], "isHidden", false);
this.$set(this.lineList[8], "isHidden", false);
this.$set(this.lineList[9], "isHidden", false);
} else if (val === "third") {
// 3级 县级 无下级平台
this.$set(this.deviceList[12], "isHidden", false);
this.$set(this.deviceList[14], "isHidden", true);
this.$set(this.lineList[8], "isHidden", false);
this.$set(this.lineList[9], "isHidden", true);
}
this.addLineAnimation();
},
goBack() {
// if (this.currentLevel === 'first') { // 返回到省级
// this.showBackButton = false
// this.$EventBus.$emit("zcchildGoBack", window.g.activeAreaCode);
// if (window.g.activeAreaCode === '420000') {
// this.level = 'first'
// } else {
// this.level = 'second'
// }
// this.currentNation = window.g.activeAreaCode
// } else if(this.currentLevel === 'second') {
// this.showBackButton = true
// this.$EventBus.$emit("zcchildGoBack", this.currentItem.parent_id);
// this.currentLevel = 'first'
// this.level = 'second' // 级联等级
// this.currentNation = this.currentItem.parent_id
// }
this.showBackButton = false;
this.$EventBus.$emit("zcchildGoBack", window.g.activeAreaCode);
this.currentLevel = "first";
if (window.g.activeAreaCode === "420000") {
this.level = "first";
} else {
this.level = "second";
}
this.currentNation = window.g.activeAreaCode;
// this.$EventBus.$emit("childSendData", this.nameList, 0);
},
dealAllData(val) {
if (val.hlwNum == 0) {
// 互联网数量为0 所有图标置灰 线条没有
this.lineList.forEach((item) => {
if (item.tag === "互联网") {
item.isHidden = true;
}
});
this.deviceList.forEach((item) => {
if (item.typeName == "互联网") {
item.unnormal = val.hlwNum != 0 ? false : true;
}
});
} else {
// 不为0 判断数据边界和视频边界
// 互联网-->数据边界
this.lineList.forEach((item) => {
if (item.tag === "互联网") {
item.isHidden = false;
}
});
this.deviceList.forEach((item) => {
if (item.typeName == "互联网") {
item.unnormal = val.hlwNum != 0 ? false : true;
}
});
if (val.hlwSjZxNum == 0 && val.hlwSjLxNum == 0) {
// 如果2个值都为0 这条链路置灰
this.deviceList[0].unnormal = true;
this.lineList[5].isHidden = true; // 线为红色
this.lineList[6].isHidden = true;
} else {
// 都不为0 或有一个为0
if (val.hlwSjLxNum > 0) {
this.deviceList[0].unnormal = false;
this.lineList[5].normal = false; // 线为红色
this.lineList[6].normal = false;
} else {
if (val.hlwSjZxNum > 0) {
this.deviceList[0].unnormal = false;
this.lineList[5].normal = true; // 线为红色
this.lineList[6].normal = true;
} else {
this.deviceList[0].unnormal = true;
}
}
}
// 互联网--> 视频边界
if (val.hlwSpZxNum == 0 && val.hlwSpLxNum == 0) {
this.deviceList[1].unnormal = true;
this.lineList[4].isHidden = true; // 线为红色
this.lineList[7].isHidden = true;
} else {
// 都不为0 或有一个为0
if (val.hlwSpLxNum > 0) {
this.deviceList[1].unnormal = false;
this.lineList[4].normal = false; // 线为红色
this.lineList[7].normal = false;
} else {
if (val.hlwSpZxNum > 0) {
this.deviceList[1].unnormal = false;
this.lineList[4].normal = true; // 线为红色
this.lineList[7].normal = true;
} else {
this.deviceList[1].unnormal = true;
}
}
}
}
if (val.qtzwNum == 0) {
this.lineList.forEach((item) => {
if (item.tag === "其他专网") {
item.isHidden = true;
}
});
this.deviceList.forEach((item) => {
if (item.typeName == "其他专网") {
item.unnormal = val.qtzwNum != 0 ? false : true;
}
});
} else {
this.lineList.forEach((item) => {
if (item.tag === "其他专网") {
item.isHidden = false;
}
});
this.deviceList.forEach((item) => {
if (item.typeName == "其他专网") {
item.unnormal = val.qtzwNum != 0 ? false : true;
}
});
if (val.qtzwSjZxNum == 0 && val.qtzwSjLxNum == 0) {
// 其他专网--> 数据边界
this.deviceList[2].unnormal = true;
this.lineList[19].isHidden = true;
this.lineList[21].isHidden = true;
} else {
if (val.qtzwSjLxNum > 0) {
// 如果离线数据大于0 线为红色
this.deviceList[2].unnormal = false;
this.lineList[19].normal = false;
this.lineList[21].normal = false;
} else {
if (val.qtzwSjZxNum > 0) {
this.deviceList[2].unnormal = false;
this.lineList[19].normal = true;
this.lineList[21].normal = true;
} else {
this.deviceList[2].unnormal = true;
}
}
}
if (val.qtzwSpZxNum == 0 && val.qtzwSpLxNum == 0) {
// 其他专网 --> 视频边界
this.deviceList[3].unnormal = true;
this.lineList[18].isHidden = true;
this.lineList[20].isHidden = true;
} else {
if (val.qtzwSpLxNum > 0) {
// 如果离线数据大于0 线为红色
this.deviceList[3].unnormal = false;
this.lineList[18].normal = false;
this.lineList[20].normal = false;
} else {
if (val.qtzwSpZxNum > 0) {
this.deviceList[3].unnormal = false;
this.lineList[18].normal = true;
this.lineList[20].normal = true;
} else {
this.deviceList[3].unnormal = true;
}
}
}
}
if (val.zrkzsbNum == 0) {
// 准入控制
this.deviceList[4].unnormal = true;
this.lineList[13].isHidden = true;
} else {
this.deviceList[4].unnormal = false;
this.lineList[13].isHidden = false;
}
if (val.spjkNum == 0) {
// 视频监控
this.deviceList[5].unnormal = true;
this.lineList[12].isHidden = true;
} else {
this.deviceList[5].unnormal = false;
this.lineList[12].isHidden = false;
}
},
clickImage(item) {
if (!item.isClick) return false;
this.currentTypeId = item.typeId;
getModalData({ nation: this.currentNation, type: item.typeId }).then(
(res) => {
this.showModal = true;
this.activeNumber = res.data.zctsTppopVo;
this.tableData = res.data.zctsTppopVo.itemList || [];
}
);
this.clickItem = item;
},
closeModal() {
this.showModal = false;
},
clickTableItem(e) {
if (!e.target.parentNode.parentNode.dataset.item) {
return;
}
const item = JSON.parse(e.target.parentNode.parentNode.dataset.item);
var dataT = {
linkId: item.borderId,
linkType: "",
};
this.$router.push({ name: "bj_detail", query: dataT });
},
clickTotal() {
console.log(this.currentNation);
this.$router.push({
name: "assets_search",
params: {
nation: this.currentNation,
dataEx: JSON.stringify({ borderType: this.currentTypeId }),
tabIndex: "3",
},
});
},
clickOnline() {
this.$router.push({
name: "assets_search",
params: {
nation: this.currentNation,
dataEx: JSON.stringify({
borderType: this.currentTypeId,
runStatus: 0,
}),
tabIndex: "3",
},
});
},
clickOffline() {
this.$router.push({
name: "assets_search",
params: {
nation: this.currentNation,
dataEx: JSON.stringify({
borderType: this.currentTypeId,
runStatus: 1,
}),
tabIndex: "3",
},
});
},
},
created() {
this.$EventBus.$on("zcshowBackButton", (data, item, notShowButton) => {
this.currentLevel = data;
this.currentItem = item;
this.currentNation =
item.nation_code == "x" ? item.parent_id : item.nation_code;
if (notShowButton) {
this.showBackButton = false;
} else {
this.showBackButton = true;
}
// if (item.nation_code === window.g.activeAreaCode) {
// this.showBackButton = false
// }
// if (item.nation_code) {
// this.currentNation = item.nation_code
// }
});
this.$EventBus.$on("zcgetCurrentLevel", (level) => {
this.level = level;
});
},
mounted() {
this.$nextTick(() => {
this.addImageAnimation();
});
$(document).mouseup((e) => {
var _con = $(".assets-list-modal"); // 设置目标区域
if (!_con.is(e.target) && _con.has(e.target).length === 0) {
// Mark 1
this.showModal = false;
}
});
},
beforeDestroy() {
this.$EventBus.$off("zcshowBackButton");
this.$EventBus.$off("zcchildGoBack");
this.$EventBus.$off("zcgetCurrentLevel");
},
};
</script>
<style lang="less" scoped>
.topo-chart {
width: 100%;
height: 100%;
padding-top: 5%;
position: relative;
&-item {
position: absolute;
z-index: 2;
&-image {
cursor: pointer;
transition: 0.2s linear;
}
&-image:hover {
transform: scale(1.1);
}
.text-style {
margin-top: -30px;
text-align: center;
color: #d0dfef;
}
.count-style {
font-size: 20px;
text-align: center;
color: #d0dfef;
}
}
&-line {
position: absolute;
z-index: 1;
background: url("./../../../assets/images/devices/icon-back-line.png")
no-repeat;
}
}
.count-wrapper {
// height: 20px;
line-height: 20px;
display: flex;
// border-radius: 10px;
border: 1px solid #6c8097;
position: absolute;
left: 105px;
top: 10px;
height: 28px;
line-height: 28px;
border-radius: 14px;
font-size: 20px;
padding-left: 5px;
padding-right: 5px;
.normal-count {
padding: 0 10px 0 5px;
color: #07f1bc;
font-family: YouSheBiaoTiHei;
}
.unnormal-count {
padding-right: 5px;
color: #fa6c6d;
font-family: YouSheBiaoTiHei;
}
}
.device-count-wrapper {
// height: 20px;
// line-height: 20px;
display: flex;
// border-radius: 10px;
border: 1px solid #6c8097;
position: absolute;
left: 85px;
top: 10px;
height: 28px;
line-height: 28px;
border-radius: 14px;
font-size: 20px;
padding-left: 5px;
padding-right: 5px;
.device-count {
padding: 0 10px;
color: #007eff;
font-family: YouSheBiaoTiHei;
}
}
.tip-wrapper {
color: #d0dfef;
font-family: YouSheBiaoTiHei;
font-size: 18px;
position: absolute;
}
.legend-wrapper {
position: absolute;
bottom: 9%;
right: 50px;
display: flex;
flex-direction: column;
align-items: flex-end;
&-line {
margin-bottom: 15px;
}
&-text {
border: 1px solid #6c8097;
border-radius: 14px;
height: 28px;
display: flex;
line-height: 28px;
padding: 0 10px;
.signal {
font-weight: bold;
font-family: YouSheBiaoTiHei;
font-size: 16px;
padding: 0 10px;
}
.run-count {
color: #007eff;
}
.online-count {
color: #07f1bc;
}
.offline-count {
color: #fa6c6d;
}
}
}
.back-wrapper {
display: flex;
flex-direction: row;
align-items: center;
cursor: pointer;
position: absolute;
right: 5%;
top: 8%;
p {
margin-bottom: 18px;
color: #fff;
font-family: YouSheBiaoTiHei;
font-size: 18px;
}
}
.assets-list-modal {
width: 800px;
height: 450px;
background: url("./../../../assets/images/devices/common-bg.png") no-repeat;
position: fixed;
top: 36%;
left: 58%;
transform: translate(-50%, -50%);
z-index: 9999999;
&-top {
display: flex;
position: relative;
padding: 10px 0 0 15px;
.fonts {
color: #d0dfef;
font-family: YouSheBiaoTiHei;
font-size: 18px;
}
.data-text {
margin-left: 20px;
font-size: 16px;
padding-top: 3px;
}
.arrow {
margin-right: 10px;
margin-left: 10px;
width: 28px;
height: 8px;
margin-top: 8px;
}
.close {
position: absolute;
right: 10px;
top: 15px;
cursor: pointer;
}
}
&-detail {
display: flex;
padding: 10px 0 0 0;
.wrapper {
display: flex;
align-items: center;
margin-left: 20px;
.label {
font-size: 14px;
color: #fff;
margin-left: 10px;
}
.unit {
font-size: 12px;
color: #fff;
}
.count {
font-size: 22px;
color: #fff;
font-family: YouSheBiaoTiHei;
margin: 0 8px;
cursor: pointer;
}
.count:hover {
color: #007eff;
}
.image {
width: 20px;
height: 20px;
margin-top: 4px;
}
}
}
&-table {
margin-top: 10px;
.table-header {
display: flex;
margin: 0 20px;
border-left: 6px solid #0163e8;
border-right: 6px solid #0163e8;
border-top: 1px solid #0163e8;
border-bottom: 1px solid #0163e8;
padding: 5px;
background: rgba(1, 99, 232, 0.1);
.header-text {
color: #fff;
padding-left: 5px;
}
}
.table-body {
overflow: hidden;
margin: 0 20px;
height: 320px;
.status {
display: flex;
align-items: center;
span {
margin-left: 8px;
}
}
}
}
}
.no-data-style {
text-align: center;
color: #e9e9e9;
padding-top: 10px;
}
.first {
display: flex;
font-size: 14px;
padding: 10px 0;
cursor: pointer;
.header-text {
color: #fff;
padding-left: 5px;
}
}
.first:hover .header-text {
color: #0095ff;
}
// .icon-active-line {
// position: absolute;
// left: 0;
// }
// ::-webkit-scrollbar-track-piece { //滚动条凹槽的颜色,还可以设置边框属性
// background-color:#f8f8f8;
// }
// ::-webkit-scrollbar {//滚动条的宽度
// width:5px;
// height: 0;
// }
// ::-webkit-scrollbar-thumb {//滚动条的设置
// background-color:#dddddd;
// background-clip:padding-box;
// min-height:28px;
// }
// ::-webkit-scrollbar-thumb:hover {
// background-color:#bbb;
// }
</style>
transform属性
补充一下,transform属性可以对元素进行移动、缩放、转动、拉长或拉伸。
有四个常用方法:rotate(x,y)旋转,scale(x,y)缩放,translate(x,y)移动(平移)和skew(x-angle,y-angle)倾斜。
animation属性
animation 最常用的几种属性有以下几种:
-
animation-name(动画名称)
animation-name属性是必须存在的,因为animation-name的值默认是none,没有动画。 -
animation-duration(动画执行一次所需时间)
animation-duration属性也是必须存在的,因为animation-duration的值默认是0,没有动画。 -
animation-delay(动画在开始前的延迟时间)
animation-delay的值可以是秒(s)或者是毫秒(ms),默认值是0,没有延迟。 -
animation-timing-function(动画以何种运行轨迹完成一个周期)
animation-timing-function,默认值是ease,表示动画以低速开始,然后加速,最后在结束前变慢。 最常用的值有以下几个:
(1)linear:表示动画从头到尾的速度都是相同的。
(2)ease-in:表示动画以低速开始。
(3)ease-out:表示动画以低速结束。
(4)ease-in-out:表示动画以低速开始和结束。
- animation-iteration-count(动画播放次数)
animation-iteration-count属性值有两种:
(1)直接写数字,自定义想要播放动画的次数。
(2)infinite:设置动画无线循环播放。
- animation-fill-mode(定义元素动画结束以后或者未开始的元素样式)
默认值为none,标示,不会在动画结束或者未开始时给元素 添加样式
常用属性值为:
(1)forwards:表示动画结束后,元素直接接使用当前样式。
(2)backwards:表示在动画延迟时间元素使用关键帧中from的属性值或者to属性值(当animation-direction为reverse或者alternate-reverse时)
- animation-direction(是否轮流反向播放动画)
默认值是normal,动画正常播放。如果动画只播放一次,则该属性无效。
常用的属性值为:
(1)reverse:表示动画反向播放。
(2)alternate:表示动画在奇数次播放时为正向播放,为偶数次播放时为反向播放。
(3)alternate-reverse: :表示动画在奇数次播放时为反向播放,为偶数次播放时为正向播放。
animation属性在书写通常合并在一起,除非需要单独设置的属性值,animation属性的简写形式为:animation:code 2s 2s linear infinite alternate forwards;