架子是用的vue3+element Plus, 要用到时间轴展示,但element组件只有竖着的,想要横着的,找了一圈没有合适的,终于找到个合适的,文章原址 https://blog.csdn.net/m0_62949703/article/details/127800712
数据结构:
{
date: '2023-09-27’,
isShow: true,
children: [
{
lineTitle: `公司地址`,
content: `变更前:${item.changeFront}\n变更后:${item.changeBack}`
}
]
}
HTML:
<template>
<!-- 横向时间轴组件-->
<ul class="timeline-wrapper">
<li class="timeline-item" v-for="(item,index) in timelineList" :key="index">
<div class="timeline-box">
<div class="out-circle">
<!-- 小圆点-->
<div class="in-circle" />
<!-- 时间-->
<div class="time">{{ item.date }}</div>
<!-- 悬浮气泡-->
<!-- <div class="timeline-date">-->
<!-- <el-popover placement="bottom" trigger="hover" width="200" title="变更明细">-->
<!-- <template >-->
<!-- <p>{{666}}</p>-->
<!-- </template>-->
<!-- <div>777777777777</div>-->
<!-- <div>888888888888</div>-->
<!-- </el-popover>-->
<!-- </div>-->
</div>
<!-- 常驻气泡框-->
<div
class="long-line"
v-show="item.isShow"
:style="`width:${item.children ? (item.children.length + 1) * 400 : 1 * 100}px`">
<div
v-for="(subItem, index) in item.children"
:key="index"
class="sub-item-box"
>
<span>{{ subItem.lineTitle }}</span>
<!-- 根据奇数偶数来判断向上展示还是向下展示 -->
<div :class="`sub-line-box ${index % 2 === 0 ? 'top-line-box' : 'bottom-line-box'}`" v-show="subItem.content">
<!-- 线-->
<div :class="`children-line-box ${index % 2 === 0 ? 'top-line' : 'bottom-line' }`"></div>
<!-- 气泡框-->
<div :class="`children-box ${index % 2 === 0 ? 'top-children-box' : 'bottom-children-box'}`">
{{ subItem.content }}
</div>
</div>
</div>
</div>
</div>
</li>
</ul>
</template>
JS:
<script setup lang="ts">
// 接收接口返回的数据
const Props = defineProps(['timelineList'])
// 时间轴数据
const timelineList = ref<any>([])
// 新增新日期
const newArrayPush = (item: any) => {
let childrenData = [
{
lineTitle: item.changeItem,
content: `变更前:${item.changeFront}\n变更后:${item.changeBack}`
}
]
let list = {
date: item.changeTime,
isShow: true,
children: childrenData
}
timelineList.value.push(list)
}
watch(()=>Props.timelineList, (newV) => {
console.log(newV)
if (newV && newV.length > 0){
newV.forEach((item: any) => {
if (timelineList.value.length > 0){
const index = timelineList.value.findIndex((newItem: any) => newItem.date === item.changeTime)
if (index !== -1){
// 该日期已存在,直接往该对象的children里塞
timelineList.value[index].children.push({
lineTitle: item.changeItem,
content: `变更前:${item.changeFront}\n变更后:${item.changeBack}`
},
)
}else {
// 该日期不存在, 创建新对象塞进newArray
newArrayPush(item)
}
}else {
newArrayPush(item)
}
})
console.log(timelineList.value)
}else {
timelineList.value = []
}
})
</script>
CSS:
原点颜色用的element的颜色
background: var(--el-menu-active-color);
<style scoped>
.timeline-wrapper{
padding: 200px 20px;
width: 100%;
min-width: 0;
display: flex;
overflow-x: auto;
}
/*展示时间样式*/
.time{
position: absolute;
top: 15px;
width: 80px;
}
.timeline-wrapper::-webkit-scrollbar {
width: 4px;
height: 12px;
}
.timeline-wrapper::-webkit-scrollbar-thumb {
border-radius: 10px;
-webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.3);
opacity: 0.2;
background-color: #dadada;
}
.timeline-wrapper::-webkit-scrollbar-track {
border-radius: 10px;
-webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.3);
}
/* 时间线 */
.timeline-item {
position: relative;
display: inline-block;
}
.timeline-item .timeline-box {
text-align: center;
display: flex;
align-items: center;
}
/*原点样式*/
.timeline-item .timeline-box .out-circle {
width: 12px;
height:12px;
background: var(--el-menu-active-color);
box-shadow: 0px 4px 12px 0px rgba(0, 0, 0, 0.4);
border-radius: 50%;
display: flex;
align-items: center;
cursor: pointer;
position: relative;
}
.timeline-item .timeline-box .out-circle .in-circle {
width: 8px;
height: 8px;
margin: 0 auto;
background: var(--el-menu-active-color);
border-radius: 50%;
box-shadow: 0px 4px 12px 0px rgba(0, 0, 0, 0.1);
}
.timeline-item .timeline-box .out-circle .timeline-date {
color: #333;
margin-top: 55px;
}
.timeline-item .timeline-box .out-circle .timeline-date .father-text {
font-weight: 900;
font-size: 16px;
margin-left: -15px;
}
.long-line {
height: 2px;
background: rgba(14, 116, 218, 0.2);
box-shadow: 0px 4px 12px 0px rgba(0, 0, 0, 0.3);
display: flex;
flex-direction: revert;
justify-content: space-around;
}
.long-line .sub-item-box {
margin-top: -20px;
position: relative;
}
.long-line .sub-item-box .sub-line-box {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.long-line .sub-item-box .sub-line-box .children-line-box {
width: 0px;
border-left: 1px solid rgba(14, 116, 218, 0.3);
}
.long-line .sub-item-box .sub-line-box .children-box {
width: 100%;
min-width: 250px;
flex-wrap: wrap;
display: flex;
justify-content: center;
align-items: center;
border: 1px solid rgba(14, 116, 218, 0.3);
white-space: break-spaces;
text-align: center;
padding: 5px;
}
.long-line .top-line-box {
margin-top: -100px;
height: 60px;
}
.long-line .bottom-line-box {
margin-top: 5px;
height: 150px;
}
.long-line .top-line {
height: 65px;
}
.long-line .bottom-line {
height: 120px;
}
.long-line .top-children-box {
margin-top: -90px;
background-color: #e2e2e2;
border-radius: 5px;
width: 100px;
}
.long-line .bottom-children-box {
background-color: #e2e2e2;
border-radius: 5px;
width: 150px;
}
.timeline-content {
box-sizing: border-box;
margin-left: 20px;
height: 106px;
padding: 0 0 0 20px;
text-align: left;
margin-bottom: 30px;
}
.timeline-content .timeline-title {
font-size: 14px;
word-break: break-all;
margin-bottom: 16px;
color: #333;
font-weight: 500;
/*display: inline;*/
}
.timeline-content .timeline-desc {
font-size: 14px;
color: #999999;
}
.timeline-item:last-of-type .timeline-content {
margin-bottom: 0;
}
</style>
接口返回数据样式:
逻辑就是根据相同的时间来判断,时间相同就把数据往改时间的对象的children里塞。没有该时间就新push个含有该时间的对象, 然后往这个时间的对象children里塞数据。children里就是轴上下展示的气泡框信息