react+ts实现左右联动

index.tsx中

import { Component, createRef } from "react";
import './index.less'

interface Props {

}
interface NavListType {
    ID: string,
    Content: string
}
interface ContentListType {
    ID: string,
    Content: string
}
interface State {
    Index: number,
    NavList: NavListType[],
    ContentList: ContentListType[],
    // 用来判断是否监听滚动
    listBoxState: boolean
}

class LinkAge extends Component<Props, State>{
    constructor(props: Props) {
        super(props);
        this.state = {
            Index: 0,
            NavList: [
                { ID: "nav1", Content: "按钮1" },
                { ID: "nav2", Content: "按钮2" },
                { ID: "nav3", Content: "按钮3" },
                { ID: "nav4", Content: "按钮4" },
                { ID: "nav5", Content: "按钮5" },
                { ID: "nav6", Content: "按钮6" },
                { ID: "nav7", Content: "按钮7" },
                { ID: "nav8", Content: "按钮8" },
                { ID: "nav9", Content: "按钮9" },
                { ID: "nav10", Content: "按钮10" },
                { ID: "nav11", Content: "按钮11" },
                { ID: "nav12", Content: "按钮12" },
                { ID: "nav13", Content: "按钮13" }
            ],
            ContentList: [
                { ID: "content1", Content: "内容1" },
                { ID: "content2", Content: "内容2" },
                { ID: "content3", Content: "内容3" },
                { ID: "content4", Content: "内容4" },
                { ID: "content5", Content: "内容5" },
                { ID: "content6", Content: "内容6" },
                { ID: "content7", Content: "内容7" },
                { ID: "content8", Content: "内容8" },
                { ID: "content9", Content: "内容9" },
                { ID: "content10", Content: "内容10" },
                { ID: "content11", Content: "内容11" },
                { ID: "content12", Content: "内容12" },
                { ID: "content13", Content: "内容13" }
            ],
            listBoxState: true
        }
    }
    // 定义ref类型
    Nav = createRef<HTMLDivElement>();
    Content = createRef<HTMLDivElement>();
    // 定义EveryHeight类型,这个是内容区每个子元素的高度
    EveryHeight:number=0;
    // 导航点击事件,void是没有返回值
    NavClick(index: number): void {
        this.setState({
            Index: index,
            listBoxState: false
        })
        let el = this.Content.current?.children[index] as HTMLDivElement;
        this.EveryHeight = el.clientHeight;       
        this.ChangedNavScrollHeight(index);
              
        if (this.Content.current) {
            this.Content.current.scrollTop = el.offsetTop;
        }    
    }
    // 改变导航的滚动高
    ChangedNavScrollHeight(index:number): void{
        if (this.Nav.current) {
            if(index<this.state.NavList.length/2){
                this.Nav.current.scrollTop -= 300;
              }
              if (index >= this.state.NavList.length - this.state.NavList.length/2) {
                this.Nav.current.scrollTop += 300;
              }
        }
    }
    // 监听内容区域滚动
    ContentScroll(): void {
        if (this.Content.current) {
            for (let i: number = 0; i < this.Content.current?.children.length; i++) {
                let el = this.Content.current.children[i] as HTMLDivElement;
                if (this.state.listBoxState) {
                    if (this.Content.current.scrollTop >= el.offsetTop) {
                        this.setState({
                            Index: i
                        })
                    }
                    let index = this.state.Index;
                    this.ChangedNavScrollHeight(index);
                }
                // 开启内容区联动导航
                if (this.Content.current.scrollTop === el.offsetTop) {
                    this.setState({
                        listBoxState: true
                    })
                }
            }
        }
    }
    // 随机数
    getRandom(min:number, max:number) {
        return Math.floor(Math.random() * (max - min + 1)) + min;
    }
    // 开局设置
    componentDidMount(): void{
        for(var i=0;i<this.state.ContentList.length;i++){
            if (this.Content.current) {
                // 定义内容区每个子元素的高
                let el = this.Content.current.children[i] as HTMLDivElement;
                el.style.height=this.getRandom(150, 300) + "vh";
            }
        }
    }
    render() {
        let NavList = this.state.NavList;
        let ContentList = this.state.ContentList;

        return (
            <div className="linkage-wrap">
                <div className="nav" ref={this.Nav}>
                    {NavList.map((item, index) => <div className={this.state.Index === index ? 'nav-list active' : 'nav-list'} onClick={this.NavClick.bind(this, index)} key={item.ID}>{item.Content}</div>)}
                </div>
                <div className="content" id='content' ref={this.Content} onScroll={this.ContentScroll.bind(this)}>
                    {ContentList.map((item) => <div className="content-list" key={item.ID}><div className="content-title">{item.Content}</div></div>)}
                </div>
            </div>
        )
    }
}

export default LinkAge;

index.less中

.linkage-wrap {
    display: flex;

    .nav {
        height: 100vh;
        overflow-y: scroll;
        // scroll-behavior: smooth;
        // -webkit-overflow-scrolling: touch;/* 解决ios滑动不流畅问题 */
        font-size: 30px;
        text-align: center;
        color: #fff;

        .nav-list {
            height: 10vh;
            line-height: 10vh;
            width: 20vw;
            background: rgb(46, 143, 253);
        }

        .nav-list.active {
            background-color: rgb(219, 65, 246);
        }
    }

    .content {
        overflow-y: scroll;
        height: 100vh;
        scroll-behavior: smooth;
        -webkit-overflow-scrolling: touch;
        /* 解决ios滑动不流畅问题 */
        transition: 0.3s ease-in all;

        .content-list {
            height: 100vh;
            width: 80vw;
            background-color: rgb(250, 62, 62);
            font-size: 50px;

            .content-title {
                color: #333;
                text-align: center;
                height: 70px;
                background: aqua;
                position: sticky;
                top: 0;
            }
        }
    }


}

以上仅安卓可以用,如要ios使用,需要使用scrollTo方法,并且配合smoothscroll-polyfill。

下载smoothscroll-polyfill

npm install smoothscroll-polyfill --save

如果是ts项目的话还需要下载一个插件

npm i --save-dev @types/smoothscroll-polyfill

在当前页面的tsx文件中引入smoothscroll-polyfill

import smoothscroll from "smoothscroll-polyfill";

在改变scroll值的事件里写

smoothscroll.polyfill();

将上面的this.Content.current.scrollTop = el.offsetTop;改为

this.Content.current.scrollTo({top:el.offsetTop,behavior:"smooth"})

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值