页面需求:
点击左侧版本号,右侧展示对应版本内容并置于顶部 右侧某一内容滚动到顶部时,左侧需要展示高亮
实现效果:
实现代码:
< template>
< div>
< div class = " historyBox pd-20 bg-white" >
< div class = " w100 flex h100" v-if = " versionList.length > 0" >
< div class = " left size-14" >
< div
v-for = " (item, index) in versionList"
:key = " index"
class = " leftItem pd-10 pointer"
:class = " index == activeIndex ? 'isActive' : ''"
@click = " gotoTarget(index)"
>
< div> {{ item.versionNumber }}</ div>
< div> {{ item.releaseTime }}</ div>
</ div>
</ div>
< div class = " right" >
< div
v-for = " (item, index) in versionList"
:key = " index"
class = " rightItem pd-20 center"
:class = " index == activeIndex ? 'isActive' : ''"
>
< div v-html = " item.versionDescription" class = " ql-editor w60" > </ div>
</ div>
</ div>
</ div>
< div class = " w100 h100 center size-16 gray-2" v-else > 暂无版本记录</ div>
</ div>
</ div>
</ template>
< script>
import { listAllVersion } from "./components/api" ;
export default {
name : "VersionHistory" ,
data ( ) {
return {
versionList : [ ] ,
activeIndex : 0 ,
clickIndex : 0 ,
scrollIndex : 0 ,
scrollStopTimer : null ,
} ;
} ,
created ( ) {
this . getList ( ) ;
} ,
mounted ( ) { } ,
methods : {
checkItemsHover ( ) {
const rightBox = document. querySelector ( ".right" ) ;
rightBox. addEventListener ( "scroll" , this . checkItemsAtTop) ;
window. addEventListener ( "load" , this . checkItemsAtTop) ;
} ,
checkItemsAtTop ( ) {
const rightBox = document. querySelector ( ".right" ) ;
const rightItems = Array. from ( rightBox. querySelectorAll ( ".rightItem" ) ) ;
rightItems. forEach ( ( item, index ) => {
const rect = item. getBoundingClientRect ( ) ;
const containerRect = rightBox. getBoundingClientRect ( ) ;
if (
rect. top - containerRect. top <= 0 &&
rect. bottom - containerRect. top >= 0
) {
this . scrollIndex = index;
}
if ( this . scrollStopTimer) {
clearTimeout ( this . scrollStopTimer) ;
}
this . scrollStopTimer = setTimeout ( this . onScrollStopped, 150 ) ;
} ) ;
} ,
onScrollStopped ( ) {
if ( this . scrollIndex < this . clickIndex) {
this . activeIndex = this . clickIndex;
this . clickIndex = 0 ;
} else {
this . activeIndex = this . scrollIndex;
}
const leftItems = document. querySelectorAll ( ".leftItem" ) ;
const leftBox = document. querySelector ( ".left" ) ;
const targetLeftItem = leftItems[ this . activeIndex] ;
const offsetTop = targetLeftItem. offsetTop - leftBox. offsetTop;
leftBox. scrollTo ( {
top : offsetTop,
behavior : "smooth" ,
} ) ;
} ,
gotoTarget ( index ) {
this . clickIndex = index;
this . activeIndex = index;
const rightItems = document. querySelectorAll ( ".rightItem" ) ;
const rightBox = document. querySelector ( ".right" ) ;
const targetRightItem = rightItems[ index] ;
const offsetTop = targetRightItem. offsetTop - rightBox. offsetTop + 1 ;
rightBox. scrollTo ( {
top : offsetTop,
behavior : "smooth" ,
} ) ;
} ,
getList ( ) {
listAllVersion ( ) . then ( ( response ) => {
this . versionList = response. data;
this . $nextTick ( ( ) => {
this . checkItemsHover ( ) ;
} ) ;
} ) ;
} ,
} ,
} ;
</ script>
< style lang = " scss" scoped >
@import "./components/quill.snow.css" ;
.historyBox {
height : calc ( 100vh - 90px) ;
::-webkit-scrollbar {
width : 6px;
// height : 24px;
}
::-webkit-scrollbar-track {
background : #eee;
}
::-webkit-scrollbar-thumb {
background : rgba ( 0, 0, 0, 0.1) ;
background : rgb ( 158, 203, 255) ;
border-radius : 12px;
&:hover {
background : rgb ( 95, 169, 253) ;
}
}
.left {
width : 260px;
min-width : 260px;
height : 100%;
// height : calc ( 100vh - 117px) ;
overflow-y : auto;
.leftItem {
display : flex;
justify-content : space-evenly;
align-items : center;
border : 1px solid #eee;
}
.isActive {
border : 1px solid #3f8cff;
border-left : 4px solid #3f8cff;
color : #3f8cff;
background : rgba ( 63, 140, 255, 0.1) ;
font-weight : bold;
}
}
.right {
box-sizing : border-box;
width : calc ( 100% - 260px) ;
height : 100%;
// height : calc ( 100vh - 117px) ;
overflow-y : auto;
background : #eef6ff;
.rightItem {
border : 1px dotted #eef6ff;
&:hover {
border : 1px dotted #ddd;
}
.w60 {
width : 60%;
}
}
.isActive {
// border : 1px dotted #ddd;
border : 1px dotted #3f8cff;
// box-shadow : 0px 0px 20px #3f8cff;
// box-shadow : 0px 5.04px 10.08px rgba ( 55, 114, 233, 0.22) ,
// inset 0px 5.04px 10.08px rgba ( 211, 221, 242, 1) ;
}
}
}
</ style>