时间轴的实现
<template>
<div class="learnPath">
<div class="part1">
<div class="htitile">学习路径</div>
<div class="parent" ref='parent' @mousedown='handleMouseDome' @mousemove='handleMouseMove' @mouseup='handleMouseUp'>
<div class="timePath" ref='path'>
<div class="year">2019年</div>
<!-- 展开前 -->
<div class="con1" v-if='!openDateList'>
<div class="bor"></div>
<div class="time">
<div class="date" v-for='item in timelist' :key='item.id'>
<div class="txt">{{item.date}}</div>
<div :class="item.active ? 'active circle' : 'circle'"></div>
</div>
</div>
</div>
<!-- 展开后 -->
<div class="con2" v-else ref='con2'>
<div class="track">
<div class="traL"></div>
<div class="traC">
<ol>
<li>
<time>
05:30
</time>
<i></i>
</li>
<li>
<time>
05:30
</time>
<i></i>
</li>
<li>
<time>
05:30
</time>
<i></i>
</li>
<li>
<time>
05:30
</time>
<i></i>
</li>
<li>
<time>
05:30
</time>
<i></i>
</li>
<li>
<time>
05:30
</time>
<i></i>
</li>
<li>
<time>
05:30
</time>
<i></i>
</li>
<li>
<time>
05:30
</time>
<i></i>
</li>
<li>
<time>
05:30
</time>
<i></i>
</li>
<li>
<time>
05:30
</time>
<i></i>
</li>
</ol>
</div>
<div class="traR">
<time>
05:30
</time>
<i class="active"></i>
</div>
</div>
<div class="track">
<div class="traL">
<time>
05:30
</time>
<i></i>
</div>
<div class="traC">
<ol>
<li>
<time>
05:30
</time>
<i></i>
</li>
<li>
<time>
05:30
</time>
<i></i>
</li>
<li>
<time>
05:30
</time>
<i></i>
</li>
<li>
<time>
05:30
</time>
<i></i>
</li>
<li>
<time>
05:30
</time>
<i></i>
</li>
<li>
<time>
05:30
</time>
<i></i>
</li>
<li>
<time>
05:30
</time>
<i></i>
</li>
<li>
<time>
05:30
</time>
<i></i>
</li>
<li>
<time>
05:30
</time>
<i></i>
</li>
</ol>
</div>
<div class="traR"></div>
</div>
<!-- <div class="track">
<div class="traL"></div>
<div class="traC"></div>
<div class="traR"></div>
</div> -->
</div>
<!-- 按钮 -->
<div class="open" @click='handleOrC'>
<i class="el-icon-arrow-up" v-if='openDateList'></i>
<i class="el-icon-arrow-down" v-else></i>
</div>
<!-- 放大按钮 -->
<div class="enlarge" v-if='openDateList'>
<div class="percentage">{{maxScale*100 + '%'}}</div>
<div class="add" @click='handleAdd'>
<i class="el-icon-plus"></i>
</div>
<div class="reduce" @click='handleReduce'>
<i class="el-icon-minus"></i>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { Icon } from 'element-ui'
import KnowNew from '@components/myCourse/knowNew'
import CardTemplate from '@components/myCourse/cardTemplate'
export default {
data() {
return {
timelist:[
{
date: '05.10',
id: 0,
active: true
},
{
date: '05.15',
id: 1,
active: true
},
{
date: '05.20',
id: 2,
active: true
},
{
date: '05.25',
id: 3,
active: false
},
{
date: '05.30',
id: 4,
active: false
},
{
date: '06.05',
id: 5,
active: false
},
{
date: '06.15',
id: 6,
active: false
},
{
date: '06.20',
id: 7,
active: false
},
],
openDateList: false,
boxX: null,
boxY: null,
isDrop: false, // 判断能否拖动
maxScale: 1
}
},
components: {
KnowNew,
CardTemplate
},
mounted () {
if (this.openDateList){
this.setItemPosition()
}
window.onmouseup = () => {
this.isDrop = false
}
},
methods: {
setItemPosition () {
const item = this.$refs.con2.children
const topBor = item[0].children[0]
let topBorH = getComputedStyle(topBor, null).borderTop
topBorH = parseInt(topBorH)
for (let i = 0; i < item.length; i++) {
const lis = item[i]
const tops = -i * topBorH
lis.style.top = tops + 'px'
}
},
// 展开或者关闭时间图
handleOrC() {
this.maxScale = 1
this.openDateList = !this.openDateList;
this.$refs.path.style.top = 0;
this.$refs.path.style.left = 0
this.setAnimation()
},
// 放大功能
handleAdd() {
if (this.maxScale >= 2) {
this.maxScale = 2
} else {
this.maxScale += 0.5
}
this.setAnimation()
},
// 缩小功能
handleReduce() {
if (this.maxScale <=1 ) {
this.maxScale = 1
} else {
this.maxScale -= 0.5
}
if (this.maxScale == 1) {
this.$refs.path.style.left = 0;
this.$refs.path.style.top = 0;
} else if (this.maxScale == 1.5) {
this.$refs.path.style.right = 0;
this.$refs.path.style.top = 0;
this.$refs.path.style.left = 0
}
this.setAnimation()
},
// 动画过度
setAnimation() {
this.$refs.path.style.transform = 'scale('+this.maxScale +')'
this.$refs.path.style.webkitTransform = 'scale('+this.maxScale +')'
this.$refs.path.style.msTransform = 'scale('+this.maxScale +')'
this.$refs.path.style.oTransform = 'scale('+this.maxScale +')'
this.$refs.path.style.mozTransform = 'scale('+this.maxScale +')'
this.$refs.path.style.cursor = 'pointer'
this.$refs.path.style.transition = 'transform 0.3s'
this.$refs.path.style.webkitTransition = 'transform 0.3s'
this.$refs.path.style.msTransition = 'transform 0.3s'
this.$refs.path.style.oTransition = 'transform 0.3s'
this.$refs.path.style.mozTransition = 'transform 0.3s'
},
// 鼠标按下事件
handleMouseDome(e) {
let box = this.$refs.path
var e = e || window.event;//要用event这个对象来获取鼠标的位置
this.boxX = e.clientX - box.offsetLeft;
this.boxY = e.clientY - box.offsetTop;
this.isDrop = true;//设为true表示可以移动
},
// 鼠标拖动事件
handleMouseMove(e) {
if (this.maxScale == 1) {
return
}
//是否为可移动状态
if(this.isDrop && this.openDateList) {
let e = e || window.event
let moveX = e.clientX - this.boxX;//得到距离左边移动距离
let moveY = e.clientY - this.boxY;//得到距离上边移动距离
this.setBor(moveX, moveY)
}
},
setBor(x, y) {
let moveX = x
let moveY = y
if(this.maxScale == 2) {
let wX = this.$refs.parent.offsetWidth / 2
let hY = this.$refs.parent.offsetHeight / 2
if(moveX > wX) {
moveX = wX
} else if (-wX > moveX ){
moveX = -wX
}
if(moveY > hY ) {
moveY = hY
} else if (-hY > moveY) {
moveY = -hY
}
} else if (this.maxScale == 1.5) {
let wX = this.$refs.parent.offsetWidth / 4
let hY = this.$refs.parent.offsetHeight / 4
if(moveX > wX) {
moveX = wX
} else if (-wX > moveX ){
moveX = -wX
}
if(moveY > hY ) {
moveY = hY
} else if (-hY > moveY) {
moveY = -hY
}
}
this.$refs.path.style.left = moveX + "px";
this.$refs.path.style.top = moveY + "px";
},
// 鼠标弹起
handleMouseUp() {
this.isDrop = false
this.$refs.parent.mousemove = null
document.onmouseup = () => {
this.$refs.parent.mousemove = null
}
},
},
}
</script>
<style lang='scss' scoped>
.learnPath{
width: 100%;
height: 100%;
box-sizing: border-box;
padding: 0px 30px;
.htitile{
padding: 32px 0px 19px 0px;
border-bottom: 1px solid #E6E8E9;
}
.parent{
overflow: hidden;
position: relative;
margin-top: 12px;
}
.timePath{
width: 100%;
/* height: 162px; */
background-color: #E8F1EC;
position: relative;
overflow: hidden;
.year{
text-align: center;
font-size: 20px;
font-family: SourceHanSansCN-Bold;
font-weight: bold;
color: #319F60;
width: 100%;
padding: 20px 0;
}
.con1{
width: 100%;
position: relative;
/* padding: 42px 0; */
padding-top: 42px;
color: #4BBE7C;
.bor{
width: 100%;
height: 2px;
background: #5BCA8A;
}
.time{
position: absolute;
/* top: -25px; */
top: 5px;
width: 100%;
display: flex;
.date{
margin: 0px 38px;
.txt{
padding-bottom: 10px;
}
}
.circle{
width:18px;
height:18px;
margin: 0 auto;
background:#EDF8F2;
border:2px solid rgba(128, 206, 161, 1);
box-shadow:0px 4px 8px 0px rgba(75, 128, 199, 0.35);
border-radius:50%;
}
}
}
.active{
background:linear-gradient(-36deg,rgba(79,185,124,1),rgba(107,224,157,1)) !important;
}
.con2{
position: relative;
margin-top: 45px;
color: #4BBE7C;
font-weight:400;
.track{
width: 892px;
/* flex: 1; */
height: 100px;
margin: 0 auto;
padding:0;
display: flex;
position: relative;
&:nth-of-type(1){
div:nth-of-type(1){
display: none !important;
}
.traC{
width: 90%;
}
}
&:nth-of-type(odd){
div:first-child{
visibility: hidden;
}
}
&:nth-of-type(even){
div:last-child{
visibility: hidden;
}
}
.traL{
width: 100px;
height: 100%;
box-sizing: border-box;
border: 2px solid #5BCA8A;
border-radius: 100% 0 0 100%;
border-right: none;
line-height: 100px;
time{
display: block;
text-align: right;
padding-right: 36px;
}
i{
position: absolute;
left: -9px;top: 50%;
width: 18px;
height: 18px;
margin: -9px 0 0 0;
box-sizing: border-box;
border: 2px solid #80CEA1;
background: #fff;
border-radius: 50%;
}
}
.traC{
width: 80%;
height: 100px;
border-top: 2px solid #5BCA8A;
box-sizing: border-box;
ol{
width: 110%;
height: 50%;
position: relative;
top: -50%;
display: flex;
left: -5%;
z-index: 10;
li{
flex: 1;
position: relative;
text-align: center;
line-height: 50px;
time{
display: block;
font-size: 16px;
}
i{
position: absolute;
left: 50%;
bottom: -9px;
width: 18px;
height: 18px;
box-sizing: border-box;
border: 2px solid #80CEA1;
border-radius: 50%;
margin: 0 0 0 -9px;
background: #fff;
}
}
}
}
.traR{
width: 100px;
height: 100%;
border: 2px solid #5BCA8A;
border-radius: 0 100% 100% 0;
border-left: none;
box-sizing: border-box;
line-height: 100px;
position: relative;
time{
display: block;
text-align: left;
padding-left: 36px;
}
i{
position: absolute;
right: -9px;top: 50%;
width: 18px;
height: 18px;
margin: -9px 0 0 0;
box-sizing: border-box;
border: 2px solid #80CEA1;
background: #fff;
border-radius: 50%;
}
}
}
}
.open{
width:60px;
height:16px;
background:#80CEA1;
border-radius:10px 10px 0px 0px;
color: #fff;
font-weight: bold;
text-align: center;
font-size: 18px;
margin: 30px auto 0;
}
.enlarge{
position: absolute;
top: 20px;
right: 15px;
line-height: 24px;
text-align: center;
color: #fff;
div{
display: inline-block;
margin-right: 5px;
}
.percentage{
width:60px;
height:24px;
background:#ACD7BE;
border-radius:12px;
}
.add{
width:24px;
height:24px;
background:rgba(24,170,31,1);
border-radius:2px;
}
.reduce{
width:24px;
height:24px;
background:rgba(24,170,31,1);
border-radius:2px;
}
}
}
}
</style>
备注:
该组件主要是实现弧形样式的实现,还有div的放大和缩小动画的实现,以及鼠标按下拖动效果的实现