文章目录
前言
画Dom元素的连线的工具有leader-line-vue,leader-line,G6和我们现在重点要介绍的jsPlumb等等。其中G6提供了丰富的示例代码,且官方文档为中文,功能还是比较强大的。leader-line-vue是用leader-line封装的vue插件,在vue中使用比leader-line友好,安装引入即可使用,可以省略leader-line的繁杂配置。但leader-line-vue存在一个缺陷,那就是leader-line-vue用来画dom元素间连线的svg画布是被加载到页面的body元素里的,导致页面局部滚动时dom元素间的连线位置不变,无法随局部滚动条位置更新。如如需解决这个问题,有两种方法:一、使用d3辅助,在初始化画布时把svg画布移到指定容器内,在该容器内绘制dom元素间连线。二、使用jsPlumb画Dom元素间的连线。
一、 什么是jsplumb?
你有没有想过在你的网站上展示图表或者甚至在浏览器应用程序中使用它?用jsPlumb你可以!它是完全免费的,并根据MIT许可证提供。您可以直接从jsPlumb github网站下载框架。
该项目主要由Simon Porritt开发,他在澳大利亚西德尼担任网络开发人员。 jsPlumb由他积极开发。作为许多优秀的开发人员,他似乎更喜欢开发代码而不是编写教程,这就是为什么我提供一个简单的入门教程。
二、jsplumb能干什么?
那么如果你应该使用它取决于你想用jsPlumb做什么。该框架适用于必须绘制图表的Web应用程序,例如类似于Visio的应用程序或工作流程设计器等。由于图表项目和连接的所有参数都是非常精细可控的,因此您可以绘制您可以想到的任何类型的图表的!
三、安装
1.安装jsplumb
npm install jsplumb --save
//在组件中引入jsplumb
import { jsPlumb } from "jsplumb";
代码如下(示例):
<template>
<div class="TestTwo">
<div class="TestTwoOutbox">
<div class="line-wrap" style="margin-left: 70px">
<div id="item-1" class="state-item">State 1</div>
<div id="item-2" class="state-item">State 2</div>
</div>
</div>
</div>
</template>
<script>
import { jsPlumb } from "jsplumb";
export default {
name: "TestTwo",
mounted() {
let plumbIns = jsPlumb.getInstance();
plumbIns.ready(function () {
plumbIns.connect({
source: "item-1",
target: "item-2",
anchor: [
"Left",
"Right"
],
connector: ["StateMachine"],
endpoint: "Blank",
overlays: [["Arrow", { width: 8, length: 8, location: 1 }]],
paintStyle: { stroke: "#909399", strokeWidth: 2 },
});
});
},
};
</script>
<style lang="scss" scoped>
.TestTwo {
width: 100%;
height: 100%;
.TestTwoOutbox {
background: radial-gradient(
ellipse at top left,
rgba(255, 255, 255, 1) 40%,
rgba(229, 229, 229, 0.9) 100%
);
height: 100%;
padding:100px;
width: 100%;
position: relative;
overflow: auto;
.line-wrap {
display: flex;
margin-bottom: 40px;
.state-item {
width: 80px;
height: 40px;
color: #606266;
background: #f6f6f6;
border: 2px solid rgba(0, 0, 0, 0.05);
text-align: center;
line-height: 40px;
font-family: sans-serif;
border-radius: 4px;
margin-right: 60px;
}
}
}
}
</style>
2.安装 d3
npm i d3 @6.2.0
//在main.js中引入
import * as d3 from "d3";
Vue.prototype.$d3 = d3;
window.d3 = d3;
代码如下(示例):
if (d3.selectAll(".jtk-connector")) {
d3.selectAll(".ShowContent").selectAll(".jtk-connector").remove();
}
if (d3.selectAll(".jtk-endpoint")) {
d3.selectAll(".ShowContent").selectAll(".jtk-endpoint").remove();
}
d3.js 清除svg
rave.select(el).html(''); // 不推荐
rave.selectAll("svg > *").remove(); // 移除svg内部节点
rave.selectAll("svg").remove(); // 移除svg节点
注:使用d3作用是切换时清除之前连线
安装成功后如图所示:
完整代码
<template>
<div class="TestOne">
<div class="FrameContnet">
<div class="ShowContent" v-if="showTree">
<div class="FirstContent">
<div
v-for="(item, index) in FirstContentData"
:key="index"
class="Itembox"
:class="FirstContentNowIndex === index ? 'ActiveItembox' : ''"
:id="item.Id"
@click="FirstContentFun(item, index)"
>
<!-- <div class="Itembox_PartOne"></div> -->
<div class="Itembox_PartTwo">
<div class="ContentOutbox">
<div class="TopPart">
<div class="LeftPart">{{ item.Name }}</div>
<div class="RightPart">{{ item.Time }}</div>
</div>
<div class="ShowCode">{{ item.ShowCode }}</div>
<div class="BottomPart">
<div
v-for="(childitem, childindex) in item.List"
:key="childindex"
class="childitembox"
>
<div class="Numbox">{{ childitem.Data }}</div>
<div class="Titlebox">{{ childitem.Title }}</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="SecondContent">
<div
v-for="(item, index) in SecondContentData"
:key="index"
class="Itembox"
:class="SecondContentNowIndex === index ? 'ActiveItembox' : ''"
:id="item.Id"
@click="SecondContentFun(item, index)"
>
<!-- <div class="Itembox_PartOne"></div> -->
<div class="Itembox_PartTwo">
<div class="ContentOutbox">
<div class="TopPart">
<div class="LeftPart">{{ item.Name }}</div>
<div class="RightPart">{{ item.Time }}</div>
</div>
<div class="ShowCode">{{ item.ShowCode }}</div>
<div class="BottomPart">
<div
v-for="(childitem, childindex) in item.List"
:key="childindex"
class="childitembox"
>
<div class="Numbox">{{ childitem.Data }}</div>
<div class="Titlebox">{{ childitem.Title }}</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="ThirdContent">
<div
v-for="(item, index) in ThirdContentData"
:key="index"
class="Itembox"
:class="ThirdContentNowIndex === index ? 'ActiveItembox' : ''"
:id="item.Id"
@click="ThirdContentFun(item, index)"
>
<!-- <div class="Itembox_PartOne"></div> -->
<div class="Itembox_PartTwo">
<div class="ContentOutbox">
<div class="TopPart">
<div class="LeftPart">{{ item.Name }}</div>
<div class="RightPart">{{ item.Time }}</div>
</div>
<div class="ShowCode">{{ item.ShowCode }}</div>
<div class="BottomPart">
<div
v-for="(childitem, childindex) in item.List"
:key="childindex"
class="childitembox"
>
<div class="Numbox">{{ childitem.Data }}</div>
<div class="Titlebox">{{ childitem.Title }}</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="FourContent">
<div
v-for="(item, index) in FourContentData"
:key="index"
class="Itembox"
:class="FourContentNowIndex === index ? 'ActiveItembox' : ''"
:id="item.Id"
@click="FourContentFun(item, index)"
>
<!-- <div class="Itembox_PartOne"></div> -->
<div class="Itembox_PartTwo">
<div class="ContentOutbox">
<div class="TopPart">
<div class="LeftPart">{{ item.Name }}</div>
<div class="RightPart">{{ item.Time }}</div>
</div>
<div class="ShowCode">{{ item.ShowCode }}</div>
<div class="BottomPart">
<div
v-for="(childitem, childindex) in item.List"
:key="childindex"
class="childitembox"
>
<div class="Numbox">{{ childitem.Data }}</div>
<div class="Titlebox">{{ childitem.Title }}</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import AnimEvent from "anim-event";
import FirstContentDataJson from "./data/FirstContentData.json";
import SecondContentDataJson from "./data/SecondContentData.json";
import ThirdContentDataJson from "./data/ThirdContentData.json";
import FourContentDataJson from "./data/FourContentData.json";
import ListDataJson from "./data/ListData.json";
import { jsPlumb } from "jsplumb";
export default {
name: "TestOne",
data() {
return {
ListData: ListDataJson.Data,
FirstContentData: ListDataJson.Data,
SecondContentData: [],
ThirdContentData: [],
FourContentData: [],
FirstContentNowIndex: 0,
SecondContentNowIndex: 0,
ThirdContentNowIndex: 0,
FourContentNowIndex: 0,
///
// jsPlumb默认配置
jsPlumbSetting: {
// 动态锚点、位置自适应
Anchors: [
"Top",
"TopCenter",
"TopRight",
"TopLeft",
"Right",
"RightMiddle",
"Bottom",
"BottomCenter",
"BottomRight",
"BottomLeft",
"Left",
"LeftMiddle",
],
// 连线的样式 StateMachine、Flowchart,Bezier、Straight
Connector: ["Bezier", { curviness: 60 }],
// 鼠标是否拖动删除线
ConnectionsDetachable: false,
// 删除线的时候节点不删除
DeleteEndpointsOnDetach: false,
// 连线的两端端点类型:矩形 Rectangle;圆形Dot; eight: 矩形的高 ,idth: 矩形的宽
Endpoints: [
["Dot", { radius: 2 }],
["Dot", { radius: 2 }],
],
// 线端点的样式
EndpointStyle: { fill: "skyblue", outlineWidth: 1 },
// 绘制连线
PaintStyle: {
stroke: "#000000",
strokeWidth: 1,
outlineStroke: "transparent",
// 设定线外边的宽,单位px
outlineWidth: 10,
},
// 绘制连线箭头
Overlays: [
// 箭头叠加
[
"Arrow",
{
width: 10, // 箭头尾部的宽度
length: 8, // 从箭头的尾部到头部的距离
location: 1, // 位置,建议使用0~1之间
direction: 1, // 方向,默认值为1(表示向前),可选-1(表示向后)
foldback: 0.623, // 折回,也就是尾翼的角度,默认0.623,当为1时,为正三角
},
],
],
// 绘制图的模式 svg、canvas
RenderMode: "svg",
DragOptions: { cursor: "pointer", zIndex: 2000 },
// 鼠标滑过线的样式
HoverPaintStyle: {
stroke: "skyblue",
strokeWidth: 3,
cursor: "pointer",
},
},
// 连线的配置
jsPlumbConnectOptions: {
isSource: true,
isTarget: true,
// 动态锚点、提供了4个方向 Continuous、AutoDefault
anchor: "Continuous",
overlays: [
[
"Arrow",
{
width: 10, // 箭头尾部的宽度
length: 8, // 从箭头的尾部到头部的距离
location: 1, // 位置,建议使用0~1之间
direction: 1, // 方向,默认值为1(表示向前),可选-1(表示向后)
foldback: 0.623, // 折回,也就是尾翼的角度,默认0.623,当为1时,为正三角
},
],
], // overlay
},
};
},
computed: {
/**
* 是否展示树计算属性
*/
showTree() {
return this.ListData && this.ListData.length;
},
},
mounted() {
this.$nextTick(() => {
this.InitDataFun();
// this.AddEventListenerSrollFun();
});
},
beforeDestroy() {
this.RomoveSvgFun();
},
methods: {
FirstContentFun(item, index) {
this.FirstContentNowIndex = index;
this.AsyncFun();
},
SecondContentFun(item, index) {
this.SecondContentNowIndex = index;
this.AsyncFun();
},
ThirdContentFun(item, index) {
this.ThirdContentNowIndex = index;
this.AsyncFun();
},
FourContentFun(item, index) {
this.FourContentNowIndex = index;
this.AsyncFun();
},
/**
* 异步执行 获取数据----->清空已有连线--->从新绘制连线
*/
AsyncFun() {
new Promise((resolve) => {
setTimeout(() => {
resolve("aaa");
}, 10);
})
.then((res) => {
this.ChangShowDataFun();
console.log(res, "第一次自己处理别的业务的代码");
return res + "111";
})
.then((res) => {
this.RomoveSvgFun();
console.log(res, "第二次自己处理别的业务的代码");
return res + "222";
})
.then((res) => {
this.InitDrawLine();
console.log(res, "第三次自己处理别的业务的代码");
})
.then((res) => {});
},
ChangShowDataFun() {
this.SecondContentData =
this.ListData[this.FirstContentNowIndex].Children;
this.ThirdContentData =
this.ListData[this.FirstContentNowIndex].Children[
this.SecondContentNowIndex
].Children;
this.FourContentData =
this.ListData[this.FirstContentNowIndex].Children[
this.SecondContentNowIndex
].Children[this.ThirdContentNowIndex].Children;
},
RomoveSvgFun() {
if (d3.selectAll(".jtk-connector")) {
d3.selectAll(".ShowContent").selectAll(".jtk-connector").remove();
}
if (d3.selectAll(".jtk-endpoint")) {
d3.selectAll(".ShowContent").selectAll(".jtk-endpoint").remove();
}
},
/*
************
*/
InitDrawLine() {
this.$nextTick().then(() => {
let plumbIns = jsPlumb.getInstance();
let defaultConfig = {
anchor: ["Left", "Right"],
Endpoints: [
["Dot", { radius: "50%" }],
["Dot", { radius: "50%" }],
],
paintStyle: { stroke: "#75cede", strokeWidth: 3 },
endpointStyle: {
fill: "red",
outlineStroke: "yellow",
outlineWidth: 5,
},
connector: ["Bezier", { curviness: 60 }],
overlays: [
[
"Arrow",
{
width: 10, // 箭头尾部的宽度
length: 8, // 从箭头的尾部到头部的距离
location: 1, // 位置,建议使用0~1之间
direction: 1, // 方向,默认值为1(表示向前),可选-1(表示向后)
foldback: 0.623, // 折回,也就是尾翼的角度,默认0.623,当为1时,为正三角
},
],
],
};
let FirstId = this.ListData[this.FirstContentNowIndex].Id;
if (this.SecondContentData && this.SecondContentData.length) {
this.SecondContentData.map((item) => {
plumbIns.ready(() => {
plumbIns.connect(
{
source: FirstId,
target: item.Id,
},
defaultConfig
);
});
});
}
let SecondId = document.getElementById(
this.SecondContentData[this.SecondContentNowIndex].Id
);
if (this.ThirdContentData && this.ThirdContentData.length) {
this.ThirdContentData.map((item) => {
plumbIns.ready(() => {
plumbIns.connect(
{
source: SecondId,
target: item.Id,
},
defaultConfig
);
});
});
}
let ThirdId = document.getElementById(
this.ThirdContentData[this.ThirdContentNowIndex].Id
);
if (this.FourContentData && this.FourContentData.length) {
this.FourContentData.map((item) => {
plumbIns.ready(() => {
plumbIns.connect(
{
source: ThirdId,
target: item.Id,
},
defaultConfig
);
});
});
}
///
});
},
/*
************
*/
/**
* 监听滚动条变化各部分连线跟随变化
*/
AddEventListenerSrollFun() {
window.addEventListener(
"scroll",
AnimEvent.add(() => {
//this.ResetPositionDrawLine();
}),
false
);
let scrollableBox1 = document.getElementsByClassName("FirstContent")[0];
scrollableBox1.addEventListener(
"scroll",
AnimEvent.add(() => {
// this.ResetPositionDrawLine();
}),
false
);
},
/************************以下是生成数据方法***********************************/
InitDataFun() {
let ListData = [];
let FirstContentData = [];
let SecondContentData = [];
let ThirdContentData = [];
let FourContentData = [];
for (var i = 0; i < 16; i++) {
if (i < 6) {
FirstContentData.push({
Name: "一级水厂" + (i + 1),
Time: "13:0" + i,
Id: "Firstid" + (i + 1),
LID: "Firstlid" + (i + 1),
List: [
{
Title: "浊度",
Data: 0.23,
},
{
Title: "PH",
Data: 3,
},
{
Title: "湿度",
Data: 0.63,
},
{
Title: "COD",
Data: 0.23,
},
],
});
let ListDataSec = [];
for (var Seci = 0; Seci < 16; Seci++) {
let ListDatarsd = [];
for (var Rsdi = 0; Rsdi < 16; Rsdi++) {
let ListDataFour = [];
for (var Fouri = 0; Fouri < 16; Fouri++) {
ListDataFour.push({
Name: "四级水厂" + (Fouri + 1),
Time: "13:0" + Fouri,
Id: "Fourid" + (Fouri + 1),
LID: "Fourlid" + (Fouri + 1),
ShowCode:
"一级---" +
(i + 1) +
"---二级---" +
(Seci + 1) +
"---三级---" +
(Rsdi + 1) +
"---四级---" +
(Fouri + 1),
Children: [],
List: [
{
Title: "浊度",
Data: 0.23,
},
{
Title: "PH",
Data: 3,
},
{
Title: "湿度",
Data: 0.63,
},
{
Title: "COD",
Data: 0.23,
},
],
});
}
ListDatarsd.push({
Name: "三级水厂" + (Rsdi + 1),
Time: "13:0" + Rsdi,
Id: "Thirdid" + (Rsdi + 1),
LID: "Thirdlid" + (Rsdi + 1),
ShowCode:
"一级---" +
(i + 1) +
"---二级---" +
(Seci + 1) +
"---三级---" +
(Rsdi + 1),
Children: ListDataFour,
List: [
{
Title: "浊度",
Data: 0.23,
},
{
Title: "PH",
Data: 3,
},
{
Title: "湿度",
Data: 0.63,
},
{
Title: "COD",
Data: 0.23,
},
],
});
}
ListDataSec.push({
Name: "二级水厂" + (Seci + 1),
Time: "13:0" + Seci,
Id: "Secondid" + (Seci + 1),
LID: "Secondlid" + (Seci + 1),
ShowCode: "一级---" + (i + 1) + "---二级---" + (Seci + 1),
Children: ListDatarsd,
List: [
{
Title: "浊度",
Data: 0.23,
},
{
Title: "PH",
Data: 3,
},
{
Title: "湿度",
Data: 0.63,
},
{
Title: "COD",
Data: 0.23,
},
],
});
}
ListData.push({
Name: "一级水厂" + (i + 1),
Time: "13:0" + i,
Id: "Firstid" + (i + 1),
LID: "Firstlid" + (i + 1),
ShowCode: "一级---" + (i + 1),
List: [
{
Title: "浊度",
Data: 0.23,
},
{
Title: "PH",
Data: 3,
},
{
Title: "湿度",
Data: 0.63,
},
{
Title: "COD",
Data: 0.23,
},
],
Children: ListDataSec,
});
}
SecondContentData.push({
Name: "二级水厂" + (i + 1),
Time: "13:0" + i,
Id: "Secondid" + (i + 1),
LID: "Secondlid" + (i + 1),
List: [
{
Title: "浊度",
Data: 0.23,
},
{
Title: "PH",
Data: 3,
},
{
Title: "湿度",
Data: 0.63,
},
{
Title: "COD",
Data: 0.23,
},
],
});
ThirdContentData.push({
Name: "三级水厂" + (i + 1),
Time: "13:0" + i,
Id: "Thirdid" + (i + 1),
LID: "Thirdlid" + (i + 1),
List: [
{
Title: "浊度",
Data: 0.23,
},
{
Title: "PH",
Data: 3,
},
{
Title: "湿度",
Data: 0.63,
},
{
Title: "COD",
Data: 0.23,
},
],
});
FourContentData.push({
Name: "四级水厂" + (i + 1),
Time: "13:0" + i,
Id: "Fourid" + (i + 1),
LID: "Fourlid" + (i + 1),
List: [
{
Title: "浊度",
Data: 0.23,
},
{
Title: "PH",
Data: 3,
},
{
Title: "湿度",
Data: 0.63,
},
{
Title: "COD",
Data: 0.23,
},
],
});
}
this.FirstContentData = FirstContentData;
this.SecondContentData = SecondContentData;
this.ThirdContentData = ThirdContentData;
this.FourContentData = FourContentData;
// console.log("ListData",ListData)
// console.log("JSON.stringify(ListData)", JSON.stringify(ListData));
this.AsyncFun();
},
},
};
</script>
<style lang="scss" scoped>
.TestOne {
width: 100%;
height: 100%;
.FrameContnet {
display: flex;
flex-flow: row nowrap;
justify-content: center;
align-items: center;
width: 100%;
height: 80%;
background: #1f4760;
overflow: auto;
margin-top: 60px;
/*定义滚动条高宽及背景 高宽分别对应横竖滚动条的尺寸*/
&::-webkit-scrollbar {
width: 5px;
height: 5px;
background-color: #f5f5f5;
}
/*定义滚动条轨道 内阴影+圆角*/
&::-webkit-scrollbar-track {
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
border-radius: 2px;
background-color: #f5f5f5;
}
/*定义滑块 内阴影+圆角*/
&::-webkit-scrollbar-thumb {
border-radius: 2px;
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
background-color: #eee;
}
.ShowContent {
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
width: calc(100% - 40px);
height: calc(100% - 40px);
position: relative;
.FirstContent {
width: 20%;
// height: 100%;
// overflow: auto;
/*定义滚动条高宽及背景 高宽分别对应横竖滚动条的尺寸*/
&::-webkit-scrollbar {
width: 0px;
height: 0px;
background-color: #f5f5f5;
}
/*定义滚动条轨道 内阴影+圆角*/
&::-webkit-scrollbar-track {
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
border-radius: 2px;
background-color: #f5f5f5;
}
/*定义滑块 内阴影+圆角*/
&::-webkit-scrollbar-thumb {
border-radius: 2px;
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
background-color: #eee;
}
.Itembox {
display: flex;
flex-flow: row nowrap;
width: 100%;
//height: 190px;
margin-bottom: 10px;
background: #235270;
border-radius: 5px;
cursor: pointer;
// .Itembox_PartOne {
// background: #63d2e1;
// width: 5px;
// height: 100%;
// border-radius: 5px;
// }
.Itembox_PartTwo {
display: flex;
flex-flow: column;
justify-content: center;
align-items: center;
// width: calc(100% - 5px);
width: 100%;
height: 100%;
border: 3px solid #396079;
border-left: 5px solid #63d2e1;
box-sizing: border-box;
border-radius: 5px;
.ContentOutbox {
width: calc(100% - 20px);
height: calc(100% - 20px);
.TopPart {
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
align-items: center;
width: 100%;
margin: 15px 0 15px 0;
.LeftPart {
color: #fff;
font-size: 20px;
font-weight: bold;
}
.RightPart {
color: #fff;
font-size: 16px;
}
}
.ShowCode {
color: #fff;
font-size: 16px;
}
.BottomPart {
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
align-items: center;
width: 100%;
margin: 15px 0 15px 0;
.childitembox {
display: flex;
flex-flow: column;
justify-content: center;
align-items: center;
.Numbox {
color: #fff;
font-size: 16px;
font-weight: bold;
margin-bottom: 10px;
}
.Titlebox {
color: rgb(213, 213, 213);
font-size: 14px;
}
}
}
}
}
}
.ActiveItembox {
background: #112b3a;
}
}
.SecondContent {
width: 20%;
// height: 100%;
// overflow: auto;
/*定义滚动条高宽及背景 高宽分别对应横竖滚动条的尺寸*/
&::-webkit-scrollbar {
width: 0px;
height: 0px;
background-color: #f5f5f5;
}
/*定义滚动条轨道 内阴影+圆角*/
&::-webkit-scrollbar-track {
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
border-radius: 2px;
background-color: #f5f5f5;
}
/*定义滑块 内阴影+圆角*/
&::-webkit-scrollbar-thumb {
border-radius: 2px;
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
background-color: #eee;
}
.Itembox {
display: flex;
flex-flow: row nowrap;
width: 100%;
//height: 190px;
margin-bottom: 10px;
background: #235270;
border-radius: 5px;
cursor: pointer;
// .Itembox_PartOne {
// background: #63d2e1;
// width: 5px;
// height: 100%;
// border-radius: 5px;
// }
.Itembox_PartTwo {
display: flex;
flex-flow: column;
justify-content: center;
align-items: center;
// width: calc(100% - 5px);
width: 100%;
height: 100%;
border: 3px solid #396079;
border-left: 5px solid #63d2e1;
box-sizing: border-box;
border-radius: 5px;
.ContentOutbox {
width: calc(100% - 20px);
height: calc(100% - 20px);
.TopPart {
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
align-items: center;
width: 100%;
margin: 15px 0 15px 0;
.LeftPart {
color: #fff;
font-size: 20px;
font-weight: bold;
}
.RightPart {
color: #fff;
font-size: 16px;
}
}
.ShowCode {
color: #fff;
font-size: 16px;
margin: 5px 0 5px 0;
}
.BottomPart {
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
align-items: center;
width: 100%;
margin: 15px 0 15px 0;
.childitembox {
display: flex;
flex-flow: column;
justify-content: center;
align-items: center;
.Numbox {
color: #fff;
font-size: 16px;
font-weight: bold;
margin-bottom: 10px;
}
.Titlebox {
color: rgb(213, 213, 213);
font-size: 14px;
}
}
}
}
}
}
.ActiveItembox {
background: #112b3a;
}
}
.ThirdContent {
width: 20%;
// height: 100%;
// overflow: auto;
/*定义滚动条高宽及背景 高宽分别对应横竖滚动条的尺寸*/
&::-webkit-scrollbar {
width: 0px;
height: 0px;
background-color: #f5f5f5;
}
/*定义滚动条轨道 内阴影+圆角*/
&::-webkit-scrollbar-track {
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
border-radius: 2px;
background-color: #f5f5f5;
}
/*定义滑块 内阴影+圆角*/
&::-webkit-scrollbar-thumb {
border-radius: 2px;
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
background-color: #eee;
}
.Itembox {
display: flex;
flex-flow: row nowrap;
width: 100%;
//height: 190px;
margin-bottom: 10px;
background: #235270;
border-radius: 5px;
cursor: pointer;
// .Itembox_PartOne {
// background: #63d2e1;
// width: 5px;
// height: 100%;
// border-radius: 5px;
// }
.Itembox_PartTwo {
display: flex;
flex-flow: column;
justify-content: center;
align-items: center;
// width: calc(100% - 5px);
width: 100%;
height: 100%;
border: 3px solid #396079;
border-left: 5px solid #63d2e1;
box-sizing: border-box;
border-radius: 5px;
.ContentOutbox {
display: flex;
flex-flow: column;
justify-content: space-between;
width: calc(100% - 20px);
height: calc(100% - 20px);
.TopPart {
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
align-items: center;
width: 100%;
margin: 15px 0 15px 0;
.LeftPart {
color: #fff;
font-size: 20px;
font-weight: bold;
}
.RightPart {
color: #fff;
font-size: 16px;
}
}
.ShowCode {
color: #fff;
font-size: 16px;
}
.BottomPart {
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
align-items: center;
width: 100%;
margin: 15px 0 15px 0;
.childitembox {
display: flex;
flex-flow: column;
justify-content: center;
align-items: center;
.Numbox {
color: #fff;
font-size: 16px;
font-weight: bold;
margin-bottom: 10px;
}
.Titlebox {
color: rgb(213, 213, 213);
font-size: 14px;
}
}
}
}
}
}
.ActiveItembox {
background: #112b3a;
}
}
.FourContent {
width: 20%;
// height: 100%;
// overflow: auto;
/*定义滚动条高宽及背景 高宽分别对应横竖滚动条的尺寸*/
&::-webkit-scrollbar {
width: 0px;
height: 0px;
background-color: #f5f5f5;
}
/*定义滚动条轨道 内阴影+圆角*/
&::-webkit-scrollbar-track {
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
border-radius: 2px;
background-color: #f5f5f5;
}
/*定义滑块 内阴影+圆角*/
&::-webkit-scrollbar-thumb {
border-radius: 2px;
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
background-color: #eee;
}
.Itembox {
display: flex;
flex-flow: row nowrap;
width: 100%;
//height: 190px;
margin-bottom: 10px;
background: #235270;
border-radius: 5px;
cursor: pointer;
// .Itembox_PartOne {
// background: #63d2e1;
// width: 5px;
// height: 100%;
// border-radius: 5px;
// }
.Itembox_PartTwo {
display: flex;
flex-flow: column;
justify-content: center;
align-items: center;
// width: calc(100% - 5px);
width: 100%;
height: 100%;
border: 3px solid #396079;
border-left: 5px solid #63d2e1;
box-sizing: border-box;
border-radius: 5px;
.ContentOutbox {
width: calc(100% - 20px);
height: calc(100% - 20px);
.TopPart {
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
align-items: center;
width: 100%;
margin: 15px 0 15px 0;
.LeftPart {
color: #fff;
font-size: 20px;
font-weight: bold;
}
.RightPart {
color: #fff;
font-size: 16px;
}
}
.ShowCode {
color: #fff;
font-size: 16px;
}
.BottomPart {
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
align-items: center;
width: 100%;
margin: 15px 0 15px 0;
.childitembox {
display: flex;
flex-flow: column;
justify-content: center;
align-items: center;
.Numbox {
color: #fff;
font-size: 16px;
font-weight: bold;
margin-bottom: 10px;
}
.Titlebox {
color: rgb(213, 213, 213);
font-size: 14px;
}
}
}
}
}
}
.ActiveItembox {
background: #112b3a;
}
}
}
}
}
</style>
Github源码