Using react to make a slide carousel display component

Time:2020-8-2

Rules of the river and lake ~ no picture, no truth, first picture!

Using react to make a slide carousel display component
This is a slide rotation component of the exhibition list. You can click the left and right buttons to slide left and right. You can slide the specified number of lines each time, and how many lines of content can be displayed.

I’m a rookie in front of me, and big guys are whistling

Let’s share the code

Because I use react + typescript to do the project, if you don’t understand it, it doesn’t matter! Change to ordinary HTML and JS are similar.

use

<Slider cityList={cityList} row={2} step={2} />

Component code

import React, { Component, ComponentType } from 'react'
import { Icon } from 'antd'

import './index.scss'

interface IProps {
  cityList: Array<number>,
  row: number,
  step: number
}

interface IStates {
  cityContainerWidth: number,
  cityWrapWidth: number,
  cityWrapTranslateX: number
}

class Slider extends Component<IProps, IStates> {
  constructor(props: IProps) {
    super(props)
    this.state = {
      cityContainerWidth: 0,
      cityWrapWidth: 0,
      cityWrapTranslateX: 0
    }
  }

  componentDidMount(): void {
    const { cityList, row } = this.props
    const cityWrapWidth: number = cityList.length > 12 ? Math.ceil(cityList.length / row) * 220 : 1320
    const cityWrapDom: HTMLElement | null = document.getElementById('city__wrap') as HTMLElement
    const cityContainerDom: HTMLElement | null = document.getElementById('city__container') as HTMLElement
    const cityContainerWidth: number = cityContainerDom.offsetWidth
    cityWrapDom && (cityWrapDom.style.width = `${cityWrapWidth}px`)

    this.setState({
      cityContainerWidth,
      cityWrapWidth
    })
  }

  handleArrowClick(direction: string): void {
    const { step } = this.props
    const { cityContainerWidth, cityWrapWidth, cityWrapTranslateX } = this.state
    const cityWrapDom: HTMLElement | null = document.getElementById('city__wrap') as HTMLElement
    /*Step size*/
    const translateStep: number = 220 * step
    const translateDistance: number = translateStep * (direction === 'left' ? 1 : -1)

    let newTranslateX: number = cityWrapTranslateX
    /*Relative moving distance*/
    const relativeTranslateX: number = cityContainerWidth - cityWrapTranslateX
    const isLeftEnd: boolean = relativeTranslateX <= cityContainerWidth
    const isLeftOverflow: boolean = relativeTranslateX - translateDistance <= cityContainerWidth
    Const isrightend: Boolean = relativetranslatex + 10 > = citywrappwidth // this 10 represents 10 pixels of the right margin, plus 10 hidden
    const isRightOverflow: boolean = relativeTranslateX - translateDistance >= cityWrapWidth

    /*Click the left arrow*/
    if (translateDistance > 0) {
      /*Is it at the end of the left*/
      if (isLeftEnd) return

      if (isLeftOverflow) {
        /*Out of range, slide just to the left end of the distance*/
        newTranslateX = 0
      } else {
        /*Within the range, the sliding distance is directly added to the step size*/
        newTranslateX += translateDistance
      }

    } else if (translateDistance < 0) {
      /*Is it at the right end*/
      if (isRightEnd) return

      if (isRightOverflow) {
        /*Out of range, slide just to the end of the right*/
        newTranslateX += relativeTranslateX + 10 - cityWrapWidth
      } else {
        /*Within the range, the sliding distance is directly added to the step size*/
        newTranslateX += translateDistance
      }
    }

    const transformString: string = `translateX(${newTranslateX}px)`
    cityWrapDom && (cityWrapDom.style.transform = transformString)
    this.setState({
      cityWrapTranslateX: newTranslateX
    })
  }

  render() {
    const { cityList } = this.props
    return (
      <div className="city" >
        <div className="city__ Title "> I am a rotation chart < / div >
        <div className="city__container" id="city__container">
          <div className="city__arrow" onClick={() => this.handleArrowClick('left')}>
            <Icon className="icon" type="left" />
          </div>
          <div className="city__arrow city__arrow--right" onClick={() => this.handleArrowClick('right')}>
            <Icon className="icon" type="right" />
          </div>
          <div className="city__wrap" id="city__wrap">
            {cityList.map(item => (
              <div className="city__item" key={item}>{item}</div>
            ))}
          </div>
        </div>
      </div>
    )
  }
}

export default Slider as ComponentType<IProps>

Style file (SASS is used for style writing)

.city {
  &__container {
    position: relative;
    overflow: hidden;
    width: 1200px;
    padding-top: 10px;

    &::-webkit-scrollbar {
      width: 15px;
      height: 15px;
    }

    &::-webkit-scrollbar-track {
      border-radius: 20px;
      background: #e7e7e7;
    }

    &::-webkit-scrollbar-thumb {
      background: #66a6ff;
      background-image: linear-gradient(120deg, #89a4fe 0%, #66a6ff 100%);
      border-radius: 20px;
    }
  }

  &__title {
    margin-top: 30px;
    color: #333;
    font-size: 24px;
    font-weight: bold;
  }

  &__arrow {
    position: absolute;
    display: flex;
    justify-content: center;
    align-items: center;
    top: 50%;
    width: 50px;
    height: 100px;
    background: rgba(0, 0, 0, 0.7);
    transform: translateY(-50%);
    transition: all .3s ease;
    z-index: 2;
    opacity: .5;
    cursor: pointer;

    &--right {
      right: 0;
    }

    .icon {
      color: #fff;
      font-size: 30px;
    }

    &:hover{
      opacity: 1;
    }
  }

  &__wrap {
    transition: all .3s ease-in-out;
  }

  &__item {
    float: left;
    width: 210px;
    height: 90px;
    margin: 0 10px 10px 0;
    color: #fff;
    font-size: 40px;
    font-weight: bold;
    line-height: 90px;
    text-align: center;
    // background: url(https://static.zhipin.com/zhipin-geek/v98/web/geek/images/city_101010100.png) no-repeat;
    // background-size: cover;
    background-image: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  }
}

Finally, it’s hereitemList

This is a list of data that will be used for presentation. Here we can use the function to generate a list for display. If you need to, you can change it to the list obtained by the provider

  getCityList(): Promise<Array<number>> {
    return new Promise(async (resolve, reject) => {
      const length: number = 15
      const cityList: Array<number> = Array.from({ length }, (_: unknown, index: number): number => index + 1)
      resolve(cityList)
    })
  }

Here we generate an array of natural numbers with a length of 15[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]

code analysis

Although there are comments in the code, but still a brief share of it~

The steps are, of course:
Get the data list to be displayed, then input the list to the sliding carousel component, and then set the dynamic width of the container according to the length of the list and the number of rows to be displayed

In the next is the play!!!

I’ve done a lot of work on how to handle the sliding of containers. Let’s take a look at them bit by bit

  1. Listen for functions that click the arrow button

handleArrowClick(direction)This function means that when you click the left arrow, the direction isleftOn the contrary, it isright

  <div className="city__arrow" onClick={() => this.handleArrowClick('left')}>
    <Icon className="icon" type="left" />
  </div>
  <div className="city__arrow city__arrow--right" onClick={() => this.handleArrowClick('right')}>
    <Icon className="icon" type="right" />
  </div>

They are left and right arrows. Click the left arrow to pass in a string to represent the direction of the function

  1. Define step size
/*Step size*/
const translateStep: number = 220 * step
const translateDistance: number = translateStep * (direction === 'left' ? 1 : -1)

This is very simple. It is passed in according to the parent componentstepStep size (how many elements to slide at a time) and the direction passed in when the button is clicked. If it’s left, the distance to move is-Step sizeHere, we use the property of transform: translatex to slide, and the positive axis is to the right. So if you want to show the content to move to the right, you need to set the moving distance to a negative number. In this way, the relative movement can achieve the desired effect. Now, it doesn’t matter. Let’s continue to look back,

  1. Get the moving distance and judge whether it is beyond the range

Key points!!! Key points!!! Key points!!!

First, we first set the state, which defines a variable to represent the sliding distance, with an initial value of 0

/*Sliding distance*/
this.state = {
  cityWrapTranslateX: 0
}

Then we get the width of the outer container and the content container of the sliding component. If we don’t understand, we can implement the principle of the carousel diagram, and briefly explain it

Using react to make a slide carousel display component

The outer container is the visible part, while the inner container is a part that will be hidden. Then, according to the size of the outer container, the contents in the content container can be displayed, that is, the overlapped part in the figure. Imagine that when the content container moves from left to right, are the things in the outer container moving along with it~

Good, do not understand can go to Baidu to find a more detailed principle of the rotation chart! I will continue to analyze

/*Relative moving distance*/
const relativeTranslateX: number = cityContainerWidth - cityWrapTranslateX

Then we get the size of the incoming outer containercityContainerWidthAnd the distance that has slippedcityWrapTranslateXBy subtracting the two, we can get the relative moving distance. What does this mean? Let’s continue to talk about various boundary conditions, and you will understand it!

const isLeftEnd: boolean = relativeTranslateX <= cityContainerWidth
const isLeftOverflow: boolean = relativeTranslateX - translateDistance <= cityContainerWidth
Const isrightend: Boolean = relativetranslatex + 10 > = citywrappwidth // this 10 represents 10 pixels of the right margin, plus 10 hidden
const isRightOverflow: boolean = relativeTranslateX - translateDistance >= cityWrapWidth

The four variables are: have you reached the left end (can’t click again!) Click on the left side of the button to see if it will overflow (that is, the slide is too far!) Whether it reaches the right end or not, and whether the right side of the button will overflow

Let’s mainly analyze the last two, which are similar (because I like the right side)
Let’s assume that the width of the outer container is 1200 and that of the inner container is 2000

  • isRightEnd
/*Relative moving distance*/
const relativeTranslateX: number = cityContainerWidth - cityWrapTranslateX
Const isrightend: Boolean = relativetranslatex + 10 > = citywrappwidth // this 10 represents 10 pixels of the right margin, plus 10 hidden

Let’s ignore the 10 first, because each element has an outer margin of 10px, so we add that we can ignore it first

Using react to make a slide carousel display component
Why is this the case? If our moving distance is 0, then the relative distance is the width of the outer container, which is 1200. Then the content container is 2000, which is smaller than the content container

Now let’s move 800 PX to the right, socityWrapTranslateXThat’s – 800 (remember that the content left is negative At this time, our relative moving distance is 1200 – (- 800) is 2000, which is the same as the content device

Using react to make a slide carousel display component
do you understand? This is equivalent to that the outer container moves 800px to the right. As we said before, the outer container is the visual part that controls us, so the outer container to the right is equal to the right of the content!

And then we’re looking at thisconst isRightEnd: boolean = relativeTranslateX + 10 >= cityWrapWidthIs it clear that if it is greater than or equal to, it represents the end. If you click again, it will return directly and it will not be executed

  • isRightOverflow

This means that when you click, it will not exceed the scope of the container. This is to avoid the problem of excessive sliding and unnecessary blank space. Examples are as follows:

Using react to make a slide carousel display component

There is a lot of white space on the right due to excessive sliding

So we can judge whether the relative moving distance exceeds the width of the content container, that is, beyond the width of the display content

const relativeTranslateX: number = cityContainerWidth - cityWrapTranslateX
const isRightOverflow: boolean = relativeTranslateX - translateDistance >= cityWrapWidth

Let’s take a look at the picture below

Using react to make a slide carousel display component

At the current sliding position, there is only 300px left at the end, but we set the sliding distance of 600px each time. At this time, our relative moving distance is 1200 – (- 500) is 1700, and thenrelativeTranslateX - translateDistanceThat is, 1700 – (- 600) is 2300, which is larger than 2000, which means that the overflow will be more than 300px,

We define a variable at this pointnewTranslateXTo represent the new sliding distance. The default is the last slide distance

let newTranslateX: number = cityWrapTranslateX

If it is about to overflow, we will set it to the last sliding distance plus the relative sliding distance, and then subtract the width of the content container. In this way, we may not understand it. Let’s calculate it

Newtranslatex = 500
relativeTranslateX = 1200
cityWrapWidth = 2000

newTranslateX = 500 + 1200 – 2000 = -300
Does this mean moving 300 pixels to the right! That’s just the end!

newTranslateX += relativeTranslateX - cityWrapWidth

Finally, we can set the latest sliding distance according to various situations. After setting the sliding distance, we can change the style

/*Click the left arrow*/
if (translateDistance > 0) {
  /*Is it at the end of the left*/
  if (isLeftEnd) return

  if (isLeftOverflow) {
    /*Out of range, slide just to the left end of the distance*/
    newTranslateX = 0
  } else {
    /*Within the range, the sliding distance is directly added to the step size*/
    newTranslateX += translateDistance
  }

} else if (translateDistance < 0) {
  /*Is it at the right end*/
  if (isRightEnd) return

  if (isRightOverflow) {
    /*Out of range, slide just to the end of the right*/
    newTranslateX += relativeTranslateX + 10 - cityWrapWidth
  } else {
    /*Within the range, the sliding distance is directly added to the step size*/
    newTranslateX += translateDistance
  }
}

const transformString: string = `translateX(${newTranslateX}px)`
cityWrapDom && (cityWrapDom.style.transform = transformString)
this.setState({
  cityWrapTranslateX: newTranslateX
})
  1. We’ll divide the data into rows
const { cityList, row } = this.props
const cityWrapWidth: number = cityList.length > 12 ? Math.ceil(cityList.length / row) * 220 : 1320
const cityWrapDom: HTMLElement | null = document.getElementById('city__wrap') as HTMLElement
cityWrapDom && (cityWrapDom.style.width = `${cityWrapWidth}px`)

Here is a simple way to judge the number of elements. By default, we display 12 elements, two lines, and a line of 6 elements. If less than 12 elements are displayed separately

Using react to make a slide carousel display component

When it is set to three lines:
Using react to make a slide carousel display component

I feel that there are too many words in the whole article, which is very wordy, but it is also a small summary. I’m still a little excited to write it out. You can take out paper and pen and draw a sketch map on the paper. Soon we can get the relationship, and then slowly push it out!

Recommended Today

ASP.NET Example of core MVC getting the parameters of the request

preface An HTTP request is a standard IO operation. The request is I, which is the input; the responsive o is the output. Any web development framework is actually doing these two things Accept the request and parse to get the parameters Render according to the parameters and output the response content So let’s learn […]