js部分
import React, { Component, createRef } from 'react'
import './linkage.less'
interface Props {
}
interface Content {
ID: string,
text: string,
top: number,
height: number
}
interface Button {
ID: string,
text: string
}
interface State {
ButtonList: Button[]
ContentList: Content[],
ButtonListIndex: number,
}
class Linkage extends Component<Props, State>{
FnButtonList: Button[] = []
FnContentList: Content[] = []
right = createRef<HTMLDivElement>()
linkageButtonItem = createRef<HTMLDivElement>()
linkageButton = createRef<HTMLDivElement>()
linkageButtonList = createRef<HTMLDivElement>()
linkageContent = createRef<HTMLDivElement>()
num: number = 0
ScrollSwitch: boolean = true
constructor(props: Props) {
super(props)
this.state = {
ButtonList: [],
ContentList: [],
ButtonListIndex: 0,
}
}
Getright() {
return this.right.current as HTMLDivElement
}
GetButtonItem() {
return this.linkageButtonItem.current as HTMLDivElement
}
GetBitton() {
return this.linkageButton.current as HTMLDivElement
}
GetButtonList() {
return this.linkageButtonList.current as HTMLDivElement
}
GetContent() {
return this.linkageContent.current as HTMLDivElement
}
//封装随机数
FnSetRandom(m: number, n: number) {
return parseInt(`${Math.random() * (m - n) + n}`);
}
componentDidMount() {
//左侧内容渲染
this.FnSetButton(15)
this.setState({
ButtonList: this.FnButtonList
})
//右侧内容渲染
this.FnSetContent(15)
this.setState({
ContentList: this.FnContentList
})
}
//渲染左侧标题
FnSetButton(n: number) {
for (var i = 1; i < n; i++) {
this.FnButtonList.push({
ID: `id${i}`,
text: `标题${i}`
})
}
}
//渲染右侧内容
FnSetContent(n: number) {
let num = 0;
for (let i = 1; i < n; i++) {
let Random = this.FnSetRandom(750, 1400)
this.FnContentList.push({
height: Random,
ID: `id${i}`,
text: `内容${i}`,
top: num,
})
num += Random;
}
}
// 点击左边右边跟着动
FnButton(index: number) {
this.ScrollSwitch = false
this.setState({
ButtonListIndex: index
})
// 右边的盒子距离上面滚动的距离 = 当前右边子级盒子的height
this.GetContent().scrollTop = (this.Getright().children[index] as HTMLDivElement).offsetTop
// 把index传过去
this.FnCurrent(index)
}
// 左边的hover效果居中
FnCurrent(index: number) {
//当下标大于5的时候 这边处理的是下边的情况
if (index > 5) {
// 左边盒子滚动的距离上边的距离 = 当前点击的下标-5 * 左边父盒子的高
this.GetBitton().scrollTop = (index - 5) * this.GetButtonList().offsetHeight
}
if (index < 5) {
// 让他的第一个盒子显示出来
this.GetBitton().scrollTop = 0
}
}
// 右边的滚动监听
FnScroll() {
if (this.GetContent()) {
this.num = this.GetContent().scrollTop
if (this.ScrollSwitch) {
let n = 0
for (let i = 0; i<this.state.ContentList.length; i++) {
if (this.GetContent().scrollTop >= this.state.ContentList[i].top) {
n = i
}
}
this.setState({
ButtonListIndex: n
})
this.FnCurrent(n)
}
if (this.num === this.state.ContentList[this.state.ButtonListIndex].top) {
this.ScrollSwitch = true
}
}
}
render() {
return (
<div className="linkage">
<div className="linkage-button" ref={this.linkageButton}>
<div className="linkage-button-list" ref={this.linkageButtonList}>
{this.state.ButtonList.map((item, index) => <div
className={this.state.ButtonListIndex === index ? 'linkage-button-item ac' : 'linkage-button-item'}
key={item.ID}
onClick={this.FnButton.bind(this, index)}
ref={this.linkageButtonItem}
>
{item.text}
</div>)}
</div>
</div>
<div className="linkage-content" ref={this.linkageContent} onScroll={this.FnScroll.bind(this)}>
<div className="linkage-content-list" ref={this.right}>
{this.state.ContentList.map((item) => <div
className="linkage-content-item"
style={{ height: item.height + 'px' }}
key={item.ID}>
<div className="linkage-content-title"> {item.text}</div>
</div>)}
</div >
</div >
</div >
)
}
}
export default Linkage
css部分
body {
margin: 0;
}
.linkage {
width: 100vw;
height: 100vh;
display: flex;
.linkage-button {
width: 30vw;
height: 100vh;
background: rgb(2, 252, 239);
text-align: center;
font-size: 26px;
color: #fff;
overflow: scroll;
scroll-behavior: smooth;
.linkage-button-list {
width: 30vw;
.linkage-button-item.ac {
background: pink;
}
.linkage-button-item {
width: 30vw;
height: 10vh;
line-height: 10vh;
}
}
}
.linkage-content {
width: 73vw;
height: 100vh;
scroll-behavior: smooth;
overflow: scroll;
.linkage-content-list {
.linkage-content-item {
width: 73vw;
height: 100vh;
.linkage-content-title {
position: sticky;
top: 0;
height: 10vh;
line-height: 10vh;
width: 73vw;
text-align: center;
background: aqua;
color: #fff;
font-size: 26px;
}
}
}
}
}
.linkage-button::-webkit-scrollbar {
display: none;
/* Chrome Safari */
}
.linkage-content::-webkit-scrollbar {
display: none;
/* Chrome Safari */
}