模拟antd-mobile的tabs组件,带小滑块(第一种方式不带头部滑动,第二种带)

103 阅读2分钟

第一种tsx部分

import { Component } from 'react'
import './index.scss'
export default class index extends Component {
  state = { start: 0, move: 0, index: 0, arr: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] }
  render() {
    const { start, move, index, arr } = this.state
    return (
      <div className='app'>
        <div className='ul'>
          <div
            className='ulSub'
            style={{ left: index > 0 && index < 7 ? -75 * index + 75 : index === 0 ? 0 : -375 }}
          >
            <div className='slide' style={{ left: 75 * index + 18 }}></div>
            {arr.map((e, i) => (
              <div
                className={index === i ? 'active' : ''}
                onTouchStart={(e) => this.setState({ index: i })}
              >
                {e}
              </div>
            ))}
          </div>
        </div>
        <div
          className='sub'
          style={{ left: index * -375 }}
          onTouchStart={(e) => this.setState({ start: e.changedTouches[0].pageX, move: 0 })}
          onTouchMove={(e) => this.setState({ move: e.changedTouches[0].pageX - start })}
          onTouchEnd={(e) => {
            if (move > 50) index > 0 && this.setState({ index: index - 1 })
            else if (move < -50) index < 9 && this.setState({ index: index + 1 })
          }}
        >
          {arr.map((e) => (
            <div>{e}</div>
          ))}
        </div>
      </div>
    )
  }
}

第二种scss部分

.app {
  position: absolute;
  width: 100%;
  height: 100%;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  .sub {
    position: relative;
    width: 1000%;
    height: 90vh;
    display: flex;
    transition: .6s;
    div {
      width: 100vw;
      height: 100%;
      text-align: center;
      line-height: 100vh;
      font-size: 100px;
    }
  }
  .ul {
    position: relative;
    width: 100vw;
    height: 10vh;
    top: 0;
    background-color: red;

    .ulSub {
      transition: .6s;
      position: absolute;
      width: 200vw;
      height: 100%;
      background-color: pink;
      display: flex;
      div {
        width: 20vw;
        height: 100%;
        text-align: center;
        line-height: 10vh;
        border: 1px solid #000;
      }
      .slide {
        position: absolute;
        width: 10vw;
        height: 10px;
        border-radius: 5px;
        background-color: red;
        top: 9vh;
        z-index: 20;
        transition: .1s;
      }
      .active {
        font-weight: 700;
        font-size: 30px;
      }
    }
  }
}

第二种tsx部分

import { Component } from 'react'
import './index.scss'
export default class index extends Component {
  state = { start: 0, move: 0, index: 0, arr: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] }
  componentDidUpdate() {
    const { index } = this.state
    ;(this.refs.ul as HTMLDivElement).scrollLeft =
      index > 0 && index < 7 ? 75 * index - 75 : index === 0 ? 0 : 375
  }
  render() {
    const { start, move, index, arr } = this.state
    return (
      <div className='app'>
        <div className='ul' ref={'ul'}>
          <div className='ulSub'>
            <div className='slide' style={{ left: 75 * index + 18 }}></div>
            {arr.map((e, i) => (
              <div className={index === i ? 'active' : ''} onTouchStart={(e) => this.setState({ index: i })}>
                {e}
              </div>
            ))}
          </div>
        </div>
        <div
          className='sub'
          style={{ left: index * -375 }}
          onTouchStart={(e) => this.setState({ start: e.changedTouches[0].pageX, move: 0 })}
          onTouchMove={(e) => this.setState({ move: e.changedTouches[0].pageX - start })}
          onTouchEnd={(e) => {
            if (move > 50) index > 0 && this.setState({ index: index - 1 })
            else if (move < -50) index < 9 && this.setState({ index: index + 1 })
          }}
        >
          {arr.map((e) => (
            <div>{e}</div>
          ))}
        </div>
      </div>
    )
  }
}

第二种scss部分

* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}
.app {
  position: absolute;
  width: 100%;
  height: 100%;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  .sub {
    position: relative;
    width: 1000%;
    height: 90vh;
    display: flex;
    transition: 0.6s;
    div {
      width: 100vw;
      height: 100%;
      text-align: center;
      line-height: 100vh;
      font-size: 100px;
    }
  }
  .ul {
    position: relative;
    width: 100vw;
    height: 10vh;
    top: 0;
    background-color: red;
    overflow-x: scroll;
    scroll-behavior: smooth;
    &::-webkit-scrollbar {
      display: none;
    }

    .ulSub {
      position: relative;
      transition: 0.6s;
      width: 200vw;
      height: 100%;
      background-color: pink;
      display: flex;
      ::-webkit-scrollbar {
        display: none;
      }
      div {
        width: 20vw;
        height: 100%;
        text-align: center;
        line-height: 10vh;
      }
      .slide {
        position: absolute;
        width: 10vw;
        height: 10px;
        border-radius: 5px;
        background-color: red;
        top: 8vh;
        z-index: 20;
        transition: 0.1s;
      }
      .active {
        font-weight: 700;
        font-size: 30px;
      }
    }
  }
}