Typescript 实现左右联动

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 */
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值